2008年6月20日金曜日

.NET 列挙体に属性を付けるには?

名前属性を作成します。
Imports System.Reflection
 _
Friend Class NameAttribute
Inherits Attribute

Private _name As String

Public Property Name() As String
Get
Return Me._name
End Get
Private Set(ByVal value As String)
Me._name = value
End Set
End Property

Public Sub New(ByVal name As String)
Me.Name = name
End Sub

Public Shared Function GetName(ByVal enumValue As [Enum]) As String
Dim enumType As Type = enumValue.[GetType]()
Dim enumName As String = [Enum].GetName(enumType, enumValue)
If enumName Is Nothing Then
Return Nothing
Else
Return GetName(enumType.GetField(enumName))
End If
End Function

Private Shared Function GetName(ByVal type As MemberInfo) As String
Dim attributes As Attribute()
attributes = TryCast(type.GetCustomAttributes(GetType(NameAttribute), True), Attribute())
If attributes Is Nothing OrElse attributes.Length = 0 Then
Return Nothing
End If
Dim nameAttribute As NameAttribute = TryCast(attributes(0), NameAttribute)
Return nameAttribute.Name
End Function

End Class


別名属性を作成します。
Imports System.Reflection
 _
Friend Class AliasNameAttribute
Inherits Attribute

Private _aliasName As String

Public Property AliasName() As String
Get
Return Me._aliasName
End Get
Private Set(ByVal value As String)
Me._aliasName = value
End Set
End Property

Public Sub New(ByVal aliasName As String)
Me.AliasName = aliasName
End Sub

Public Shared Function GetAliasName(ByVal enumValue As [Enum]) As String
Dim enumType As Type = enumValue.GetType
Dim enumName As String = [Enum].GetName(enumType, enumValue)
If enumName Is Nothing Then
Return Nothing
Else
Return GetAliasName(enumType.GetField(enumName))
End If
End Function

Private Shared Function GetAliasName(ByVal type As MemberInfo) As String
Dim attributes As Attribute()
attributes = TryCast(type.GetCustomAttributes(GetType(AliasNameAttribute), True), Attribute())
If attributes Is Nothing OrElse attributes.Length = 0 Then
Return Nothing
End If
Dim nameAttribute As AliasNameAttribute = TryCast(attributes(0), AliasNameAttribute)
Return nameAttribute.AliasName
End Function

End Class


列挙体に名前と別名の属性を付けます。
Public Enum DayOfWeek As Integer
<NameAttribute("日曜日"), AliasNameAttribute("日")> _
Sun = 0
<NameAttribute("月曜日"), AliasNameAttribute("月")> _
Mon = 1
<NameAttribute("火曜日"), AliasNameAttribute("火")> _
Tue = 2
<NameAttribute("水曜日"), AliasNameAttribute("水")> _
Wed = 3
<NameAttribute("木曜日"), AliasNameAttribute("木")> _
Thu = 4
<NameAttribute("金曜日"), AliasNameAttribute("金")> _
Fri = 5
<NameAttribute("土曜日"), AliasNameAttribute("土")> _
Sat = 6
End Enum


列挙体の属性を取得するには以下のコードを書きます。
Dim dayOfWeek As DayOfWeek = DayOfWeek.Wed 

Dim name As String
name = NameAttribute.GetName(CType(dayOfWeek , [Enum]))

Dim alias As String
alias = AliasNameAttribute.GetAliasName(CType(dayOfWeek , [Enum]))

2008年6月18日水曜日

.NET System.Typeオブジェクトよりバージョン情報を取得するには

Public Sub GetFileVersionInfo(ByVal type As System.Type)
Dim ver As System.Diagnostics.FileVersionInfo
ver = System.Diagnostics.FileVersionInfo.GetVersionInfo(type.Assembly.Location)
Dim manufacturer As String = ver.CompanyName
Dim productName As String = ver.ProductName
End Sub

2008年6月17日火曜日

.NET セットアッププロジェクト インストール完了後にプログラムを実行するには

「チェックボックス」ダイアログを使用して、インストール終了後にプログラムを実行するかを選択し
チェックON時のみプログラムを実行する方法です。

まずユーザーインターフェースエディタで終了ノードに「チェックボックス(A)」ダイアログを追加します。



次にカスタムアクションとして実行するVBScript「CustomAction.vbs」を用意します。
Dim WshShell
Dim path, manufacturer, productName

if Session.Property("CHECKBOXA1") then
manufacturer = Session.Property("Manufacturer")
productName = Session.Property("ProductName")
path = """" & Session.Property("TARGETDIR") & "WindowsApplication1.exe " & """"  & " " & manufacturer & " " & productName 
set WshShell = CreateObject("WScript.Shell")
WshShell.Run path
end if

※パスの指定方法
 コマンドライン引数がない場合
 path = """" & Session.Property("TARGETDIR") & "WindowsApplication1.exe " & """"
 コマンドライン引数がある場合
 path = """" & Session.Property("TARGETDIR") & "WindowsApplication1.exe " & """" & " " & 引数1 & " " & 引数2


作成したカスタムアクション「CustomAction.vbs」ファイルをアプリケーションフォルダに配置します。


セットアッププロジェクトをビルドし、MSIファイルを作成します。

作成したMSIファイルをORCAで開きます。
「File]」テーブルの「FileName」フィールドが「CustomAction.vbs」のデータを探します。
該当データの「File」フィールド値をコピーします。
※「File」フィールド値が「_77760E20AE324214B847ADADACA85FA6」であるとします。


「CustomAction」テーブルに以下の行を追加します。
ActionTypeSourceTarget
AC122_77760E20AE324214B847ADADACA85FA6

ActionフィールドはCustomActionテーブル内で一意になるよう名前をつけます。
TypeフィールドはVBScriptファイルである定数値22を指定します。
その他の定数値はCustom Action Typesを参照してください。
Sourceフィールドは先程の「CustomAction.vbs」のFileフィールド値を指定します。


「ControlEvent」テーブルに以下の行を追加します。
Dialog_Control_EventArgumentConditionOrdering
FinishedFormCloseButtonDoActionAC111



以上でORCAでの編集は終了です。

作成したMSIファイルでインストールを実行し、チェックボックスダイアログでチェックONした時のみプログラムが実行される事を確認してください。

.NET セットアッププロジェクト すべてのユーザをデフォルトにするには?

msiファイルをORCAで編集します。
Propertyテーブルの「FolderForm_AllUsers」のValueを「ME」から「ALL」に変更します。

2008年6月13日金曜日

.NET 文字列を暗号化するには?(DES暗号化)

System.Security.Cryptography.DESCryptoServiceProvider クラスを使用し、DES (Data Encryption Standard) アルゴリズムにより文字列の暗号化、復号化を行います。

''' <summary>
''' 文字列を暗号化します。
''' </summary>
''' <param name="value">暗号化する文字列</param>
''' <param name="key">暗号キー</param>
''' <returns>暗号化後の文字列</returns>
''' <remarks></remarks>
Public Shared Function Encrypt(ByVal value As String, ByVal key As String) As String

'キーをバイト型配にし、8バイトにリサイズします。
Dim bKey As Byte() = System.Text.Encoding.UTF8.GetBytes(key)
Array.Resize(bKey, 8)

'DES暗号化プロバイダオブジェクトを作成します。
Dim des As New System.Security.Cryptography.DESCryptoServiceProvider
des.Key = bKey
des.IV = bKey

'暗号化されたデータを書き出すためのメモリーストリームオブジェクトを作成します。
Using memStream As New System.IO.MemoryStream()

'データ ストリームを暗号変換にリンクするストリームを定義します。 
Using cryptStream As New System.Security.Cryptography.CryptoStream( _
memStream, des.CreateEncryptor, _
System.Security.Cryptography.CryptoStreamMode.Write)

'書き込むためのストリームライターを作成します。
Using sw As New System.IO.StreamWriter(cryptStream)

'暗号化前の文字列を書き込みます。
sw.WriteLine(value)

sw.Close()
cryptStream.Close()
End Using 'sw
End Using 'cryptStream

'メモリーストリームから暗号化後のバイト配列を取得します。
Dim bRet As Byte() = memStream.ToArray()

memStream.Close()

'Base64で文字列に変更し返します。
Return System.Convert.ToBase64String(bRet)

End Using 'memStream

End Function

''' <summary>
''' 文字列を復号化します。
''' </summary>
''' <param name="value">復号化する文字列</param>
''' <param name="key">暗号キー</param>
''' <returns>復号化後の文字列</returns>
''' <remarks></remarks>
Public Shared Function Decrypt(ByVal value As String, ByVal key As String) As String

'キーをバイト型配にし、8バイトにリサイズします。
Dim bKey As Byte() = System.Text.Encoding.UTF8.GetBytes(key)
Array.Resize(bKey, 8)

'DES暗号化プロバイダオブジェクトを作成します。
Dim des As New System.Security.Cryptography.DESCryptoServiceProvider
des.Key = bKey
des.IV = bKey

'Base64で文字列をバイト配列に戻します。
Dim bValue As Byte() = System.Convert.FromBase64String(value)

'暗号化されたデータを読み込むためのメモリーストリームオブジェクトを作成します。
Using memStream As New System.IO.MemoryStream(bValue)

'データ ストリームを暗号変換にリンクするストリームを定義します。 
Using cryptStream As New System.Security.Cryptography.CryptoStream( _
memStream, des.CreateDecryptor, _
System.Security.Cryptography.CryptoStreamMode.Read)

'読み込むためのストリームリーダーオブジェクトを作成します。
Using sr As New System.IO.StreamReader(cryptStream, _
System.Text.Encoding.UTF8)

'メモリーストリームから復号化後のバイト配列を取得します。
Dim vRet As String = sr.ReadLine

'ストリームを閉じます。
sr.Close()
cryptStream.Close()
memStream.Close()

Return vRet

End Using
End Using 'cryptStream

End Using 'memStream
End Function




他にもSystem.Security.Cryptography名前空間には暗号化複号化を行うクラスとして、以下のものがあります。いずれも使い方はほとんど同じです。


  • DESCryptoServiceProvider
  • RC2CryptoServiceProvider
  • RijndaelManaged
  • TripleDESCryptoServiceProvider

.NET Orcaの使用方法

すべてのプログラムよりOrcaを起動します。
「File」→「Open」より編集するmsiを選択します。

編集後は「File」→「Save」で保存し、Orcaを終了してください。
終了せずにインストールを行うと「インストールパッケージを開くことができませんでした。」とエラーメッセージが表示されます。


ダイアログのボタンを無効にするには?


「Control」テーブルより無効にしたいボタンを探し、Atributesフィールドを「1」にします。
有効にしたい場合はAtributesフィールドを「3」にします。



ダイアログに表示されているテキストを変更するには?


「Control」テーブルより変更したいテキストを探し、Textフィールドを変更します。



ダイアログの×ボタンでインストール中止メッセージを表示しないようにするには?


あるダイアログのキャンセルボタンを無効にしても、ダイアログの×ボタンをクリックすると「インストールを中止しますか?」とメッセージが表示されてしまいます。
×ボタンでメッセージを表示せずにダイアログを閉じるには
「ControlEvent」テーブルより
「Dialog_」フィールドが変更したいダイアログで「Control_」フィールドが「CanncelButton」のデータを探し、下記のように変更します。

Dialog_Control_EventArgumentConditionOrdering
変更したいダイアログCanncelButtonEndDialogReturn0

.NET インストーラでアンインストールに失敗した場合、再インストール出来るようにするには?

アンインストール時にカスタム動作を設定したセットアッププロジェクトでインストールを行いました。
が、アンインストール時のカスタム動作で失敗してしまい、アンインストールできません・・・。
アンインストール出来なければ、再インストールもできません。

こんなたときはレジストリを操作することで再インストールが可能になります。

「すべてのユーザ」でインストールした場合はHKEY_CLASSES_ROOT\Installer\Products以下のサブキー
「このユーザのみ」でインストールした場合はHKEY_CURRENT_USER\Software\Microsoft\Installer\Products以下のサブキーを一つ一つ確認しそのサブキー内のProductsNameキーを確認して、該当するものをサブキーごと削除します。


これで再インストールが可能になります。

2008年6月12日木曜日

.NET Image画像の上に配置したLabelの背景を透過させるには?

Image画像の上に配置したLabelのBackColorプロパティをTransparentに設定しても
そのままではLabelの背景は透過されません。
これはLabelの親コントロールがFormになるため、ラベルの背景色がFormの背景色になるためです。
Labelの背景色を透過するためには、Labelの親コントロールをImageコントロールに変更します。

LabelコントロールのBackColorプロパティをTransparentに設定し
FormのコンストラクタでLabelの親コントロールを変更します。
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()

' InitializeComponent() 呼び出しの後で初期化を追加します。
Me.Controls.RemoveByKey(Me.Label1e.Name)
Me.PictureBox1.Controls.Add(Me.Lable1)

End Sub

.NET msi編集ツールOrca

Windows インストーラ ツールの制限により、Windows インストーラ パッケージ (.msi) ファイルを直接編集する必要がある場合があります。Orca エディタでは、マージ モジュール (.msm) ファイル、内部整合性検証 (.cub) ファイル、およびパッチ作成ファイル (.pcp) の編集と作成を行うことができます。


Orca のインストールと実行



Orcaは単体では配布されていません。OrcaはPlatform SDKに含まれています。
まずWindows Installer SDK を次のページからダウンロードしてインストールします。
Windows SDK for Windows Server 2008 and .NET Framework 3.5


インストールしたフォルダにある Orca.msi を実行しインストールします。(デフォルトではC:\Program Files\Microsoft SDK\Bin\Orca.Msi)

すべてのプログラムより[Orca] をクリックし実行します。
[File] メニューの [Open] をクリックし、編集する .msi ファイルを指定します。

2008年6月10日火曜日

.NET セットアッププロジェクト カスタム動作

Installクラスを使用したdllファイルのカスタムアクションを定義します。

前々回自作のアセンブリのインストールで、[参照の追加]ダイアログに表示するには?
で作成したソリューションを流用します。

ソリューションにクラスライブラリ「Action1」を追加し、Installerクラスを継承したInstaller1クラスを作成します。


Installer1.vb
<System.ComponentModel.RunInstaller(True)> _
Public Class Installer1
Inherits System.Configuration.Install.Installer

 

Public Overrides Sub Install( _
ByVal stateSaver As System.Collections.IDictionary)
MyBase.Install(stateSaver)

 

Dim id As String = Me.Context.Parameters("id")
Dim pswd As String = Me.Context.Parameters("pswd")

 

System.Windows.Forms.MessageBox.Show("ID:" & id & "   PSWD:" & pswd)
End Sub

 

End Class


MSDNライブラリ RunInstallerAttribute クラス
MSDNライブラリ Installer クラス


セットアッププロジェクトを選択し、右クリックメニューより「表示」→「カスタム動作」をクリックします。
カスタム動作エディタが表示されます。


「インストール」を選択し、右クリックメニューより「カスタム動作の追加」をクリックします。
「プロジェクトから項目を選択」ダイアログが起動します。


「プロジェクトから項目を選択」ダイアログの検索対象コンボボックスを「アプリケーションフォルダ」に変更し
「出力の追加」ボタンをクリックします。
「プロジェクト出力グループの追加」ダイアログより「Action1のプライマリ出力」を追加します。


カスタム動作エディタの「インストール」ノードに「Action1のプライマリ出力」が追加されますので
「Action1のプライマリ出力」を右クリックし、プロパティウインドウを表示します。



CustomActionDataプロパティを「/id=[ID] /pswd=[PSWD]」と入力します。
[ID]と/の間に半角スペースがありますので注意してください。

Installerクラスを使ったカスタムアクションにデータを渡すときは、
CustomActionDataプロパティに「/パラメータ名=パラメータ値」という形式で指定します。
複数のデータを渡す場合は、スペース文字で区切ります。
また、Windows Installerのプロパティを使うときは、[]で囲みます。
Installerクラス内でデータを取得するには、InstallContext.Parametersプロパティを使います。

つまり
カスタム動作のCustomActionDataプロパティでは
前回セットアッププロジェクト ユーザーインターフェースで追加した
テキストボックス(A)ダイアログのEdit1Propertyプロパティの値とEdit2Properyプロパティの値を、id、pswdというパラメータ名でInstallerクラスに渡すよう設定します。
Installer1クラスでは、Me.Context.Parameters("id")でパラメータ名がidのパラメータ値を取得しています。




動作確認


セットアッププロジェクトをビルドし、インストールを実行します。
ID、パスワードに適当に値を入力します。


インストール終了後に、ID、パスワードが表示されればOKです。


捕捉


VSのセットアップの機能ではインストール終了後にカスタム動作が発生します。
たとえばID、パスワードを入力し「次へ」ボタンで条件分岐を行いたいなどの要件には対応できません。
ORCAなどを使って追加作業を行うか、VSセットアッププロジェクトではなく、WiXやInstalllShieldなどのインストーラ作成ツールを使用する必要があります。

.NET セットアッププロジェクト ユーザーインターフェース

セットアッププロジェクトでテキストボックス付きダイアログを表示できるようにします。

前回自作のアセンブリのインストールで、[参照の追加]ダイアログに表示するには?
で作成したセットアッププロジェクトを流用します。

セットアッププロジェクトを選択し、右クリックメニューより「表示」→「ユーザーインターフェイス」をクリックします。
ユーザーインターフェイスエディタが起動します。

この画面には[インストール]と、[管理インストール]という2つのノードがありますが
インストールは通常のインストール、管理インストールはセットアップに必要なファイルをファイル・サーバ上に転送しておき、そこからセットアップを可能にする機能です。

「インストール」の「開始」ノードを選択し、右クリックメニューの「ダイアログの追加」をクリックします。
「ダイアログの追加」ダイアログが起動しますので「テキストボックス(A)」を追加します。


追加できるダイアログの種類については下記を参照してください。
MSDNライブラリ Installation User Interface Dialog Boxes

「インストール」の「開始」ノードの最後に「テキストボックス(A)」が追加されます。


「テキストボックス(A)」をドラッグして「ようこそ」の次に移動します。


「テキストボックス(A)」は標準で4つのテキストボックスが表示されます。
今回は2つのテキストボックスを表示しようと思います。
「テキストボックス(A)」のプロパティウインドウより下記項目を設定します。
BannerTextプロパティ・・・「ライセンス登録」
BodyTextプロパティ・・・「IDおよびパスワードを入力してください。」
Edit1Labelプロパティ・・・「ID:」
Edit1Propertyプロパティ・・・「ID」
Edit2Labelプロパティ・・・「パスワード:」
Edit2Propertyプロパティ・・・「PSWD」
Edit3Visibleプロパティ・・・「False」
Edit4Visibleプロパティ・・・「False」


この状態でセットアッププロジェクトをビルドし、インストールを実行すると「ようこそ」画面の次に
以下のような画面が表示されます。


次回のセットアッププロジェクト カスタム動作で「ID」「パスワード」の入力値を取得する方法を説明します。

2008年6月6日金曜日

.NET 自作のアセンブリのインストールで、[参照の追加]ダイアログに表示するには?

自作アセンブリのインストーラで、GAC登録を行い、レジストリを追加することで、ツールボックスの「アイテムの選択」ダイアログや「参照の追加」ダイアログに自作アセンブリを表示することができます。

自作アセンブリに厳密名をつける


例えばMyControlsクラスライブラリにMyTextBox、MyComboBoxを作成したとします。
このMyControlsクラスライブラリに厳密名をつけます。

※厳密名をつけることで以下のようなメリットがあります。
メリット1:参照DLLが改竄されていないことを証明する
メリット2:GACに登録することができるようになる
メリット3:コードアクセスセキュリティで厳密名による設定が可能になる
詳しくはアセンブリ署名とコードアクセスセキュリティを参照してください。

VS2005で厳密名をつける手順は簡単です。
MyControlsクラスライブラリのプロパティページの署名タブを開きます。
アセンブリの署名チェックボックスをチェックONにし、コンボボックスより新規作成を選択します。


厳密な名前のキー作成ダイアログが表示されますので、キーファイル名とパスワードを入力します。


ソリューションエクスプローラに、厳密な名前のキー作成ダイアログで指定したキーファイル名.pfxファイルが追加されます。


セットアッププロジェクトを作成します。


ソリューションにセットアッププロジェクトを追加します。
セットアッププロジェクトのプロパティを必要に応じて変更してください。


続いて「アプリケーションフォルダ」を右クリックし「追加」→「プロジェクト出力」を選択ます。


表示された「プロジェクト出力グループの追加」ダイアログより「プライマリ出力」を選択します。




GAC登録


「対象コンピュータ上のファイルシステム」を右クリックし「特別なフォルダの追加」より「グローバルアセンブリキャッシュフォルダ」を選択します。
依存関係のあるdllをGACに登録する場合、グローバルアセンブリキャッシュに依存関係のあるdllを含め、アプリケーションフォルダにはプライマリ出力だけになるようにします。
手順はグローバルアセンブリキャッシュにプライマリ出力を行った後、アプリケーションフォルダにプロジェクト出力を行います。



「グローバルアセンブリキャッシュフォルダ」を右クリックし「追加」→「プロジェクト出力」を選択ます。


表示された「プロジェクト出力グループの追加」ダイアログより「プライマリ出力」を選択します。


レジストリの追加


まず自PCのレジストリを確認します。
「スタート」→「ファイル名を指定して実行」をクリックし、「regedit」と打ち込んで「OK」をクリックしレジストリエディタを起動してください。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFoldersを確認してください。
ここに自作コントロールライブラリMyControlsを作成することにより、GACに登録されていれば、ツールボックスのアイテムの選択ダイアログに表示されるようになります。

確認できたらVSの作業に戻ります。
ツールメニューの「表示」→「エディタ」→「レジストリエディタ」をクリックしレジストリエディタを起動します。


HKEY_LOCAL_MACHINEを右クリックし「新しいキー」で下記構成になるようにキーを作成します。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\[ProductName]


[ProductName]を右クリックし「新規作成」→「文字列の値」を選択します。
Nameプロパティは空値、Valueプロパティは[TARGETDIR]とします。


以上でインストーラの作成は終了です。


動作確認


MyControlsのインストールを行います。

C:\WINDOWS\assemblyフォルダ内にMyControlsがあるかどうか確認します。


レジストリエディタを起動し、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFoldersにMyControlsが作成され、インストールパスが正しいか確認します。


VSを起動しWindowsアプリケーションを作成します。
ツールボックスを右クリックし「アイテムの選択」をクリックします。
「ツールボックス アイテムの選択」ダイアログにMyTextBoxとMyComboBoxが表示されている事を確認します。