#Hidennotare とは
「Hidennotare」は なるべくクラスの再利用性を上げるべく開発されたVBAのクラスライブラリです。
Excel2010以上の32/64bitに対応。Excel2007以前には対応していません。
Hidennotare
https://github.com/RelaxTools/Hidennotare
Hidennotare Wiki
https://github.com/RelaxTools/Hidennotare/wiki
VBAは継承が使用できないため、移譲やインタフェースによるポリモーフィズムをメインとしています。
インターフェースって便利なの?というVBAユーザの参考にもなるかと思います。
##直接アクセスできるクラス
通常クラスはインスタンスを生成(New または CreateObject)しないと使えませんが、特にインスタンスを必要としないような関数のみのクラス(FileIO, RegExp 等)はそのまま使えるようになっています。
'Scripting.FileSystemObject をラップした、FileIO クラスのメソッドは標準モジュールのように使える。
FileIO.FolderCreate TargetPath
'VBScript.RegExp をラップした、RegExp クラスも同様
blnRet = RegExp.Test(strFile,"[A-Z0-9]*")
##直感的に書けるコンストラクタ
インスタンスが必要なクラスで、引数が必要なものはコンストラクタが使えます。
コンストラクタの名前は「CreateObject」です。
インテリセンスで引数の内容が表示されます。
##ポリモーフィズム
Hidennotare は変更に強くするために ポリモーフィズムを多用しています。
たとえば、ICursor インターフェース(以下I/F)に対応しているクラスはすべて同じ動作で処理をすることが可能です。
ICurosr I/F に対応したTextファイルを読む処理を作成した場合、簡単に他の処理(CSVファイルを読む、Sheet を読む、配列を操作、連想配列を操作)に変更することが可能です。
###ICursor インターフェイス
ICursor I/F の使い方
ICursor で変数を宣言し、対応クラスのインスタンスを設定する。
Dim cc As ICursor
'コンストラクタ
Set cc = TextReader.CreateObject("File.txt")
クラスによっては ICursor I/F を返すものもあるので With で使用可能です。この辺はWiki を見るかソースで確認してください。
'コンストラクタ
With TextReader.CreateObject("File.txt")
ICursor I/F に対応したクラス
- CharCursor
- CollectionCursor
- RangeCursor
- SheetCursor
- TableCursor
- TextReader
- CSVReader
- ArrayList
- LinkedList
- MList
- Dictionary
- OrderedDictionary
- SortedDictionary
- MRecord
以下はシートを読むクラスですが、他のCSVファイルを読む機能に変更する場合、コンストラクタを
Dim cc As ICursor
'コンストラクタ
Set cc = SheetCursor.CreateObject(Sheet1, 3, "B")
から
Dim cc As ICursor
'コンストラクタ
Set cc = CSVReader.CreateObject("File.csv")
に書き換えるだけで、それ以降はほぼ修正が無くても行けます。(一部例外あり)
####ICursor インターフェース の有用性
なぜ ICursor I/F を使う必要があるのかとなるのですが、VBA の各クラスの I/F が統一されていないためです。
また、標準の For Each も問題があります。
今の言語は必ずIterator(For Each)があってとても簡単にループが作成できて便利ですが、For Each を使って集計処理をすると以下のようなロジックになってしまいます。
#####For Each を使用した集計処理の場合
Dim col As Collection
Dim v As Variant
Dim strWork As String
Dim lngCnt As Long
Set col = New Collection
col.Add "あ"
col.Add "い"
col.Add "い"
col.Add "う"
col.Add "え"
col.Add "え"
col.Add "お"
col.Add "お"
strWork = ""
lngCnt = 0
For Each v In col
If v <> strWork Then
'初回
If strWork <> "" Then
Debug.Print strWork & lngCnt
End If
strWork = v
lngCnt = 0
End If
lngCnt = lngCnt + 1
Next
'集計結果を表示する前にループを抜けてしまうので同じロジックを書く必要が出てしまう。
If v <> strWork Then
Debug.Print strWork & lngCnt
End If
集計場所が複数になり、キーが増えるほど複雑な処理になっていく。
EOF/MoveNextでのループ(ICursor) を用いた集計処理の場合
Dim col As Collection
Dim v As Variant
Dim strWork As String
Dim lngCnt As Long
Set col = New Collection
col.Add "あ"
col.Add "い"
col.Add "い"
col.Add "う"
col.Add "え"
col.Add "え"
col.Add "お"
col.Add "お"
Dim cc As ICursor
'コンストラクタ
Set cc = CollectionCursor.CreateObject(Col)
Do Until cc.Eof
'初期化
strWork = cc.item
lngCnt = 0
'集計処理
Do Until cc.Eof Or strWork <> cc.item
lngCnt = lngCnt + 1
cc.MoveNext
Loop
'集計結果
Debug.Print strWork & lngCnt
Loop
複数ループ(集計単位)があってもループの中心で次のデータに移動(MoveNext)できるため、
- 初期化処理
- 集計処理
- 結果表示
をわかりやすく記述することができます。
###IList インターフェイス
配列の操作を行うインターフェイスです。変数を IList で宣言し、IList I/F に対応するクラスのインスタンスを設定します。
Dim Row As IList
Set Row = New ArrayList
IList I/F に対応したクラス
- ArrayList
- LinkedList
- MList
###IDictionary インターフェイス
連想配列の操作を行うインターフェイスです。変数を IDictionaryで宣言し、IDictionaryI/F に対応するクラスのインスタンスを設定します。
Dim Col As IDictionary
Set Col = New Dictionary
IDictionaryI/F に対応したクラス
- Dictionary※
- OrderedDictionary
- SortedDictionary
- MRecord
※Scripting.Dictionary とは別の独自クラスです。
その他 インターフェイス
ほかにもインターフェイスかいろいろあります。
- IComparer
- ICompatibleProperty
- INewInstance
- IUsing
- IReader
- IWriter
##その他 Hidennotare の便利な機能
###配列の操作を楽にするArrayList
1次元配列を扱う際に、Redim や Preserve を使用する必要はありません。ToArray() メソッドで変換するだけです。
Dim ar As IList
Set ar = New ArrayList
ar.Add "あ"
ar.Add "い"
ar.Add "う"
ar.ToArray()
###単純な文字列連結からコマンド生成まで自由自在のStringBuilder
Hidennotare で最も使われるクラスです。
文字列を連結
SQL コマンドや CSV ファイルの組み立てが楽になります。
Set SB = New StringBuilder
SB.Append "Column01"
SB.Append "Column02"
SB.Append "Column03"
SB.Append "Column04"
SB.Append "Column05"
SB.ToString(",")
組み立てたコマンドの内容
Column01,Column02,Column03,Column04,Column05
####コマンド文字列を作成
DOS コマンドや、Power シェルのコマンドを組み立てる際に、ToString(" ") を使用すると追加した文字列を空白で連結することが可能です。また、Append の第2引数を True にすると追加した文字列をダブルコーテーションで囲むことができます。
Set SB = New StringBuilder
'コマンド
SB.Append "Compress-Archive"
'圧縮するファイル
SB.Append "-Path"
Set PH = New StringBuilder
For Each v In ary
PH.Append v, True
Next
SB.Append PH.ToString(",")
'出力パス
SB.Append "-DestinationPath"
SB.Append strDest, True
SB.Append "-Force"
'PowerShell を実行する
Process.ExecPowerShell SB.ToString(" ")
組み立てたコマンドの内容
Compress-Archive -Path "C:\Test.csv","C:\Test2.Txt" -DestinationPath "C:\Test.zip" -Force
###Windows API は 64bit、Unicode 対応
内部で Windows API を使用していますが、 32, 64bit 両対応、WCHAR 系の API を使用しているためファイル名やクリップボードにUNICODE文字列を使用していても問題なく動作します。
Private Declare PtrSafe Function FindFirstFileExW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal fInfoLevelId As Long, ByRef lpFindFileData As WIN32_FIND_DATA, ByVal fSearchOp As Long, ByVal lpSearchFilter As LongPtr, ByVal dwAdditionalFlags As Long) As LongPtr
Private Declare PtrSafe Function FindFirstFileW Lib "kernel32" (ByVal lpFileName As LongPtr, lpFindFileData As WIN32_FIND_DATA) As LongPtr
Private Declare PtrSafe Function FindNextFileW Lib "kernel32" (ByVal hFindFile As LongPtr, lpFindFileData As WIN32_FIND_DATA) As LongPtr
Private Declare PtrSafe Function CreateFileW Lib "kernel32" (ByVal lpFileName As LongPtr, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As LongPtr, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As LongPtr) As LongPtr
Private Declare PtrSafe Function WNetGetConnectionW Lib "mpr" (ByVal lpszLocalName As LongPtr, ByVal lpszRemoteName As LongPtr, lSize As Long) As Long
Private Declare PtrSafe Function SearchTreeForFileW Lib "dbghelp" (ByVal RootPath As LongPtr, ByVal InputPathName As LongPtr, ByVal OutputPathBuffer As LongPtr) As Long
Private Declare PtrSafe Function StrCmpLogicalW Lib "Shlwapi" (ByVal psz1 As LongPtr, ByVal psz2 As LongPtr) As Long
Private Declare PtrSafe Function DragQueryFileW Lib "shell32.dll" (ByVal hDrop As LongPtr, ByVal UINT As Long, ByVal lpszFile As LongPtr, ByVal ch As Long) As Long
###JSON 対応
JSON 文字列 -> ArrayList + Dictionary※ または ArrayList + Dictionary※ -> JSON 文字列が可能。
ユーザが作成した データ保持クラスも指定可能です。
※Scripting.Dictionary とは別の独自クラスです。
####シリアライズ化
ArrayList + Dictionary -> JSON 文字列
Dim Row As IList
Dim col As IDictionary
Set Row = New ArrayList
Set col = New Dictionary
col.Add "Field01", 10
col.Add "Field02", 20
col.Add "Field03", 30
Row.Add col
Set col = New Dictionary
col.Add "Field01", 40
col.Add "Field02", 50
col.Add "Field03", 60
Row.Add col
Debug.Print Row.ToString
Row.ToString の結果
[{"Field01":10, "Field02":20, "Field03":30}, {"Field01":40, "Field02":50, "Field03":60}]
####デシリアライズ化
JSON 文字列 -> ArrayList+Dictionary
Dim Row As IList
Dim Col As IDictionary
Dim Key As Variant
Set Row = Parser.ParseJSON("[{""Field01"":10, ""Field02"":20, ""Field03"":30}, {""Field01"":40, ""Field02"":50, ""Field03"":60}]")
For Each Col In Row
For Each Key In Col
Debug.Print "Key=" & Key
Debug.Print "Value=" & Col.Item(Key)
Next
Next
ArrayList/Dictionary の内容
Key=Field01
Value=10
Key=Field02
Value=20
Key=Field03
Value=30
Key=Field01
Value=40
Key=Field02
Value=50
Key=Field03
Value=60
###メッセージのプレースホルダー化と制御文字
メッセージを表示する際に「\n」などの制御文字、埋め込み文字列が可能なプレースホルダ。ステータスバーへのメッセージなど機能があります。
'Information メッセージ
Message.Information "サンプルです。"
'改行する場合
Message.Information "サンプルです。\n改行も簡単に使えます。"
'リプレースホルダを使用する場合
Message.Error "サンプルです。{0}のだけでなく{1}もある", "金", "名誉"
'ステータスバー
Message.StatusBar "サンプルです。{0}のだけでなく{1}もある", "金", "名誉"
以上です。使ってみてください。
Hidennotare
https://github.com/RelaxTools/Hidennotare
Hidennotare Wiki
https://github.com/RelaxTools/Hidennotare/wiki