SQLの窓

2018年01月23日


VS2010(C#) : TKMP.DLLを使った、メール送信テンプレート

OneDrive へ移動

( TKMP.DLL 同梱 )

久しぶりにメールの処理の検証をしてみようと、最新(周辺)の Microsoft の Framework をチェックしてみたのですが、相変わらず標準的なものはなさそうなので、最新の TKMP.DLL で検証してみました。TKMP.DLL は運用はした事がありませんが、メール送信に非同期処理が無い事を除いて、たいていは間に合いそうな気がします。

しかし、いかに簡単に使えるように設計されていても、メール処理はそれなりに煩雑なので、単に『メール送信』に特化してクラスを作成しました。

メールは Hotmail でなくても使えますが、送信用のクラスを作成する為のテストに Hotmail を使って行い、Hotmail の特性に従ってエラー処理もしています。

Hotmail を使用する場合は、ひとつ注意が必要で、エラーになる原因としてメールサービスがスパム対策として確認用の画像を読ませいログインさせようとする場合があるようです。
MailClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TKMP.Writer;
using TKMP.Net;

namespace TKMP_SendMail3
{
    class MailClass
    {
        private MailWriter mw = null;

        public string SmtpServer { get; set; }
        public int Port { get; set; }
        public string User { get; set; }
        public string Pass { get; set; }
        public AuthenticationProtocols Protocol { get; set; }

        private string err_message = "";

        public class MailClassErrorArg
        {
            public string Message { get; set; }
        }

        public delegate void MailClassError(MailClassErrorArg e);

        public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J, MailClassError mce)
        {
            bool bResult = true;

            mw = new MailWriter();

            try
            {
                mw.ToAddressList.Add(To);
            }
            catch (Exception ex)
            {
                bResult = false;
            }
            if (!bResult)
            {
                if (mce != null)
                {
                    MailClassErrorArg e = new MailClassErrorArg() { Message = "宛先が正しくありません" };
                    mce(e);
                }
                return bResult;
            }

            // From が未指定や正しくない文字列の場合
            try
            {
                mw.FromAddress = From;
            }
            catch (Exception ex)
            {
                // ユーザが正しければ、以下のように設定しても『ユーザ名 <メールアドレス>』に変換される
                mw.FromAddress = "______@hotmail.co.jp";
            }

            TextPart tp = new TextPart(Body);
            mw.MainPart = tp;

            if (To_J != null)
            {
                mw.Headers.Add("To", To_J + " <" + To + ">");
            }
            else
            {
                mw.Headers.Add("To", To);
            }
            if (From_J != null)
            {
                mw.Headers.Add("From", From_J + " <" + From + ">");
            }
            else
            {
                // Hotmail では、自動的に 『ユーザ名 <メールアドレス>』に変換される
                mw.Headers.Add("From", From);
            }

            mw.Headers.Add("Subject", Subject);
            mw.Headers.Add("X-Mailer", "TKMP Version 3.1.2");

            var logon = new TKMP.Net.AuthLogin(User, Pass);
            SmtpClient sc = new SmtpClient(SmtpServer, Port, logon);
            sc.AuthenticationProtocol = Protocol;

            try
            {
                if (!sc.Connect())
                {
                    err_message = "接続に失敗しました";
                    bResult = false;
                }
                else
                {
                    sc.SendMail(mw);
                    sc.Close();
                }
            }
            catch (Exception ex)
            {
                err_message = ex.Message;
                bResult = false;
            }
            if (!bResult)
            {
                if (mce != null)
                {
                    MailClassErrorArg e = new MailClassErrorArg() { Message = err_message };
                    // このメソッドの引数である、ErrorHandler デリゲートを呼び出す
                    mce(e);
                }
            }

            return bResult;
        }

        public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J)
        {
            return SendMail(To, From, Subject, Body, To_J, From_J, null);
        }

        public bool SendMail(string To, string From, string Subject, string Body)
        {
            return SendMail(To, From, Subject, Body, null, null, null);
        }

    }

}

エラー処理は、引数にデリゲートを渡す仕様にしているので、Java の 引数へのインターフェイス渡しのような感じで『ラムダ式』を使ってその場で記述する事を想定しています。

これによって、細かいエラー情報が必要な場合は記述し、そうでない場合はオーバーロードされた引数の少ないメソッドを使って成功が失敗かだけをチェックすればいいようになっています。
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Mail;
using System.Net;
using TKMP.Writer;
using TKMP.Net;

namespace TKMP_SendMail3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            MailClass mc = new MailClass()
            {
                SmtpServer = "smtp.live.com",
                Port = 587,
                User = "ユーザ名@hotmail.co.jp",
                Pass = "パスワード",
                Protocol = AuthenticationProtocols.TLS
            };

            var result = mc.SendMail(
                "宛先メールアドレス",
                "ユーザ名@hotmail.co.jp",
                this.subject.Text,
                this.body.Text,
                null,   // 必要な場合、宛先を日本語で
                null,   // 必要な場合、差出人を日本語で
                (MailClass.MailClassErrorArg _e) =>
                {
                    this.error.Text = _e.Message;
                }
            );

            if (result)
            {
                MessageBox.Show("メールを送信しました");
            }

        }

    }
}

Hotmail の仕様に関しては、正式には 『アプリから Outlook.com メールを送受信する』というページにある、『POP3 または SMTP をサポートするアプリ』という中にあります

受信 (POP3) サーバー
サーバー アドレス: pop3.live.com
ポート: 995
SSL 暗号化: はい

送信 (SMTP) サーバー
サーバー アドレス: smtp.live.com
ポート: 25 (25 がブロックされている場合は 587)
認証: はい
TLS または SSL で暗号化された安全な接続: はい
ユーザー名: メール アドレス
パスワード: パスワード
一般的にどこのメールサービスでも、TLS または SSL と書かれていますが、TLS で 587、SSL で 465 です。( このへんはかなり仕様がわかり難いです / Microsoft は、TLS のみ。Google は、両方。他は SSL のみだったり ) メッセージのソースの様子 ( ソースは GMail で確認するのが一番良さそうです )
From: =?iso-2022-jp?B?GyRCOjk9UD9NGyhCQg==?= <______@hotmail.co.jp>
To: =?iso-2022-jp?B?GyRCMDhAaBsoQkI=?= <______@gmail.com>
Date: Tue, 23 Jul 2013 20:10:15 +0900
MIME-Version: 1.0
Subject: =?iso-2022-jp?B?GyRCN29MPhsoQg==?=
X-Mailer: TKMP Version 3.1.2
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit

$BK\J8$N(B
$BFbMF(B

Gmail 用テンプレート

コードは同じですが、smtp サーバーが、『smtp.gmail.com(TLS/587)』になります。ユーザは、Hotmail ではメールアドレスでしたが、Gmail では、ユーザ名部分だけで認証します(メールアドレスでもOKなはずです)。

Nifty 用テンプレート

同様に、コードは同じです。smtp サーバーは、『smtp.nifty.com(SSL/465)』になります。ユーザは、NiftyID を使用したメールアドレスを使いますが、From では通常の別名を使用します。

Yahoo 用テンプレート

同様です。smtp サーバーは、『smtp.mail.yahoo.co.jp(SSL/465)』になります。アカウントは、「@yahoo.co.jpより前の部分」となります。

関連する記事

(C#) / VS2010 または VS2012 : TKMP.DLL(3.1.2 または 3.1.8)を使った、『さくらインターネット』用メール送信テンプレート




posted by lightbox at 2018-01-23 21:30 | VS(C#) | このブログの読者になる | 更新情報をチェックする

(C#) / VS2010 または VS2012 : TKMP.DLL(3.1.2 または 3.1.8)を使った、『さくらインターネット』用メール送信テンプレート



OneDrive よりダウンロード

テンプレートには、3.1.2 が入っていますが、Windwos10(64) + Visual Studio 2012 C# でテスト(2018-01-23)しました。デフォルトでは、32ビットでビルドされますが、『構成マネージャ』で 64ビットに変更しても動作しています。

さくらインターネット

現在スタンダードを運用していますが、月額 515円 容量 100GB です

メールメールアドレスを無制限で作成できます(当然容量内ですが)。
メールボックスの容量を1MBから2048MBまで任意に指定できます。
※ サーバのディスク容量がひっ迫していると、しきい値内であってもメールは届きません。
ウェブメール ※ 一応あります( そんなに力を入れてるとは思えないです ) ❸ メーリングリストは10個 コスト 月額515円 ( 年間一括支払いの場合、5,142円 ) レンタルサーバーとしては、さくらのブログの内容が Seesaa ブログの劣化版である事をのぞけば、結構いたれりつくせりだと思っています。 基本仕様一覧 Ruby は 1.8.x なんで、ちょっと古いと思っています。 データベース使用量は、こんなふうに昔から記述されています。
基本的に制限は設けておりませんが、共用データベースサーバでは使用量の目安がございます。
目安以上の容量を使用された場合、他のお客様への影響がでたり、障害が発生した場合、データの復旧が正常に行えない 可能性がございます。
SSL は 共有SSL が使えます。気軽にログイン部分等、暗号化可能です。 CRONの設定数は 5 です
MailClass mc = new MailClass()
{
    SmtpServer = "初期ドメイン",
    Port = 587,
    User = "ユーザ名@ドメイン",
    Pass = "パスワード",
    Protocol = AuthenticationProtocols.TLS
};

var result = mc.SendMail(
    "宛て先",
    "ユーザ名@ドメイン",
    this.subject.Text,
    this.body.Text,
    null,   // 必要な場合、宛先を日本語で
    null,   // 必要な場合、差出人を日本語で
    (MailClass.MailClassErrorArg _e) =>
    {
        this.error.Text = _e.Message;
    }
);

MailClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TKMP.Writer;
using TKMP.Net;

namespace TKMP_SendMail_Sakura1 {
	class MailClass {
		private MailWriter mw = null;

		public string SmtpServer { get; set; }
		public int Port { get; set; }
		public string User { get; set; }
		public string Pass { get; set; }
		public AuthenticationProtocols Protocol { get; set; }

		private string err_message = "";

		public class MailClassErrorArg {
			public string Message { get; set; }
		}

		public delegate void MailClassError(MailClassErrorArg e);

		public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J, MailClassError mce) {
			bool bResult = true;

			mw = new MailWriter();

			try {
				mw.ToAddressList.Add(To);
			}
			catch (Exception ex) {
				bResult = false;
			}
			if (!bResult) {
				if (mce != null) {
					MailClassErrorArg e = new MailClassErrorArg() { Message = "宛先が正しくありません" };
					mce(e);
				}
				return bResult;
			}

			// From が未指定や正しくない文字列の場合
			try {
				mw.FromAddress = From;
			}
			catch (Exception ex) {
				// ユーザが正しければ、以下のように設定しても『ユーザ名 <メールアドレス>』に変換される
				mw.FromAddress = "______@hotmail.co.jp";
			}

			TextPart tp = new TextPart(Body);
			mw.MainPart = tp;

			if (To_J != null) {
				mw.Headers.Add("To", To_J + " <" + To + ">");
			}
			else {
				mw.Headers.Add("To", To);
			}
			if (From_J != null) {
				mw.Headers.Add("From", From_J + " <" + From + ">");
			}
			else {
				// Hotmail では、自動的に 『ユーザ名 <メールアドレス>』に変換される
				mw.Headers.Add("From", From);
			}

			mw.Headers.Add("Subject", Subject);
			mw.Headers.Add("X-Mailer", "TKMP Version 3.1.2");

			var logon = new TKMP.Net.AuthLogin(User, Pass);
			SmtpClient sc = new SmtpClient(SmtpServer, Port, logon);
			sc.AuthenticationProtocol = Protocol;

			try {
				if (!sc.Connect()) {
					err_message = "接続に失敗しました";
					bResult = false;
				}
				else {
					sc.SendMail(mw);
					sc.Close();
				}
			}
			catch (Exception ex) {
				err_message = ex.Message;
				bResult = false;
			}
			if (!bResult) {
				if (mce != null) {
					MailClassErrorArg e = new MailClassErrorArg() { Message = err_message };
					// このメソッドの引数である、ErrorHandler デリゲートを呼び出す
					mce(e);
				}
			}

			return bResult;
		}

		public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J) {
			return SendMail(To, From, Subject, Body, To_J, From_J, null);
		}

		public bool SendMail(string To, string From, string Subject, string Body) {
			return SendMail(To, From, Subject, Body, null, null, null);
		}

	}

}

関連する記事

VS2010(C#) : TKMP.DLL(3.1.2)を使った、メール送信テンプレート




posted by lightbox at 2018-01-23 21:23 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年12月19日


C# : Excel を データベースとして DataGridView に読み込む

※ Microsoft Office の Excel がインストールされている必要はありません

Microsoft.ACE.OLEDB.12.0 を使用して、OleDbConnection と OleDbCommand でデータベースとして処理します。テーブル名としては、シート名が使われますが、範囲指定して名前を定義しない限りは [シート名$] をテーブル
として使用します。( カギかっこは、Oracle で言うところのダブルクォートです )

Microsoft.ACE.OLEDB.12.0 がインストールされていない場合

Microsoft Access データベース エンジン 2010 再頒布可能コンポーネントをダウンロードしてインストールします。


( 32ビット版と64ビット版があるので選択してダウンロードします / ※ システム要件に 『32 ビット版の Access データベース エンジンは、Windows XP Service Pack 3 でしか使用できません』とあります。Windows7 では既にインストールされていると思われます )

▼ ダウンロードページの『インストール方法』より抜粋
OLEDB を使用するアプリケーション開発者: ConnectionString プロパティのプロバイダー引数を "Microsoft.ACE.OLEDB.12.0" に設定します。 

Microsoft Office Excel データに接続する場合は、Excel ファイル形式に基づいて OLEDB 接続文字列の適切な拡張プロパティを追加します 

ファイル形式 (拡張子)                                             拡張プロパティ
---------------------------------------------------------------------------------------------
Excel 97-2003 ブック (.xls)                                  "Excel 8.0"
Excel 2007-2010 ブック (.xlsx)                             "Excel 12.0 Xml"
Excel 2007-2010 マクロ有効ブック (.xlsm)      "Excel 12.0 Macro"
Excel 2007-2010 XML 以外のバイナリ ブック (.xlsb)      "Excel 12.0"
処理コード
	public partial class FormExcelGridView : Form {

		private string path = null;

		public FormExcelGridView() {
			InitializeComponent();
		}

		private void buttonExcel_Click(object sender, EventArgs e) {

			path = Helper.OpenFileDialog();
			if (path == null) {
				return;
			}

			LoadExcel();

		}

		// *********************
		// Excel の読み込み
		// *********************
		private void LoadExcel() {

			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand()) {

				// SQL文字列格納用
				string myQuery = "select * from [sheet1$]";

				// 接続文字列の作成
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\"", path);
				Debug.WriteLine(myCon.ConnectionString);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
					return;
				}

				// *********************
				// 実行 SQL
				// *********************
				myCommand.CommandText = myQuery;

				// *********************
				// レコードセット取得
				// *********************
				try {
					using (OleDbDataReader myReader = myCommand.ExecuteReader()) {

						DataTable dataTable = new DataTable();
						dataTable.Load(myReader);
						dataGridView.DataSource = dataTable;

						// リーダを使い終わったので閉じる
						myReader.Close();
					}
				}
				catch (Exception ex) {
					myCon.Close();
					MessageBox.Show(this, ex.Message);
					return;
				}

				// 接続解除
				myCon.Close();

			}	// 最外の using の終わり

			// カラム幅の自動調整
			dataGridView.AutoResizeColumns();

		}
	}



Helpre クラス
	class Helper {

		// https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/application-object-excel
		public const int xlMaximized = -4137;
		public const int xlMinimized = -4140;
		public const int xlNormal = -4143;

		public static string OpenFileDialog() {

			OpenFileDialog ofd = new OpenFileDialog();

			ofd.Filter = "Excel(*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "Excel ブックを選択してください";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() != DialogResult.OK) {
				return null;
			}

			return ofd.FileName;
		}
	}


関連する記事

C# : dynamic 型 による Excel へのアクセス



posted by lightbox at 2017-12-19 00:12 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年12月17日


C# : dynamic 型 による Excel へのアクセス

dynamic 型のオブジェクトは静的な型チェックをバイパスします。 なので、そのオブジェクトに対して熟練している必要がありますが、COM を使用する事を想定している場合、プログラマはそのメソッドに対して良く経験しているはすです。

▼ テンプレートのダウンロード


Excel の初期化部分と終了部分
		// *********************
		// 初期処理
		// *********************
		private void Form1_Load(object sender, EventArgs e) {

			excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
			excelApp.Visible = true;

		}

		// *********************
		// 終了処理
		// *********************
		private void Form1_FormClosed(object sender, FormClosedEventArgs e) {

			if (excelApp != null) {
				if (workBook != null) {
					// 保存した事にする
					workBook.Saved = true;
				}
				excelApp.Quit();
			}
			System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);

		}
Excel.Application は、VBScript では CreateObject で使用する ID です。excelApp は、dynamic 型で定義されており、excelApp.Visible = true; は、Excel が表示される事を意味します。



本来は、非表示でなければなりませんが(ユーザが直接操作するとエラーが発生します)、アプリケーション側(C#)が完成せずにテスト段階でエラーを起こしてしまうと、Excel が終了せずにメモリに残ってしまうので(その場合はタスクマネージャより終了させる)、このようにしています。

実装している機能

Excel には気の遠くなるほど、機能がたくさんあります。その中でも基本となる部分を実装しました。
1) セルへの書き込み。

2) Book を開いて、シート名の一覧をコンボボックスに表示

3) 各 シートをアクティブにする

4) Book を閉じる

5) Book を保存して閉じる

6) 最大化・最小化・標準表示
ソースコード
	public partial class Form1 : Form {

		private dynamic excelApp = null;
		private dynamic workBook = null;
		private string path = null;

		public Form1() {
			InitializeComponent();
		}

		// *********************
		// 書き込みテスト
		// *********************
		private void buttonTest_Click(object sender, EventArgs e) {

			if (workBook == null) {
				return;
			}

			// セル用変数
			dynamic cell;
			// 行と列より、セルオブジェクト(アクティブシート)
			cell = workBook.ActiveSheet.Cells(numericRow.Value, numericColumn.Value);
			// セルに値をセット
			cell.Value = textString.Text;

		}

		// *********************
		// アクティブにする
		// *********************
		private void buttonActive_Click(object sender, EventArgs e) {

			if (workBook == null) {
				return;
			}

			string sheetName = listBoxSheet.Text;
			workBook.Sheets(sheetName).Activate();

		}

		// *********************
		// 初期処理
		// *********************
		private void Form1_Load(object sender, EventArgs e) {

			excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
			excelApp.Visible = true;

		}

		// *********************
		// 終了処理
		// *********************
		private void Form1_FormClosed(object sender, FormClosedEventArgs e) {

			if (excelApp != null) {
				if (workBook != null) {
					// 保存した事にする
					workBook.Saved = true;
				}
				excelApp.Quit();
			}
			System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);

		}

		// *********************
		// ブックを開く
		// *********************
		private void 開く_Click(object sender, EventArgs e) {

			if (workBook != null) {
				MessageBox.Show(this, "ブックは一つしか開く事ができません");
				return;
			}

			path = Helper.OpenFileDialog();
			if (path != null) {
				workBook = excelApp.Workbooks.Open(path);
				listBoxSheet.Items.Clear();
				// シートの数によりループ
				for (int i = 1; i <= workBook.Sheets.Count; i++) {
					// シート名をコンボボックスにセット
					listBoxSheet.Items.Add(workBook.Sheets(i).Name);
				}
				// コンボボックスを使用可能にして
				listBoxSheet.Enabled = true;
				// 先頭を選択する
				listBoxSheet.SelectedIndex = 0;
			}

		}

		// *********************
		// 閉じる
		// *********************
		private void 閉じる_Click(object sender, EventArgs e) {

			if (workBook != null) {
				// 保存した事にする
				workBook.Saved = true;
			}
			workBook.Close();
			workBook = null;

			// クリア
			listBoxSheet.Items.Clear();
			// リストボックスを使用不可にして
			listBoxSheet.Enabled = false;
			// 選択しない
			listBoxSheet.SelectedIndex = -1;

		}

		// *********************
		// 保存して閉じる
		// *********************
		private void 保存して閉じる_Click(object sender, EventArgs e) {

			if (workBook != null) {
				workBook.Save();
			}
			workBook.Close();
			workBook = null;

			// クリア
			listBoxSheet.Items.Clear();
			// リストボックスを使用不可にして
			listBoxSheet.Enabled = false;
			// 選択しない
			listBoxSheet.SelectedIndex = -1;

		}

		// *********************
		// 最大化
		// *********************
		private void 最大化_Click(object sender, EventArgs e) {

			excelApp.WindowState = Helper.xlMaximized;

		}

		// *********************
		// 最小化
		// *********************
		private void 最小化_Click(object sender, EventArgs e) {

			excelApp.WindowState = Helper.xlMinimized;

		}

		// *********************
		// 標準
		// *********************
		private void 標準_Click(object sender, EventArgs e) {

			excelApp.WindowState = Helper.xlNormal;

		}


	}



Helpre クラス
	class Helper {

		// https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/application-object-excel
		public const int xlMaximized = -4137;
		public const int xlMinimized = -4140;
		public const int xlNormal = -4143;

		public static string OpenFileDialog() {

			OpenFileDialog ofd = new OpenFileDialog();

			ofd.Filter = "Excel(*.xls;*.xlsx;*.xlsm)|*.xls;*.xlsx;*.xlsm|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "Excel ブックを選択してください";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() != DialogResult.OK) {
				return null;
			}

			return ofd.FileName;
		}
	}


関連する記事

C# : Excel を データベースとして DataGridView に読み込む



タグ:C# EXCEL
posted by lightbox at 2017-12-17 20:29 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年11月26日


C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (4)



C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (3) で、Game、Player という二つのクラスで、左右の矢印キーでプレイヤーの画像が左右に動く処理を標準化しました。

この Player クラスの機能をそのまま使って、背景を表示する Background クラスを追加します。背景画像はこちらからダウンロードできますが、サイズは 1007x1007 という中途半端なサイズになっています。

この画像はパターン画像で、左端が右端に続き、上端が下端に続く画像で、適当に作ったのでこのようなサイズになっています。ただ、1007 の幅なので、ゲーム画面の幅はこれ以内でないとうまく動作しないので注意して下さい。

Background クラス

背景は、プレイヤーの動きと逆に動くようになっています。また、背景は常に画面いっぱいに表示されるので、DrawRectGraph で描画しています。左端と右端を同時に更新する必要があるのですが、パターン画像なので、二つのエリアに分けて描画します。(矢印キーをずっと押し続けると、プレイヤーは画面の端で止まりますが、背景はずっと横スクロールし続けます)

現在横の動きだけなので二つの DrawRectGraph を使用していますが、縦の動きを入れる場合はさらに二つの DrawRectGraph が必要になる予定です。
		// *******************
		// コンストラクタ
		// *******************
		public Background(Game game, string name, int offset) {

			this.game = game;

			// 画像の読み込み
			image = DX.LoadGraph(name);

			// 画像のサイズを取得
			int w, h;
			DX.GetGraphSize(image, out w, out h);
			graph_w = w;
			graph_h = h;

			// 背景の初期位置
			x = 0;
			y = 0;

			move_offset = offset;

		}

		public int image { get; set; }
		public int graph_w { get; set; }
		public int graph_h { get; set; }
		public int x { get; set; }
		public int y { get; set; }
		public int move_offset { get; set; }
		public Game game { get; set; }

		// *******************
		// 描画
		// *******************
		internal void draw() {

			DX.DrawRectGraph(0, 0, this.graph_w - this.x, this.y, this.x, this.graph_h - this.y, this.image, 0, 0);
			DX.DrawRectGraph(this.x, 0, 0, this.y, this.graph_w, this.graph_h - this.y, this.image, 0, 0);

		}

		// *******************
		// 左移動
		// *******************
		internal void left() {

			this.x -= this.move_offset;

			// 背景は一周する
			if (this.x < 0) {
				// 左へ消えた部分は、右から出て来る
				this.x = this.graph_w;
			}

		}

		// *******************
		// 右移動
		// *******************
		internal void right() {

			this.x += 5;

			// 背景は一周する
			if (this.x >= this.graph_w) {
				// 右へ消えた部分は、左から出て来る
				this.x = 0;
			}

	
		}
	}


Background クラスを追加したメイン処理( Program クラス内 ) は以下のようになります

Program 内の処理

処理としては逆向きのメソッドをそれぞれ配置しただけのものになっています
			// メインゲームインスタンス作成
			Game game = new Game(800, 600);

			// 初期化
			game.init();

			// 背景インスタンス作成
			Background background = new Background(game, "field.png", 5);

			// プレイヤーインスタンス作成
			Player player = new Player(game, "player.png", 5);

			game.start(
				// *******************
				// 主処理
				// *******************
				(int counter) => {

					// 右矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {

						player.right();
						// player と 逆向き
						background.left();

					}

					// 左矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {

						player.left();
						// player と 逆向き
						background.right();

					}

				},
				// *******************
				// 描画処理
				// *******************
				() => {

					background.draw();
					player.draw();

				}

			);



posted by lightbox at 2017-11-26 20:17 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (3)



C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (2) では、Player クラスを作成し、Player に依存する情報を Player クラス内にプロパティとして保存しました。

以下では、そのプロパティを使って、Player クラス内でデータを処理する為の right、left、draw メソッドを作成しています。

Player クラス
	class Player {

		// *******************
		// コンストラクタ
		// *******************
		public Player(Game game, string name, int offset) {

			this.game = game;

			// 画像の読み込み
			image = DX.LoadGraph(name);

			// 画像のサイズを取得
			int w, h;
			DX.GetGraphSize(image, out w, out h);
			graph_w = w;
			graph_h = h;

			// プレーヤーの初期位置
			x = game.screen_w / 2 - h / 2;
			y = game.screen_h - 70;

			move_offset = offset;

		}

		public int image { get; set; }
		public int graph_w { get; set; }
		public int graph_h { get; set; }
		public int x { get; set; }
		public int y { get; set; }
		public int move_offset { get; set; }
		public Game game { get; set; }

		// *******************
		// 描画
		// *******************
		internal void draw() {

			DX.DrawGraph(this.x, this.y, this.image, DX.TRUE);

		}

		// *******************
		// 右移動
		// *******************
		internal void right() {

			this.x += this.move_offset;
			if (this.x + this.graph_w > game.screen_w) {
				this.x = game.screen_w - this.graph_w;
			}

		}

		// *******************
		// 左移動
		// *******************
		internal void left() {

			this.x -= this.move_offset;
			if (this.x < 0) {
				this.x = 0;
			}

		}
	}


そして、以下ではこの Player クラスのメソッドを使用して、Program クラス内の記述を簡略化しています。
			// メインゲームインスタンス作成
			Game game = new Game(800, 600);

			// 初期化
			game.init();

			// プレイヤーインスタンス作成
			Player player = new Player(game, "player.png", 5);

			game.start(
				// *******************
				// 主処理
				// *******************
				(int counter) => {

					// 右矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {

						player.right();

					}

					// 左矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {

						player.left();

					}

				},
				// *******************
				// 描画処理
				// *******************
				() => {

					player.draw();

				}

			);

関連する記事

C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (4)




posted by lightbox at 2017-11-26 17:51 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (2)



C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (1) では、メインループと初期化部分を Game クラスとしてクラス化しました。(Game クラスの start メソッド内で、キーアクションの処理部分と描画部分を分けて、start の引数の無名ブロックを呼び出すようにしました。)

今回は、それに引き続いてプレイヤーを左右矢印キーで左右に動くようにしている部分をクラス化し、Player クラスを作成します。

プレイヤーの初期処理は、使用する画像の決定と一回のキー押下でどのくらい移動するかの距離を設定する事にしました。また、初期位置を画面下部中央に設置する為に、スクリーンサイズが必要になるので、Game クラスのインスタンスも同時に引き渡しています。

Player クラス
ここでは情報をプロパティとして定義しています。

1) image : 画像ハンドル
2) graph_w : 画像幅
3) graph_h : 画像高さ
4) x : 描画座標
5) y : 描画座標
6) move_offset : キー押下による移動距離
7) game : Game クラスのインスタンス
	class Player {

		// *******************
		// コンストラクタ
		// *******************
		public Player(Game game, string name, int offset) {

			this.game = game;

			// 画像の読み込み
			image = DX.LoadGraph(name);

			// 画像のサイズを取得
			int w, h;
			DX.GetGraphSize(image, out w, out h);
			graph_w = w;
			graph_h = h;

			// プレーヤーの初期位置
			x = game.screen_w / 2 - h / 2;
			y = game.screen_h - 70;

			// キー押下による移動距離
			move_offset = offset;

		}

		public int image { get; set; }
		public int graph_w { get; set; }
		public int graph_h { get; set; }
		public int x { get; set; }
		public int y { get; set; }
		public int move_offset { get; set; }
		public Game game { get; set; }
	}


次に、この Player クラスを使用して、Program クラスの記述を変更すると以下のようになります。

ただ、この時点ではまだ Player の処理が Program クラス での記述に依存してしまっているので、キーの処理と描画の処理を Player クラスのメソッドとして変更する必要があります
			// メインゲームインスタンス作成
			Game game = new Game(800, 600);

			// 初期化
			game.init();

			// プレイヤーインスタンス作成
			Player player = new Player(game, "player.png", 5);

			game.start(
				// *******************
				// 主処理
				// *******************
				(int counter) => {

					// 右矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {
						player.x += player.move_offset;
						if (player.x + player.graph_w > game.screen_w) {
							player.x = game.screen_w - player.graph_w;
						}
					}

					// 左矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {
						player.x -= player.move_offset;
						if (player.x < 0) {
							player.x = 0;
						}
					}

				},
				// *******************
				// 描画処理
				// *******************
				() => {

					DX.DrawGraph(player.x, player.y, player.image, DX.TRUE);

				}

			);

関連する記事

C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (3)



posted by lightbox at 2017-11-26 17:06 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年11月25日


C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (1)



まずプロジェクトですが、DXライブラリのダウンロードから、C# 用をダウンロードしてそのまま動作する場合はそれでもいいですが、Visual Studio の 2010 では動かないので普通にプロジェクトを Windows アプリケーションで作成します。

次に、bin の下の実行場所に DxLib.dll と DxLib_x64.dll と DxLibDotNet.dll をコピーして、DxLibDotNet.dll を参照すれば使えるようになります。



以下のソースコードに関しては、player.png が必要ですが、シューティングゲーム用ドット絵フリー素材よりダウンロードして作成しました。


(DxLib.dll と同じ場所に保存します)

こちらはクラス化した C# テンプレートです。プロジェクトをテンプレートで作成したら、DxLib.dll と DxLib_x64.dll と DxLibDotNet.dll と player.png をコピーして DxLibDotNet.dll を参照します


クラス化なしのベタコード

このコードで、自機が左矢印キーと右矢印キーで左右に移動します。
using DxLibDLL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DX_001 {

	static class Program {

		[STAThread]
		static void Main() {

			// ウインドウモードで起動( コメントにするとフルスクリーン )
			DX.ChangeWindowMode(DX.TRUE);

			// スクリーンサイズ
			int screen_w = 800, screen_h = 600;
			DX.SetGraphMode(screen_w, screen_h, 32);

			// DXライブラリの初期化
			if (DX.DxLib_Init() < 0) {
				return;
			}

			// 描画先を裏画面に変更
			DX.SetDrawScreen(DX.DX_SCREEN_BACK);

			// 画像の読み込み
			int player = DX.LoadGraph("player.png");

			// 画像のサイズを取得
			int player_graph_w, player_graph_h;
			DX.GetGraphSize(player, out player_graph_w, out player_graph_h);

			// プレーヤーの初期位置
			int x = screen_w / 2 - player_graph_w / 2, y = screen_h - 70;

			int payer_move_offset = 5;

			// メインループ
			while (DX.ProcessMessage() != -1) {

				// ESC で終了
				if (DX.CheckHitKey(DX.KEY_INPUT_ESCAPE) == 1) {
					break;
				}

				// 右矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {
					x += payer_move_offset;
					if (x + player_graph_w > screen_w) {
						x = screen_w - player_graph_w;
					}
				}
				// 左矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {
					x -= payer_move_offset;
					if (x < 0) {
						x = 0;
					}
				}
				// 上矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_UP) == 1) {
				}
				// 下矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_DOWN) == 1) {
				}
				// スペースキー
				if (DX.CheckHitKey(DX.KEY_INPUT_SPACE) == 1) {
				}

				// 画面をクリア
				DX.ClearDrawScreen();

				// プレイヤーを描画
				DX.DrawGraph(x, y, player, DX.TRUE);

				// 裏画面の内容を表画面に反映する
				DX.ScreenFlip();
			}

			// DXライブラリの後始末
			DX.DxLib_End();
		}
	}

}


このままいろいろ機能を実装して行くと、とてもメンテしにくいコードになるので、まずゲームの本体である初期化とメインループをクラス化し、メインループ用の start メソッドの引数の無名処理を呼び出すようにしました。

Game クラスを作成して使用
	static class Program {

		[STAThread]
		static void Main() {

			// メインゲームインスタンス作成
			Game game = new Game(800, 600);

			// 初期化
			game.init();

			// 画像の読み込み
			int player = DX.LoadGraph("player.png");

			// 画像のサイズを取得
			int player_graph_w, player_graph_h;
			DX.GetGraphSize(player, out player_graph_w, out player_graph_h);

			// プレーヤーの初期位置
			int x = game.screen_w / 2 - player_graph_w / 2, y = game.screen_h - 70;

			int payer_move_offset = 5;

			game.start(
				// *******************
				// 主処理
				// *******************
				(int counter) => {

					// 右矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {
						x += payer_move_offset;
						if (x + player_graph_w > game.screen_w) {
							x = game.screen_w - player_graph_w;
						}
					}

					// 左矢印キー
					if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {
						x -= payer_move_offset;
						if (x < 0) {
							x = 0;
						}
					}

				},
				// *******************
				// 描画処理
				// *******************
				() => {

					DX.DrawGraph(x, y, player, DX.TRUE);

				}

			);



		}
	}


Game クラス

public void start(main_action call, draw_action draw) として定義されているので、内側から call と draw を呼び出して呼び出し元のコードを実行させます。

こうする事によって、ループ処理の中をキー処理と描画処理を分けて解りやすく記述できるようになります。

呼び出し元は、ラムダ式で単純なブロックを作成して記述が可能です。
class Game {

	// 外部呼出し用
	public delegate void main_action(int counter);
	public delegate void draw_action();

	// メインループカウント
	private int loopCount = 0;

	// スクリーンサイズ
	public int screen_w;
	public int screen_h;

	// *******************
	// コンストラクタ
	// *******************
	public Game(int w, int h) {
		screen_w = w;
		screen_h = h;
	}

	// *******************
	// 初期化
	// *******************
	public void init() {

		// ウインドウモードで起動( コメントにするとフルスクリーン )
		DX.ChangeWindowMode(DX.TRUE);

		// スクリーンサイズ
		DX.SetGraphMode(screen_w, screen_h, 32);

		// DXライブラリの初期化
		if (DX.DxLib_Init() < 0) {
			return;
		}

		// 描画先を裏画面に変更
		DX.SetDrawScreen(DX.DX_SCREEN_BACK);

	}

	// *******************
	// メインループ開始
	// *******************
	public void start(main_action call, draw_action draw) {


		// メインループ
		while (DX.ProcessMessage() != -1) {

			// ESC で終了
			if (DX.CheckHitKey(DX.KEY_INPUT_ESCAPE) == 1) {
				break;
			}

			// 外部を呼び出し
			call(loopCount);
			loopCount++;
			if (loopCount > 100000) {
				loopCount = 0;
			}

			// 画面をクリア
			DX.ClearDrawScreen();

			// 外部を呼び出し(描画処理用)
			draw();

			// 裏画面の内容を表画面に反映する
			DX.ScreenFlip();

		}

		// DXライブラリの後始末
		DX.DxLib_End();

	}

}


関連する記事

C# でDXライブラリを使って簡単なシューティングをクラス化して標準化 / メインループとプレイヤー (2)


posted by lightbox at 2017-11-25 22:07 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年11月06日


Visual Studio 2012 : 表示メニューから、ツールボックス等のコマンドが消えてしまった場合の個別登録

原因は解りませんが、きっとどこかに Visual Studio のデフォルト状態のメニューの定義があると思うのですが、見つける事ができていません。(コマンドの追加に『リセット』とかあるので)

良く使うウインドウ表示コマンドを、自分で登録してみます。

▼ メニューをカスタマイズするコマンドの場所

(これが消えていたら、どうしていいかは現在未調査)

▼ 表示する位置の決定


この Visual Studio は正常なので、『出力』も『ツールボックス』もあります。無い場合はこのあたりを選択してコマンドの追加ボタンをクリックします。

▼ コマンドの選択


ウインドウの表示コマンドは、『表示』の中にあると思います。画像のスクロールバー位置を参考に探して下さい。



posted by lightbox at 2017-11-06 10:47 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年10月29日


C# : Microsoft Access のテーブルとビューの一覧と任意の SQL を実行するテンプレート

Visual Studio 2012 で作成しています。
(C:\Users\ユーザ\Documents\Visual Studio 2012\Templates\ProjectTemplates に保存します)





Access を参照すると、テーブル一覧とビュー一覧が表示され、テーブルまたはビューをダブルクリックすると、行を表示するテンプレートです。

システムテーブル表示をチェックすると、Access のシステムテーブルを表示しますが、ユーザと権限の管理でシステムテーブルへのアクセス権限が設定できるのは、.mdb ファイルのみになります。

サンプルデータ / 販売管理C.accdb と 販売管理C.mdb



以下はシステムテーブルを表示したものですが、表示できないデータは x となっています。



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SqlUnitAccess2 {
	public partial class Form1 : Form {

		// ファイル選択用
		private OpenFileDialog ofd = new OpenFileDialog();

		// *********************
		// コンストラクタ
		// *********************
		public Form1() {
			InitializeComponent();
		}

		// *********************
		// 画面初期処理
		// *********************
		private void Form1_Load(object sender, EventArgs e) {

			// *********************
			// タイトル表示変更
			// *********************
			this.Text = "SqlUnitAccess";

		}

		// *********************
		// 参照ボタン
		// *********************
		private void ref_Click(object sender, EventArgs e) {

			// *********************
			// ファイル選択
			// *********************
			ofd.Filter = "Access(*.mdb;*.accdb)|*.mdb;*.accdb|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "Access データベースを選択してください";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() != DialogResult.OK) {
				return;
			}

			// *********************
			// タイトル表示変更
			// *********************
			this.Text = ofd.FileName;

			// *********************
			// テーブル一覧表示
			// *********************
			loadTables(ofd.FileName);

		}

		// *********************
		// 実行ボタン
		// *********************
		private void action_Click(object sender, EventArgs e) {

			string sql = textBox1.Text;
			// *********************
			// select 実行
			// *********************
			executeReader(ofd.FileName, sql);

		}

		// *********************
		// テーブル一覧ダブルクリック
		// *********************
		private void tabel_Select(object sender, DataGridViewCellEventArgs e) {

			// *********************
			// table 名取得
			// *********************
			string value = dataGridTables.Rows[e.RowIndex].Cells[0].Value.ToString();
			textBox1.Text = "select * from " + value;

			// *********************
			// select 実行
			// *********************
			executeReader(ofd.FileName, textBox1.Text);

		}

		// *********************
		// テーブル一覧表示
		// *********************
		private void loadTables(string path) {

			dataGridSelect.DataSource = null;

			using (OleDbConnection myCon = new OleDbConnection()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", path);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
					return;
				}

				DataTable dataTable = null;
				if (checkBoxSysTable.Checked) {
					// *********************
					// 全て
					// *********************
					dataTable = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, null }
					);
				}
				else {
					// *********************
					// TABLE と VIEW をマージ
					// *********************
					dataTable = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, "TABLE" }
					);
					DataTable dataTable2 = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, "VIEW" }
					);
					dataTable.Merge(dataTable2);
				}

				// 表示しない列は削除
				dataTable.Columns.Remove("TABLE_CATALOG");
				dataTable.Columns.Remove("TABLE_SCHEMA");
				//dataTable.Columns.Remove("TABLE_TYPE");
				dataTable.Columns.Remove("TABLE_GUID");
				dataTable.Columns.Remove("DESCRIPTION");
				dataTable.Columns.Remove("TABLE_PROPID");
				dataTable.Columns.Remove("DATE_CREATED");
				dataTable.Columns.Remove("DATE_MODIFIED");

				// 表示
				dataGridTables.DataSource = dataTable;

				// 接続解除
				myCon.Close();
			}

			// カラム幅の自動調整
			dataGridSelect.AutoResizeColumns();
		}

		// *********************
		// select 実行
		// *********************
		private void executeReader(string path, string sql) {

			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", path);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
					return;
				}

				// *********************
				// 実行 SQL
				// *********************
				myCommand.CommandText = sql;

				// *********************
				// レコードセット取得
				// *********************
				try {
					using (OleDbDataReader myReader = myCommand.ExecuteReader()) {

						DataTable dataTable = new DataTable();
						dataTable.Load(myReader);
						dataGridSelect.DataSource = dataTable;

						// リーダを使い終わったので閉じる
						myReader.Close();
					}
				}
				catch (Exception ex) {
					myCon.Close();
					MessageBox.Show(this, ex.Message);
					return;
				}

				// 接続解除
				myCon.Close();

			}

			// カラム幅の自動調整
			dataGridSelect.AutoResizeColumns();
		}

		// *********************
		// システム表の表示エラー対応
		// *********************
		private void dataGridSelect_DataError(object sender, DataGridViewDataErrorEventArgs e) {

		}


	}
}




posted by lightbox at 2017-10-29 02:24 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年10月03日


C# でDXライブラリを使って簡単なシューティング部分を作るサンプル

とても久しぶりに DXライブラリ を覗いてみたら、とても現役で利用されているようなのでVisualC# 用パッケージをダウンロードして、シューティング部分を実装してみました。

C++ で作成したのは、2006年なので、もう11年経ってますが、更新履歴を見たらずっと途切れなくあったので、凄いなぁと感心するばかりです。

ダウンロードしたサンプルは VisualStudio2015 とありますが、手元の VisualStudio2013 で動作しています。まあ、DLL 読んで使ってるだけだから、動くはずですけれど。

以下は Program.cs の中そのままです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using DxLibDLL;

namespace VisualStudio2015
{
	static class Program
	{
		const int SHOT_STRAIGHT = 0;
		const int SHOT_LEFT = 1;
		/// <summary>
		/// アプリケーションのメイン エントリ ポイントです。
		/// </summary>
		[STAThread]
		static void Main()
		{
			// ウインドウモードで起動( コメントにするとフルスクリーン )
			DX.ChangeWindowMode(DX.TRUE);

			// DXライブラリの初期化
			if (DX.DxLib_Init() < 0)
			{
				return;
			}

			// 描画先を裏画面に変更
			DX.SetDrawScreen(DX.DX_SCREEN_BACK);

			// 画像の読み込み
			int GraphHandle = DX.LoadGraph("play.bmp");
			// 画像の縦横サイズ
			int gsize = 64;

			// 弾の存在フラグ等の属性を持つクラス
			Shot[] shot = { new Shot(), new Shot() };

			// 初期位置
			int x = 300, y = 400;

			// メインループ
			while (DX.ProcessMessage() != -1)
			{
				// ESC で終了
				if (DX.CheckHitKey(DX.KEY_INPUT_ESCAPE) == 1) {
					break;
				}

				// 右矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_RIGHT) == 1) {
					x += 3;
					if (x + gsize > 640) {
						x = 640 - gsize;
					}
				}
				// 左矢印キー
				if (DX.CheckHitKey(DX.KEY_INPUT_LEFT) == 1) {
					x -= 3;
					if (x < 0) {
						x = 0;
					}
				}

				// スペースキー
				if (shot[SHOT_STRAIGHT].exist == 0) {
					if (DX.CheckHitKey(DX.KEY_INPUT_SPACE) == 1) {
						shot[SHOT_STRAIGHT].exist = 1;
						shot[SHOT_STRAIGHT].x = x;
						shot[SHOT_STRAIGHT].y = y;
					}
				}
				// Zキー
				if (shot[SHOT_LEFT].exist == 0) {
					if (DX.CheckHitKey(DX.KEY_INPUT_Z) == 1) {
						shot[SHOT_LEFT].exist = 1;
						shot[SHOT_LEFT].x = x;
						shot[SHOT_LEFT].y = y;
					}
				}

				// 画面をクリア
				DX.ClearDrawScreen();

				// プレイヤーを描画
				DX.DrawGraph(x, y, GraphHandle, DX.TRUE);

				// 弾1を描画
				if (shot[SHOT_STRAIGHT].exist == 1) {
					shot[SHOT_STRAIGHT].y -= 8;
					if (shot[SHOT_STRAIGHT].y < 0 - gsize) {
						shot[SHOT_STRAIGHT].exist = 0;
					}
				}
				if (shot[SHOT_STRAIGHT].exist == 1) {
					DX.DrawGraph(shot[SHOT_STRAIGHT].x, shot[SHOT_STRAIGHT].y, GraphHandle, DX.TRUE);
				}

				// 弾2を描画
				if (shot[SHOT_LEFT].exist == 1) {
					shot[SHOT_LEFT].y -= 8;
					if (shot[SHOT_LEFT].y < 0 - gsize) {
						shot[SHOT_LEFT].exist = 0;
						// 方向を左へリセット
						shot[SHOT_LEFT].direction = 0;
					}
					else {
						if (shot[SHOT_LEFT].direction == 0) {
							shot[SHOT_LEFT].x -= 8;
						}
						if (shot[SHOT_LEFT].direction == 1) {
							shot[SHOT_LEFT].x += 8;
						}
						if (shot[SHOT_LEFT].x < 0) {
							shot[SHOT_LEFT].direction = 1;
						}
						if (shot[SHOT_LEFT].x > 640 - gsize) {
							shot[SHOT_LEFT].direction = 0;
						}
					}
				}
				if (shot[SHOT_LEFT].exist == 1) {
					DX.DrawGraph(shot[SHOT_LEFT].x, shot[SHOT_LEFT].y, GraphHandle, DX.TRUE);
				}


				// 裏画面の内容を表画面に反映する
				DX.ScreenFlip();
			}

			// DXライブラリの後始末
			DX.DxLib_End();
		}

		private class Shot {

			public Shot() {
				this.exist = 0;
				this.direction = 0;
			}

			public int exist { get; set; }
			public int x { get; set; }
			public int y { get; set; }
			public int direction { get; set; }
		}
	}
}

play.bmp は適当に背景透過で 64x64 のサイズのものを使って下さい。元々のサンプルの実行フォルダに Src1.bmp という画像があります。それと同じ場所に置いて下さい。
※ 自分が使っているのは、11年前に作ったドット絵

※ 弾の時に、回転させたりしてたので、いびつな輪郭です。

仕様としては、以下のようなものです。

1) ESC で終了
2) 左右矢印キーで、プレイヤーキャラクタ(画像)を移動できる
3) SPACE キーで直線の弾
4) Zキーで、左斜めへの弾(跳ね返ると右へ)
5) プレイヤーキャラクタと弾の画像は同じ

※ 弾は二種類で、それぞれキーに依存。
※ 弾が画面内に一つある場合、二つ目は打てない
※ 違うキーの弾は同一画面に存在できる

なので、キーを増やして弾の種類を増やすのは比較的容易なはずです。ただ、ソースコードが長くなるので、それぞれはメソッドやクラスに変えるべきですけれど。

画像は弾毎に変えればいいし、左から右へ移動するだけの敵を作成して、あたり判定して爆破するのもそう難しくは無いと思います。

仕上げとしては、爆発アニメーションを組み込んで、背景を組み込んで左右のキーで背景を反対方向に移動させるとそれなりに見えると思います。



posted by lightbox at 2017-10-03 15:32 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年09月28日


Microsoft Access に対してSQLを入力してその結果を DataGridView に表示する最も簡単なコード



最初に .accdb か .mdb を選択しておいて、自由な SQL をタイプしてその結果をそのまま Excel のごとく DataGridView に表示します。

DataGridView に表示するデータは全て文字列扱いとして、ArrayList に随時行を追加して、Rows.Add に、ToArray() したものをセットします。

一応表示のみを想定しているので、以下の設定を最初にします


表示件数は多すぎると時間がかかりすきるので、固定で 100 件にしています。
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinApp1 {
	public partial class Form1 : Form {

		private OpenFileDialog ofd = new OpenFileDialog();

		public Form1() {
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e) {

			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", ofd.FileName);
				Debug.WriteLine(myCon.ConnectionString);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					MessageBox.Show(this,ex.Message);
					return;
				}

				// *********************
				// 実行 SQL
				// *********************
				myCommand.CommandText = textBox1.Text;

				// *********************
				// レコードセット取得
				// *********************
				try {
					using (OleDbDataReader myReader = myCommand.ExecuteReader()) {

						// *********************
						// 列数
						// *********************
						int nCols = myReader.FieldCount;

						// DataGridView 初期化
						dataGridView1.Columns.Clear();
						dataGridView1.ColumnCount = nCols;		// カラム数

						Type fldType;
						ArrayList rowData = new ArrayList();

						// データ取得と表示
						int maxCount = 0;
						while (myReader.Read()) {

							// 行データをセットする ArrayList をクリア
							rowData.Clear();

							maxCount++;
							if ( maxCount > 100 ) {
								break;
							}

							// 初回のみ、タイトル文字列を設定
							if (maxCount == 1) {
								for (int idx = 0; idx < nCols; idx++) {
									dataGridView1.Columns[idx].Name = myReader.GetName(idx);
								}
							}

							// 行データの作成( ArrayList で作成して ToArray() したものを Rows.Add )
							for (int idx = 0; idx <nCols; idx++) {

								// NULL でない場合
								if (!myReader.IsDBNull(idx)) {
									// 列のデータ型を取得
									fldType = myReader.GetFieldType(idx);

									// 文字列
									if (fldType.Name == "String") {
										rowData.Add(myReader.GetValue(idx).ToString());
									}
									else if (fldType.Name == "Int32") {
										rowData.Add(myReader.GetInt32(idx).ToString());
									}
									else if (fldType.Name == "DateTime") {
										rowData.Add(myReader.GetDateTime(idx).ToString());
									}
									else {
										rowData.Add(myReader.GetValue(idx).ToString());
									}

								}
								else {
									rowData.Add("");
								}
							}

							// 行追加 ( BuildArray() は配列を作成する為のメソッド )
							dataGridView1.Rows.Add(rowData.ToArray());

						}

						// リーダを使い終わったので閉じる
						myReader.Close();
					}
				}
				catch (Exception ex) {
					myCon.Close();
					MessageBox.Show(this, ex.Message);
					return;
				}

				myCon.Close();

				// カラム幅の自動調整
				dataGridView1.AutoResizeColumns();

			}		// 最外の using の終わり

		}

		private void button2_Click(object sender, EventArgs e) {

			// *********************
			// ファイル選択
			// *********************
			ofd.Filter = "Excel(*.mdb;*.accdb)|*.mdb;*.accdb|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "Access データベースを選択してください";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() != DialogResult.OK) {
				return;
			}


		}		// click イベントの終わり

	}		// class の終わり
}


※ テーブル・ビュー一覧は以下のようにして簡単に表示できます
			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", ofd.FileName);
				Debug.WriteLine(myCon.ConnectionString);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					MessageBox.Show(this,ex.Message);
					return;
				}

				DataTable dataTable = myCon.GetOleDbSchemaTable(
					OleDbSchemaGuid.Tables,
					new object[] { null, null, null, null }
				);
				// TABLE のみの場合は以下( 上記は 全て )
				//	new object[] { null, null, null, "TABLE" }

				dataGridView1.DataSource = dataTable;

				myCon.Close();

				// カラム幅の自動調整
				dataGridView1.AutoResizeColumns();

			}		// 最外の using の終わり

さらに SQL の実行結果は、データの途中加工が全くできなくなりますが、DataTable を使って以下のようにさらに短く記述する事ができます
				// *********************
				// 実行 SQL
				// *********************
				myCommand.CommandText = textBox1.Text;

				try
				{
					using (OleDbDataReader myReader = myCommand.ExecuteReader())
					{
						DataTable dataTable = new DataTable();

						dataTable.Load(myReader);

						dataGridView1.DataSource = dataTable;
		
						myReader.Close();
					}

				}
				catch (Exception ex)
				{
					myCon.Close();
					MessageBox.Show(this, ex.Message);
					return;
				}

DataSource プロパティを使用した場合、新たに直接データをセットしていきたい場合は、いったん DataSource プロパティに null を設定しておく必要があります。


Microsoft.ACE.OLEDB.12.0 がインストールされていない場合

Microsoft Access データベース エンジン 2010 再頒布可能コンポーネントをダウンロードしてインストールします。


( 32ビット版と64ビット版があるので選択してダウンロードします )



posted by lightbox at 2017-09-28 19:53 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年09月19日


System.Data.OleDb で select into 構文を使って簡単に Microsoft Access のデータを他の データベースにエクスポートする

結論から言うと、System.Data.OleDb と ADO で Microsoft Access に接続すると同等の処理ができます。元々、ADO で可能だった処理を System.Data.OleDb で可能かどうか確認し、System.Data.Odbc でとこまで同じ事が可能か試してみました。

結果的に、System.Data.Odbc では ODBC の動的接続では処理不可で、DSN を作成すると可能でした。

テスト用コード
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OdbcAccessTest {
	public partial class Form1 : Form {

		// *************************************
		// System.Data.Odbc
		// *************************************
		private OdbcConnection myCon;
		private OdbcCommand myCommand;
		private OdbcDataReader myReader;

		// *************************************
		// System.Data.OleDb
		// *************************************
		private OleDbConnection myConAccess;

		// *************************************
		// ADO
		// *************************************
		private dynamic objAdoCon;

		public Form1() {
			InitializeComponent();
		}

		// *************************************
		// System.Data.Odbc で Access データの読み込み
		// *************************************
		private void button1_Click(object sender, EventArgs e) {

			string myQuery = "SELECT * from 社員マスタ";

			using (myCommand = new OdbcCommand()) {
				// 実行する為に必要な情報をセット
				myCommand.CommandText = myQuery;
				myCommand.Connection = myCon;

				using (myReader = myCommand.ExecuteReader()) {

					// 読み出し

					while (myReader.Read()) {
						// 文字列
						Console.Write(GetValue(myReader, "社員コード") + " : ");
						Console.Write(GetValue(myReader, "氏名") + " : ");
						Console.Write(GetValue(myReader, "フリガナ") + " : ");
						// 整数
						Console.Write(GetValue(myReader, "給与") + " : ");
						Console.Write(GetValue(myReader, "手当") + " : ");
						// 日付
						Console.Write(GetValue(myReader, "作成日") + " : ");
						Console.Write(GetValue(myReader, "更新日") + " : ");

						Console.WriteLine();

					}

					myReader.Close();
				}

			}

		}

		// *************************************
		// テスト用簡易列データ取得
		// *************************************
		private string GetValue(OdbcDataReader myReader, string p) {

			string ret = "";
			int fld = 0;

			// 指定された列名より、テーブル内での定義順序番号を取得
			fld = myReader.GetOrdinal(p);
			// 定義順序番号より、NULL かどうかをチェック
			if (myReader.IsDBNull(fld)) {
				ret = "";
			}
			else {
				// NULL でなければ内容をオブジェクトとして取りだして文字列化する
				ret = myReader.GetValue(fld).ToString();
			}

			// 列の値を返す
			return ret;
		}

		// *************************************
		// 接続処理
		// *************************************
		private void Form1_Load(object sender, EventArgs e) {

			// *************************************
			// System.Data.Odbc
			// *************************************
			OdbcConnectionStringBuilder builder = new OdbcConnectionStringBuilder();

			builder.Driver = "Microsoft Access Driver (*.mdb, *.accdb)";
			builder.Add("dbq", @"C:\tmp\販売管理C.accdb");
			// 内容を確認
			Console.WriteLine(builder.ConnectionString);

			// 新しい OdbcConnection オブジェクトを作成
			myCon = new OdbcConnection();

			// 接続文字列を設定
			myCon.ConnectionString = builder.ConnectionString;

			// 接続を開く
			try {
				myCon.Open();
			}
			catch (OdbcException ex) {
				MessageBox.Show(this, "接続エラーです:" + ex.Message);
			}

			// *************************************
			// System.Data.OleDb
			// *************************************
			myConAccess = new OleDbConnection();
			myConAccess.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", @"C:\tmp\販売管理C.accdb");
			// 接続を開く
			try {
				myConAccess.Open();
			}
			catch (Exception ex) {
				MessageBox.Show(this, "接続エラーです:" + ex.Message);
			}
	
			// *************************************
			// ADO
			// *************************************
			objAdoCon = Activator.CreateInstance(Type.GetTypeFromProgID("ADODB.Connection"));

			string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\tmp\001\販売管理C.accdb;";
			try {
				objAdoCon.Open(connectionString);
			}
			catch (Exception ex) {
				MessageBox.Show(this, ex.Message);
			}
		}

		// *************************************
		// 接続解除
		// *************************************
		private void Form1_FormClosed(object sender, FormClosedEventArgs e) {

			myCon.Close();
			myConAccess.Close();
			objAdoCon.Close();

		}

		// *************************************
		// System.Data.OleDb
		// *************************************
		private void button2_Click(object sender, EventArgs e) {

			string myQuery;

			myQuery = @"select * into [Excel 8.0;DATABASE=c:\tmp\販売管理C.xls].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [Excel 12.0 xml;DATABASE=c:\tmp\販売管理C.xlsx].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.accdb].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.mdb].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS64;Database=lightbox;UID=sa;PWD=password].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS32;Database=lightbox;UID=sa;PWD=password].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=MYSQL32;Database=lightbox;UID=root;PWD=password].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [ODBC;Driver={SQL Server Native Client 11.0};server=layla;database=lightbox;uid=sa;pwd=password].商品マスタ_OleDb from 商品マスタ";
			//myQuery = @"select * into [ODBC;Driver={MySQL ODBC 5.3 Unicode Driver};server=layla;database=lightbox;uid=root;pwd=password].商品マスタ_OleDb from 商品マスタ";

			using (OleDbCommand myCommand = new OleDbCommand()) {

				// *********************
				// 接続
				// *********************
				try {
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myConAccess;
					myCommand.CommandText = myQuery;
					myCommand.ExecuteNonQuery();

				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
				}
			}

		}

		// *************************************
		// System.Data.Odbc
		// *************************************
		private void button3_Click(object sender, EventArgs e) {

			string myQuery;

			myQuery = @"select * into [Excel 8.0;DATABASE=c:\tmp\販売管理C.xls].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [Excel 12.0 xml;DATABASE=c:\tmp\販売管理C.xlsx].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.accdb].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.mdb].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS64;Database=lightbox;UID=sa;PWD=password].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS32;Database=lightbox;UID=sa;PWD=password].商品マスタ_Odbc from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=MYSQL32;Database=lightbox;UID=root;PWD=password].商品マスタ_Odbc from 商品マスタ";

			using (myCommand = new OdbcCommand()) {

				try {
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					myCommand.CommandText = myQuery;
					myCommand.ExecuteNonQuery();
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
				}
			}

		}

		// *************************************
		// ADO を使う場合
		// *************************************
		private void button4_Click(object sender, EventArgs e) {

			string myQuery;

			myQuery = @"select * into [Excel 8.0;DATABASE=c:\tmp\販売管理C.xls].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [Excel 12.0 xml;DATABASE=c:\tmp\販売管理C.xlsx].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.accdb].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [;DATABASE=C:\tmp\データベース1.mdb].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS64;Database=lightbox;UID=sa;PWD=password].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=SQS32;Database=lightbox;UID=sa;PWD=password].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [ODBC;DSN=MYSQL32;Database=lightbox;UID=root;PWD=password].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [ODBC;Driver={SQL Server Native Client 11.0};server=layla;database=lightbox;uid=sa;pwd=password].商品マスタ_ADO from 商品マスタ";
			//myQuery = @"select * into [ODBC;Driver={MySQL ODBC 5.3 Unicode Driver};server=layla;database=lightbox;uid=root;pwd=password].商品マスタ_ADO from 商品マスタ";

			try {
				objAdoCon.Execute(myQuery);
			}
			catch (Exception ex) {
				MessageBox.Show(this, ex.Message);
			}

		}

	}
}

ここでは、into 側の表で使用していますが、from 側の表でも使用できるはずです。エクスポートは高速で実行されますが、キーの定義はエクスポートされないので、後から定義する必要があります。

SQL 一覧
@"select * into [Excel 8.0;DATABASE=c:\tmp\販売管理C.xls].商品マスタ_ADO from 商品マスタ";
@"select * into [Excel 12.0 xml;DATABASE=c:\tmp\販売管理C.xlsx].商品マスタ_ADO from 商品マスタ";
@"select * into [;DATABASE=C:\tmp\データベース1.accdb].商品マスタ_ADO from 商品マスタ";
@"select * into [;DATABASE=C:\tmp\データベース1.mdb].商品マスタ_ADO from 商品マスタ";
@"select * into [ODBC;DSN=SQS64;Database=lightbox;UID=sa;PWD=password].商品マスタ_ADO from 商品マスタ";
@"select * into [ODBC;DSN=SQS32;Database=lightbox;UID=sa;PWD=password].商品マスタ_ADO from 商品マスタ";
@"select * into [ODBC;DSN=MYSQL32;Database=lightbox;UID=root;PWD=password].商品マスタ_ADO from 商品マスタ";
@"select * into [ODBC;Driver={SQL Server Native Client 11.0};server=layla;database=lightbox;uid=sa;pwd=password].商品マスタ_ADO from 商品マスタ";
@"select * into [ODBC;Driver={MySQL ODBC 5.3 Unicode Driver};server=layla;database=lightbox;uid=root;pwd=password].商品マスタ_ADO from 商品マスタ";


外部参照部分一覧
[Excel 8.0;DATABASE=c:\tmp\販売管理C.xls].テーブル名
[Excel 12.0 xml;DATABASE=c:\tmp\販売管理C.xlsx].テーブル名
[;DATABASE=C:\tmp\データベース1.accdb].テーブル名
[;DATABASE=C:\tmp\データベース1.mdb].テーブル名
[ODBC;DSN=SQS64;Database=lightbox;UID=sa;PWD=password].テーブル名
[ODBC;DSN=SQS32;Database=lightbox;UID=sa;PWD=password].テーブル名
[ODBC;DSN=MYSQL32;Database=lightbox;UID=root;PWD=password].テーブル名
[ODBC;Driver={SQL Server Native Client 11.0};server=layla;database=lightbox;uid=sa;pwd=password].テーブル名
[ODBC;Driver={MySQL ODBC 5.3 Unicode Driver};server=layla;database=lightbox;uid=root;pwd=password].テーブル名

Excel と Microsoft Access は特殊ですが、ODBC は同じ書式なので他の DB にも使用可能なはずです。接続パラメータは、実際 DSN を作成してから、レジストリを見れば必要なものが全て書かれています。

▼ エクスポートでは使えませんが、以下は Excel を ODBC で定義した場合の例です


PHP で ODBC 接続するとなると、上記データを使って以下のようになります
$ms_excel = "./data/syain.xls";
$ms_excel = realpath($ms_excel);
$excel_dir = dirname($ms_excel);
$connect_string = "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};dbq={$ms_excel};DefaultDir={$excel_dir};FIL=Excel 8.0;DriverID=790";$user="";$pass="";




posted by lightbox at 2017-09-19 00:48 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年08月17日


C# : System.Data.OleDb で Microsoft Access のデータを読み取る

出力ウインドウに結果を表示する為に、Debug.WriteLine を使用していますが、他のメッセージが邪魔なので、デバッグ =>オプション の 『出力』で、【全てのデバッグ出力】以外を オフにしています。



元々は、VB.net でしたが、Telerik Code Converter で変換して少し手を加えました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Diagnostics;

namespace MsAccess1 {
	class Program {
		static void Main(string[] args) {

			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand())
			{
				// SQL文字列格納用
				string myQuery = null;
				string myPath = @"C:\tmp\販売管理C.accdb";
//				string myPath = @"C:\tmp\販売管理C.mdb";	// 古い MsAccess

				// 接続文字列の作成
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", myPath);
				// 出力ウインドウに表示
				// デバッグ>オプション の 『出力』で、【全てのデバッグ出力】以外を オフにする
				Debug.WriteLine(myCon.ConnectionString);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					Debug.WriteLine(ex.Message);
					return;
				}

				myQuery = "select * from 社員マスタ";
				myCommand.CommandText = myQuery;

				// *********************
				// レコードセット取得
				// *********************
				try {
					using (OleDbDataReader myReader = myCommand.ExecuteReader())
					{
						// *********************
						// 列数
						// *********************
						int nCols = myReader.FieldCount;
						Type fldType;

						// カラムループ用
						int idx = 0;
						while (myReader.Read()) {

							for (idx = 0; idx <= nCols - 1; idx++) {
								if (idx != 0) {
									Debug.Write(",");
								}

								// NULL でない場合
								if (!myReader.IsDBNull(idx)) {
									// 列のデータ型を取得
									fldType = myReader.GetFieldType(idx);

									// 文字列
									if (fldType.Name == "String") {
										Debug.Write(myReader.GetValue(idx) + "");
										continue;
									}
									if (fldType.Name == "Int32") {
										Debug.Write(myReader.GetInt32(idx).ToString() + "");
										continue;
									}
									if (fldType.Name == "DateTime") {
										Debug.Write(myReader.GetDateTime(idx).ToString() + "");
										continue;
									}

									Debug.Write(myReader.GetValue(idx).ToString() + "");

								}
								else {
									Debug.Write("");
								}
							}
							// 1行の最後
							Debug.WriteLine("");

						}

						// リーダを使い終わったので閉じる
						myReader.Close();
					}
				}
				catch (Exception ex) {
					myCon.Close();
					Debug.WriteLine(ex.Message);
					return;
				}

				myCon.Close();

			}	// 最外の using の終わり

		}	// Main の終わり
	}	// class の終わり
}	// namespace の終わり




posted by lightbox at 2017-08-17 23:15 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年08月06日


C#(VS2010) : dynamic 型を使用して CreateObject と同等に Scripting.FileSystemObject を使用する

ボタンを一つフォームに貼って、固定パスの SHIFT_JIS テキストファイルを読み込んでいます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WinFormsApp1 {
	public partial class Form1 : Form {

		private dynamic objFile;

		public Form1() {
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e) {

			string buffer;
			try {
				dynamic inFile = objFile.OpenTextFile(@"c:\tmp\help.txt", 1);
				while (!inFile.AtEndOfStream) {
					buffer = inFile.ReadLine();
					Console.Out.WriteLine(buffer);
				}
				inFile.close();
			}
			catch (Exception ex) {
				MessageBox.Show("ファイルが存在しません");
			}

		}

		private void Form1_Load(object sender, EventArgs e) {

			objFile = Activator.CreateInstance(Type.GetTypeFromProgID("Scripting.FileSystemObject"));

		}

		private void Form1_FormClosed(object sender, FormClosedEventArgs e) {

			System.Runtime.InteropServices.Marshal.ReleaseComObject(objFile);

		}
	}
}


参考ページ

C#でCreateObjectと同じことをするには?(dobon.net) のコメント部分

dynamic 型の使用(docs.microsoft.com)



タグ:VS C#
posted by lightbox at 2017-08-06 22:04 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり