┏第18号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜メニュー ■.NET Tips ・公開鍵暗号による暗号化 ■.NET質問箱 ・フォームのイメージを印刷するには? ・GotFocusとLostFocusイベントはどこにいったか? 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜メニュー ─────────────────────────────── ■注意事項 ─────────────────────────────── 一行の文字数に制限があるため、長いURLには途中に改行が入っている ことがあります。実際には改行は入りませんのでご注意ください。 ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── ●公開鍵暗号による暗号化 前回は「秘密鍵暗号方式による暗号化」について説明しましたが、今 回は公開鍵暗号(非対称暗号化方式、公開キー暗号方式)により暗号化、 復号化する方法を紹介します。 公開鍵暗号とは、公開鍵と秘密鍵(個人鍵)の2つの鍵を使って暗号化、 復号化する方法です。公開鍵方式に関して「アスキーデジタル用語辞 典」では次のように説明されています。 「暗号化専用の鍵(公開鍵)と解読専用の鍵(個人鍵)を使って、暗 号化と解読を行なう形式。受信側で事前に公開鍵と個人鍵のペアを用 意し、暗号文の送信側に公開鍵のほうを配布する。送信側は平文を公 開鍵で暗号文に変換できるが、解読はできない。受信側は、個人鍵で 平文に復元可能。公開鍵だけでは解読できないという利点がある。」 ・アスキーデジタル用語辞典 http://yougo.ascii24.com/ .NETでは公開キー暗号化アルゴリズムを実装するクラスとして、 DSACryptoServiceProvider(DSA)とRSACryptoServiceProvider(RSA) の2つが用意されていますが、ここではRSACryptoServiceProviderを使 った例のみを示します。なおDSA、RSAとは何かということ関しては次 のURLが参考になります。 ・通信用語の基礎知識 - DSA http://www.wdic.org/?word=DSA ・通信用語の基礎知識 - RSA http://www.wdic.org/?word=RSA 次に示すサンプルは、公開鍵暗号により文字列を暗号化、復号化する ため3つの静的メソッドからなります。まずCreateKeysメソッドで公開 鍵と秘密鍵のペアを作成し、その公開鍵を使ってEncryptメソッドによ り暗号化します。復号化は秘密鍵を指定してDecryptメソッドにより行 います。 暗号化にはRSACryptoServiceProvider.Encryptメソッドを使用します が、この時渡す暗号化されるデータにはサイズの制限があります。 OAEPパディング、Direct Encryption、ともにサポートなしのそれぞれ のケースで暗号化されるデータの最大長の計算法が異なり、このこと はヘルプ(「RSACryptoServiceProvider.Encrypt メソッド」)で説明 されています。 ・RSACryptoServiceProvider.Encrypt メソッド http://www.microsoft.com/japan/msdn/library/ja/cpref/html /frlrfsystemsecuritycryptographyrsacryptoserviceproviderclassencrypttopic. asp 例えばDirect Encryption(高度暗号化パックがインストールされてい る Microsoft Windows 2000 以降)の場合、 RSACryptoServiceProvider.KeySize プロパティから取得できるキーサ イズが1024ビットだとすると、暗号化されるデータの最大長は、 1024/8-11=117バイト となります。 下のコードでは暗号化されるデータの最大長のチェックは全く行って いませんので、ご注意ください。 なお下の例の「RSACryptoServiceProviderオブジェクトの作成」の部 分についてですが、詳しくは「マイクロソフト サポート技術情報 - 322371」をご覧ください。 ・マイクロソフト サポート技術情報 - 322371 http://support.microsoft.com/default.aspx?scid=kb;en-us;Q322371 //[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・ /// /// 公開鍵と秘密鍵を作成して返す /// /// 作成された公開鍵(XML形式) /// 作成された秘密鍵(XML形式) public static void CreateKeys(out string publicKey, out string privateKey) { //RSACryptoServiceProviderオブジェクトの作成 //(Web Service,ASP Page,COM+の時は次のように //UseMachineKeyStoreを指定する) System.Security.Cryptography.CspParameters CSPParam = new System.Security.Cryptography.CspParameters(); CSPParam.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore; System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam); //公開鍵をXML形式で取得 publicKey = rsa.ToXmlString(false); //秘密鍵をXML形式で取得 privateKey = rsa.ToXmlString(true); } /// /// 公開鍵を使って文字列を暗号化する /// /// 暗号化する文字列 /// 暗号化に使用する公開鍵(XML形式) /// 暗号化された文字列 public static string Encrypt(string str, string publicKey) { //RSACryptoServiceProviderオブジェクトの作成 System.Security.Cryptography.CspParameters CSPParam = new System.Security.Cryptography.CspParameters(); CSPParam.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore; System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam); //公開鍵を指定 rsa.FromXmlString(publicKey); //暗号化する文字列をバイト配列に byte[] data = System.Text.Encoding.UTF8.GetBytes(str); //暗号化する //(XP以降の場合のみ2項目にTrueを指定し、OAEPパディングを使用できる) byte[] encryptedData = rsa.Encrypt(data, false); //Base64で結果を文字列に変換 return System.Convert.ToBase64String(encryptedData); } /// /// 秘密鍵を使って文字列を復号化する /// /// Encryptメソッドにより暗号化された文字列 /// 復号化に必要な秘密鍵(XML形式) /// 復号化された文字列 public static string Decrypt(string str, string privateKey) { //RSACryptoServiceProviderオブジェクトの作成 System.Security.Cryptography.CspParameters CSPParam = new System.Security.Cryptography.CspParameters(); CSPParam.Flags = System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore; System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam); //秘密鍵を指定 rsa.FromXmlString(privateKey); //復号化する文字列をバイト配列に byte[] data = System.Convert.FromBase64String(str); //復号化する byte[] decryptedData = rsa.Decrypt(data, false); //結果を文字列に変換 return System.Text.Encoding.UTF8.GetString(decryptedData); } //・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ 'C#のコードを'C# to VB.NET Translator'で変換し、修正したコードです 'http://www.aspalliance.com/aldotnet/examples/translate.aspx ' '/ '/ 公開鍵と秘密鍵を作成して返す '/ '/ 作成された公開鍵(XML形式) '/ 作成された秘密鍵(XML形式) Public Shared Sub CreateKeys(ByRef publicKey As String, _ ByRef privateKey As String) 'RSACryptoServiceProviderオブジェクトの作成 '(Web Service,ASP Page,COM+の時は次のように 'UseMachineKeyStoreを指定する) Dim CSPParam As New System.Security.Cryptography.CspParameters CSPParam.Flags = _ System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore Dim rsa As New _ System.Security.Cryptography.RSACryptoServiceProvider(CSPParam) '公開鍵をXML形式で取得 publicKey = rsa.ToXmlString(False) '秘密鍵をXML形式で取得 privateKey = rsa.ToXmlString(True) End Sub '/ '/ 公開鍵を使って文字列を暗号化する '/ '/ 暗号化する文字列 '/ 暗号化に使用する公開鍵(XML形式) '/ 暗号化された文字列 Public Shared Function Encrypt(ByVal str As String, _ ByVal publicKey As String) As String 'RSACryptoServiceProviderオブジェクトの作成 Dim CSPParam As New System.Security.Cryptography.CspParameters CSPParam.Flags = _ System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore Dim rsa As New _ System.Security.Cryptography.RSACryptoServiceProvider(CSPParam) '公開鍵を指定 rsa.FromXmlString(publicKey) '暗号化する文字列をバイト配列に Dim data As Byte() = System.Text.Encoding.UTF8.GetBytes(str) '暗号化する '(XP以降の場合のみ2項目にTrueを指定し、OAEPパディングを使用できる) Dim encryptedData As Byte() = rsa.Encrypt(data, False) 'Base64で結果を文字列に変換 Return System.Convert.ToBase64String(encryptedData) End Function '/ '/ 秘密鍵を使って文字列を復号化する '/ '/ Encryptメソッドにより暗号化された文字列 '/ 復号化に必要な秘密鍵(XML形式) '/ 復号化された文字列 Public Shared Function Decrypt(ByVal str As String, _ ByVal privateKey As String) As String 'RSACryptoServiceProviderオブジェクトの作成 Dim CSPParam As New System.Security.Cryptography.CspParameters CSPParam.Flags = _ System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore Dim rsa As New _ System.Security.Cryptography.RSACryptoServiceProvider(CSPParam) '秘密鍵を指定 rsa.FromXmlString(privateKey) '復号化する文字列をバイト配列に Dim data As Byte() = System.Convert.FromBase64String(str) '復号化する Dim decryptedData As Byte() = rsa.Decrypt(data, False) '結果を文字列に変換 Return System.Text.Encoding.UTF8.GetString(decryptedData) End Function '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ・公開鍵暗号による暗号化 http://dobon.net/vb/dotnet/string/rsaencryption.html ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── ●フォームのイメージを印刷するには? 質問: Visual Basic 6.0ではPrintFormというメソッドがあり、これによりフ ォームのイメージを印刷することが出来ましたが、同じようなことを. NETで行うにはどのようにすればよいのでしょうか? 答え: VB6のPrintFormメソッドに代わるものは.NETにはありません。ヘルプ によると、 「Visual Basic 6.0 では、フォームのイメージをプリンタに送るとき、 フォームの PrintForm メソッドが使用されていました。PrintForm メ ソッドは Visual Basic .NET ではサポートされていません。 PrintForm メソッドの結果は、画面の解像度およびプリンタの解像度 に依存するところが大きく、印刷の方法としては推奨されていません でした。PrintForm メソッドの機能を複製する必要がある場合は、サー ドパーティ製のグラフィックス ツールに用意されているスクリーン キャプチャ機能を自動化してフォームのイメージをキャプチャおよび 印刷できます。」 とあります。 ・Visual Basic .NET における印刷の変更点 http://www.microsoft.com/japan/msdn/library/ja/Vbcon/html/vbconprintingchangesinvisualbasic70.asp それではサードパーティ製のスクリーンキャプチャ機能を使うしかな いかというとそうではなく、Win32 APIでスクリーンキャプチャを行う 方法があり、しかもそれは現在ではヘルプに載っています。 ただし、VB6のPrintFormメソッドがフォームの一部が画面に表示され ていない場合でもフォーム全体が印刷されるのに対して、この方法で は表示されていない部分は印刷されません。 ・Code: Printing a Windows Form (Visual Basic) http://msdn.microsoft.com/library/en-us/dv_vbCode/html/vbtskCodeExamplePrintingForm.asp ・Code: Displaying Print Preview for a Windows Form (Visual Basic) http://msdn.microsoft.com/library/en-us/dv_vbCode/html/vbtskCodeExamplePrintPreviewingForm.asp ・コード : Windows フォームを印刷する (Visual Basic) ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1041/dv_vbcode/html/vbtskcodeexampleprintingform.htm ・コード : Windows フォームの印刷プレビューを表示する (Visual Basic) ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1041/dv_vbcode/html/vbtskcodeexampleprintpreviewingform.htm 以下にこのサンプルコードを書き直した例を示します。使い方として は、自分自身のフォームを印刷する時、C#では PrintForm(this); VB.NETでは PrintForm(Me) のようにしてください。 //[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・ /// /// フォームのイメージを印刷する /// /// イメージを印刷するフォーム public void PrintForm(Form frm) { //フォームのイメージを取得する CaptureScreen(frm); //フォームのイメージを印刷する System.Drawing.Printing.PrintDocument PrintDocument1 = new System.Drawing.Printing.PrintDocument(); PrintDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler( PrintDocument1_PrintPage); PrintDocument1.Print(); } [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); //フォームのイメージを保存する変数 private Bitmap memoryImage; //フォームのイメージを取得する private void CaptureScreen(Form frm) { Graphics mygraphics = frm.CreateGraphics(); Size s = frm.Size; memoryImage = new Bitmap(s.Width, s.Height, mygraphics); Graphics memoryGraphics = Graphics.FromImage(memoryImage); IntPtr dc1 = mygraphics.GetHdc(); IntPtr dc2 = memoryGraphics.GetHdc(); BitBlt(dc2, 0, 0, frm.ClientRectangle.Width, frm.ClientRectangle.Height, dc1, 0, 0, 13369376); mygraphics.ReleaseHdc(dc1); memoryGraphics.ReleaseHdc(dc2); } //PrintDocument1のPrintPageイベントハンドラ private void PrintDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { e.Graphics.DrawImage(memoryImage, 0, 0); } //・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ '/ '/ フォームのイメージを印刷する '/ '/ イメージを印刷するフォーム Public Sub PrintForm(ByVal frm As Form) 'フォームのイメージを取得する CaptureScreen(frm) 'フォームのイメージを印刷する Dim PrintDocument1 As New System.Drawing.Printing.PrintDocument AddHandler PrintDocument1.PrintPage, _ AddressOf PrintDocument1_PrintPage PrintDocument1.Print() End Sub _ Private Shared Function BitBlt(ByVal hdcDest As IntPtr, _ ByVal nXDest As Integer, ByVal nYDest As Integer, _ ByVal nWidth As Integer, ByVal nHeight As Integer, _ ByVal hdcSrc As IntPtr, _ ByVal nXSrc As Integer, ByVal nYSrc As Integer, _ ByVal dwRop As Integer) As Boolean End Function 'フォームのイメージを保存する変数 Private memoryImage As Bitmap 'フォームのイメージを取得する Private Sub CaptureScreen(ByVal frm As Form) Dim mygraphics As Graphics = frm.CreateGraphics() Dim s As Size = frm.Size memoryImage = New Bitmap(s.Width, s.Height, mygraphics) Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage) Dim dc1 As IntPtr = mygraphics.GetHdc() Dim dc2 As IntPtr = memoryGraphics.GetHdc() BitBlt(dc2, 0, 0, _ frm.ClientRectangle.Width, frm.ClientRectangle.Height, _ dc1, 0, 0, 13369376) mygraphics.ReleaseHdc(dc1) memoryGraphics.ReleaseHdc(dc2) End Sub 'PrintDocument1のPrintPageイベントハンドラ Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _ ByVal e As System.Drawing.Printing.PrintPageEventArgs) e.Graphics.DrawImage(memoryImage, 0, 0) End Sub '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ─────────────────────────────── ●GotFocusとLostFocusイベントはどこにいったか? 質問: VB6ではコントロールがフォーカスを受け取った時にGotFocusイベント が、フォーカスを失った時にLostFocusイベントが発生しましたが、 .NETではこれらのイベントが見つかりません。.NETではどのようにすれ ばよいのでしょうか? 答え: .NETでもVB6と同様にGotFocusイベント及びLostFocusイベントは存在 しています。しかしVisual Studio .NETでは、VB.NETの場合はコード エディタ上の「メソッド名ボックス」に、C#の場合はプロパティウィ ンドウの「イベント」にGotFocusとLostFocusが表示されません。 GotFocusイベントとLostFocusイベントについて、ヘルプには次のよう に書いてあります。 「GotFocus イベントおよび LostFocus イベントは、WM_KILLFOCUS Windows メッセージおよび WM_SETFOCUS Windows メッセージに結び付 けられた、低水準のフォーカス イベントです。一般的に、 GotFocus イベントおよび LostFocus イベントは、 UICues を更新するときにだ け使用されます。 Activated イベントおよび Deactivate イベントを 使用する Form クラス以外のすべてのコントロールに対して、 Enter イベントおよび Leave イベントを使用する必要があります。」 このことから推測すると、GotFocus及びLostFocusイベントの代わりに、 Enter及びLeaveイベントを使うべきという意味でこれらが表示されな いのかもしれません。 ・GotFocus イベント http://www.microsoft.com/japan/msdn/library/ja/cpref/html/frlrfsystemwindowsformscontrolclassgotfocustopic.asp ・LostFocus イベント http://www.microsoft.com/japan/msdn/library/ja/cpref/html/frlrfsystemwindowsformscontrolclasslostfocustopic.asp また、ヘルプの「Visual Basic .NET における TextBox コントロール の変更点」では、VB6のGotFocus及びLostFocusイベントに代わるもの は、.NETではEnter及びLeaveイベントとなっています。 ・Visual Basic .NET における TextBox コントロールの変更点 http://www.microsoft.com/japan/msdn/library/ja/Vbcon/html/vxconChangesToTextBoxControlInVisualBasicNET.asp 以下にLostFocusイベントを使ったコードを一応書いておきます。 //[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・ private void Form1_Load(object sender, System.EventArgs e) { //TextBox1のLostFocusイベントハンドラを追加する TextBox1.LostFocus += new EventHandler(TextBox1_LostFocus); } //LostFocusイベントハンドラ private void TextBox1_LostFocus(object sender, EventArgs e) { Console.WriteLine("LostFocusイベントが発生しました。"); } //・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'TextBox1のLostFocusイベントハンドラを追加する AddHandler TextBox1.LostFocus, AddressOf TextBox1_LostFocus End Sub 'LostFocusイベントハンドラ Private Sub TextBox1_LostFocus(ByVal sender As Object, _ ByVal e As EventArgs) Console.WriteLine("LostFocusイベントが発生しました。") End Sub '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ・どぼん!のVB道掲示板 - focusイベントについて http://www.sky-j.com/viewlist.php?arg_forum_id=38&arg_thread_id=825&arg_message_id=825 =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  http://dobon.net  dobon@bigfoot.com ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/vb/bbs.html ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 DOBON! All rights reserved. ===============================