#author("2018-05-26T13:20:05+09:00","default:mat2umoto","mat2umoto") #contents *VB6系全般 [#d02df15b] **基本的な言語仕様 [#j93a7891] |仕様|デフォルト|オプション指定|備考|h |文字列の比較|バイナリ比較&br;(大文字小文字を区別)|Option Compare [Binaly|Text|Database]&br;※VBSでは使用不可|DatabaseはAccessVBAのみ| |配列の添数|0~|Option Base [0|1]&br;※VBSでは使用不可|「0~」の場合、Dim a(2)という配列はa(0)~a(2)までの3要素になることに注意| |変数の宣言|不要|Option Explicit|オプション指定すると、変数の宣言を強制できる| **オブジェクトのバインド [#a9a35c0a] -アーリーバインド(事前バインド)~ COMコンポーネントをプログラムの実行前に参照設定しておく手法。''VBScriptでは使用できない。''~ オブジェクト変数の宣言時に型を指定する。 #code(vb){{ ' FileSystemObject の例 Dim objFSO As New FileSystemObject Set objFSO = Nothing }} または、 #code(vb){{ ' FileSystemObject の例 Dim objFSO As FileSystemObject Set objFSO = New FileSystemObject Set objFSO = Nothing }} 長所:プログラムの実行速度が早い。~ 短所:COMコンポーネントの仕様変更により正常に動作しなくなる可能性がある。 -レイトバインド(実行時バインド)~ COMコンポーネントをプログラムの実行時に取得する手法。~ オブジェクト変数はObject型で宣言し、CreateObject関数を使用する。 #code(vb){{ ' FileSystemObject の例 Dim objFSO As Object Set objFSO = CreateObject("Scripting.FileSystemObject") Set objFSO = Nothing }} 長所:COMコンポーネントの仕様変更に柔軟に対応できる。~ 短所:プログラムの実行速度が遅い。 **疑似continue [#n3c25434] -ループ終端の直前にラベルを置いてGoToする。 -Forループに対しては、Doループをネスト~ #code(vb){{ For k = 1 To 10 Do : Exit Do ' Continue : Loop Until 1 Next }} -Doループに対しては、Forループをネスト~ #code(vb){{ Do While True For Ctn = 1 To 1 : Exit For ' Continue : Next Loop }} **関数ポインタ [#y4d9c704] AddressOf演算子を用いることで、プロシージャのポインタを取得できる。Sub と Function のどちらにも有効。 **外部DLLの読み込み [#sf1027d9] Declare構文を使う。 -Win32APIを使うとき(例:Sleep関数) #code(vb){{ Private Declare Sub Sleep Lib "KERNEL32.dll" (ByVal dwMilliseconds As Long) }} **プロパティのByRef引数への引き渡し [#r96e8774] VB6では、ByRef引数へプロパティを直接引き渡しても、プロパティの値は変更されない。 #code(vb){{ : SomeObject.SomeProperty = "abc" ' プロパティをByRef引数に渡す Call Test(SomeObject.SomeProperty) ' SomeObject.SomeProperty は "abc" のまま : Function Test(ByRef wk As String) ' wk には "abc" が渡されている ' wk の値を変更 wk = "xyz" End Function }} **DOSコマンドの実行 [#s77fd28d] WScript.ShellオブジェクトのRunメソッドを用いる。~ ただし、ひとつのDOS窓上で複数コマンドを実行することはできない。 #code(vb){{ ' ipconfigコマンドをDOS窓非表示で実行し、終了後にDOS窓を閉じる CreateObject("WScript.Shell").Run "cmd /c ipconfig", 0, true ' ipconfigコマンドをDOS窓を表示して実行し、終了後にDOS窓を閉じない CreateObject("WScript.Shell").Run "cmd /k ipconfig", 1, true }} **条件評価を途中で中断しない [#jcb6ed60] Ifステートメントで複数条件をAndやOrで連結している場合、途中で条件式全体の真偽が確定したとしても、全ての条件判定を行うことに注意する。~ 下記のコードは、メッセージボックスが2回表示されることになる。 #code(vb){{ ' FalseがAndで連結されているので次の条件を評価する必要はないはずだが、MsgBox()もコールされる If False And MsgBox("test1") Then End If ' TrueがOfで連結されているので次の条件を評価する必要はないはずだが、MsgBox()もコールされる If True Or MsgBox("test2") Then End If }} **SMTPによるメール送信 [#ofa456be] CDO.Messageというオブジェクトを使用するとWSHからメール送信を行うことができる。~ #code(vb){{ Dim objMail Dim strSchemas ' CDO.Messageを準備 set objMail = WScript.CreateObject("CDO.Message") strSchemas = "http://schemas.microsoft.com/cdo/configuration/" ' SMTPの設定 objMail.Configuration.Fields.Item(strSchemas & "sendusing") = 2 ' 2:SMTPポートを利用 objMail.Configuration.Fields.Item(strSchemas & "smtpserver") = "smtp-server" ' SMTPサーバ名 objMail.Configuration.Fields.Item(strSchemas & "smtpserverport") = 25 ' SMTPポート番号 objMail.Configuration.Fields.Item(strSchemas & "smtpconnectiontimeout" ) = 30 ' タイムアウト時間 objMail.Configuration.Fields.Update ' 送信内容 objMail.From = "送信元 <aaa@hoge.co.jp>" objMail.To = "送信先1 <bbb@hoge.co.jp>; 送信先2 <ccc@hoge.co.jp>" objMail.Cc = "送信先3 <ddd@hoge.co.jp>" objMail.Bcc = "送信先4 <eee@hoge.co.jp>" objMail.Subject = "タイトル:VBSによるメール送信テスト" objMail.TextBody = _ "本文1" & vbCrLf & _ "本文2" & vbCrLf & _ "本文3" & vbCrLf 'objMail.AddAttachment = "添付ファイルのパス" ' 送信 objMail.Send ' CDO.Messageを解放 set objMail = nothing }} *VBA [#a0ce411c] **全般 [#i650993d] ***隠し関数 [#c46ed6b6] ヘルプに載っていないらしい関数。 -ObjPtr関数~ オブジェクトのポインタ取得 -StrPtr関数~ 文字列の先頭ポインタ取得~ ※うまくいかない? -VarPtr関数~ 変数のポインタ取得 ***外部オブジェクトの参照 [#aaadb43d] FileSystemObject などは、VBEの「参照」で追加にチェックを入れておけば、 #code(vb){{ Dim objFSO As New Scripting.FileSystemObject Dim objFolder As New Scripting.Folder }} のように直接変数宣言が可能となる。CreateObject不要。→解放はCreateしてないんだからいらない? ***配列の初期化はできない [#t7bb068d] VB6では以下のような配列の初期化はできない。 #code(vb){{ Dim intNum() As Integer = {1, 2, 3, 4} }} ***マクロを追加していないのにセキュリティ警告が表示される [#u68ff1bd] マクロを追加していない、もしくは全て削除したのにファイルを開くときにセキュリティ警告が表示されてしまう場合がある。~ VBEで1行でもマクロコードを書いている場合はセキュリティ警告が出てしまう。~ 例えば、シートのコード欄に #code(vb){{ Option Explicit }} が残っている可能性がある。~ 自動的に「Option Explicit」を挿入する設定になっている場合は、この状態になりやすいので注意。 **Excel [#nf10f8e1] ***セルを選択する際の注意点 [#x2a1f910] Range.Selectメソッド、またはRange.Activateメソッドを使ってセルを選択する場合、 対象のシートが選択されていないと実行時エラーとなり、メソッドが失敗する。 先に Worksheet.select メソッドで対象のシートを選択する処理を入れておくと回避できる。 ***シートの最下端の行番号/最左端の列番号 [#f5c06492] #code(vb){{ [Worksheetオブジェクト].Cells.Rows.Count ' 最下端の行番号 [Worksheetオブジェクト].Cells.Cols.Count ' 最左端の列番号 }} ***使用されているセルのうち最終の行番号/列番号 [#o2e42956] #code(vb){{ ' col列目で使用されている最終セルの行番号 [Worksheetオブジェクト].Cells([Worksheetオブジェクト].Rows.Count, col).End(xlUp).Row ' row行目で使用されている最終セルの列番号 [Worksheetオブジェクト].Cells(row, [Worksheetオブジェクト].Columns.Count).End(xlToLeft).Column }} ***別のブックへのハイパーリンク [#nf5d82ee] -マクロでの設定 #code(vb){{ Hyperlinks.Add( リンクするセル位置, ' Rangeオブジェクト アドレス, ' Webへのリンクはここ 別ブックへのハイパーリンクの場合はパスとファイル名 サブアドレス, ' リンク先の[シート名]![セル位置] ツールチップ文字列, セルに表示する文字列 ) }} -ハイパーリンクのダイアログでの設定~ [(パス)ファイル名]#[シート名]![セル位置] ***ハイパーリンクでジャンプしたときにジャンプ先のセルを画面左上に表示する [#t685c2d9] Workbook の SheetFollowHyperlinkイベントをハンドルする。 #code(vb){{ Private Sub Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal Target As Hyperlink) Call Application.Goto(Selection, True) ' 再選択かつスクロール ActiveWindow. ScrollColumn = 1 ' 行だけスクロールしたいときは列を1に戻す End Sub }} ***マクロで罫線を引く [#w0536f66] -基本 #code(vb){{ with [Rangeオブジェクト].Borders(??) ' 引数でどの罫線かを指定 .LineStyle = xlContinuous ' 実線、破線、点線・・・ .Weight = xlThin ' 太さ .ColorIndex = xlAutomatic ' 色 End With }} -上下左右縦横の罫線を引く場合 #code(vb){{ [Rangeオブジェクト].Borders.LineStyle = xlContinuous }} とすることで、以下のコードと同様の指定となる #code(vb){{ With [Rangeオブジェクト] .Borders(xlEdgeTop).LineStyle = xlContinuous .Borders(xlEdgeBottom).LineStyle = xlContinuous .Borders(xlEdgeRight).LineStyle = xlContinuous .Borders(xlEdgeLeft).LineStyle = xlContinuous .Borders(xlInsideVertical).LineStyle = xlContinuous .Borders(xlInsideHorizontal).LineStyle = xlContinuous End With }} ***アプリケーション機能の制御 [#p4f4372e] -エラーチェック機能のON/OFF~ Application.ErrorCheckingOptionsオブジェクトの各プロパティをON/OFF。~ ※最初にそのユーザの設定値を取得しておいて、終了時に元に戻すのが無難。 -セルのエラー値~ CVErr関数に取得したいエラーのID値を指定し、戻り値をセルのValueに入れることで Excel標準のセルエラーを使用できる。 -画面描画更新のON/OFF~ Application.ScreenUpdating プロパティ ***自作マクロをワークシート関数として使用する [#w0e2cab4] マクロの標準モジュール内にFunctionを定義すると、ワークシート関数として使用できる。 ***アドインマクロを自作メニューとして追加する [#m16836e7] メニューに追加されるオリジナルマクロを作る際は、メインの処理を 'Module' に追加しておく。~ ※'Module' に追加するモジュールでは、Thisworksheet オブジェクトではなく Activesheet を使用すること。~ &br; また、以下のコードを 'ThisWorkBook' に追加する。 #code(vb){{ Private Sub Workbook_AddinInstall() ' メニューを追加 Set NewM = Application.CommandBars("Worksheet Menu Bar").Controls.Add(Type:=msoControlPopup) NewM.Caption = "メニュー名" ' コマンドを追加 Set NewC = NewM.Controls.Add With NewC .Caption = "表示するコマンド名" .OnAction = "呼ばれるモジュール名" .BeginGroup = False .FaceId = 38 ' アイコン画像ID .TooltipText = "説明チップ" End With End Sub }} #code(vb){{ Private Sub Workbook_AddinUninstall() Application.CommandBars("Worksheet Menu Bar").Controls(MENU_MYMACRO).Delete End Sub }} アドインとして保存して出来上がり。 &br; ※メニューにFaceID(ツールバー上のアイコン)が同じである別のマクロをインストールすると、上書きされてしまう。 ***セルの接頭辞(先頭のシングルクォート) [#yab7402d] 接頭辞とは、強制的に文字列と解釈させるためにセルの先頭に付けられた「'」のこと。~ Range.ValueやRange.Textでは取得不可。Range.PrefixCharacterで取得可能。 ***セルの内容の取得 [#j00c9dca] Rangeオブジェクトのプロパティによって取得できる値が異なる。 |プロパティ|取得できる値|h |Range.Value|通常の値。デフォルトプロパティ| |Range.Value2|シリアル値。日付型や通貨型の場合、Valueとは異なる値となる。| |Range.Text|セルに実際に表示されている文字列。書式設定に依存する。| |Range.Formula|セルに入力された数式(イコールを含む)。数式が入力されていない場合はValueと同様の値。| **Visio [#u08a3452] ***イベント [#va3f647f] ExcelVBAのイベントのように簡単には実装できない。(外部アドインからも処理を可能とするため?)~ 詳しくは、開発者用ヘルプで「AddAdvise」や「イベント コード」を検索すること。~ 以下、ページを挿入したときのイベント「PageAdded」を実装するためのサンプル。~ +クラスモジュールを追加する。オブジェクト名は「clsEventSink」とする。 +追加したクラスモジュールに以下のコードを実装する。 #code(vb){{ Option Explicit Implements Visio.IVisEventProc '実行時のオーバーフロー エラーを回避するために 'visEvtAdd を 2 バイト値として宣言します Private Const visEvtAdd% = &H8000 Private Function IVisEventProc_VisEventProc( _ ByVal nEventCode As Integer, _ ByVal pSourceObj As Object, _ ByVal nEventID As Long, _ ByVal nEventSeqNum As Long, _ ByVal pSubjectObj As Object, _ ByVal vMoreInfo As Variant) As Variant Dim strMessage As String '発生したイベントを検出します Select Case nEventCode 'PageAddedイベント (*1) Case (visEvtPage + visEvtAdd) strMessage = "PageAdded (" & "&H" & Hex(nEventCode) & ")" ' ※ここにPageAddedイベントの処理を記述 Case Else strMessage = "Other (" & "&H" & Hex(nEventCode) & ")" End Select '動作確認用のコード ' MsgBox strMessage End Function }} +標準モジュールを追加する。オブジェクト名は任意で。 +追加した標準モジュールに以下のコードを実装する。 #code(vb){{ Option Explicit Private mEventSink As clsEventSink 'イベントオブジェクト (*2) Dim vsoDocumentEvents As Visio.EventList Dim vsoPageAddedEvent As Visio.Event 'visEvtAdd を 2 バイトの値として宣言し、 '実行時のオーバーフロー エラーを回避します。 Private Const visEvtAdd% = &H8000 Public Sub CreateEventObjects() 'clsEventSink クラスのインスタンスを作成し、 'AddAdvise メソッドに渡します。 Set mEventSink = New clsEventSink '作業中の図面の EventList コレクションを取得します。 Set vsoDocumentEvents = ActiveDocument.EventList 'PageAdded イベントの Event オブジェクトを追加します。 (*3) Set vsoPageAddedEvent = vsoDocumentEvents.AddAdvise( _ visEvtAdd + visEvtPage, mEventSink, "", "Page added...") End Sub Public Sub DeleteEventObjects() 'PageAdded イベントの Event オブジェクトを削除します。 (*4) vsoPageAddedEvent.Delete Set vsoPageAddedEvent = Nothing End Sub }} +CreateEventObjectsマクロを実行すればイベントをハンドルできる状態になる。~ ※この作業を自動化できないか。 PageAdded以外のイベントを実装するには、(*1)~(*4)の処理に任意のイベント用の処理を追記する必要がある。 *VBScript [#nf03892c] **WSHエンジン [#v7502eae] VBScriptを実行するホストは、2種類ある。~ それぞれで、WScript.Echo メソッドの処理が異なる。 -CScript ~CUIベースの処理用。~ WScript.Echo メソッドは、コマンドプロンプト上に文字列を出力する処理になる。 -WScript (既定) ~GUIベースの処理用。~ WScript.Echo メソッドは、メッセージボックスに文字列を出力する処理になる。 既定のホストを変更することも可能。 **クリップボード [#v0b99174] IE7がインストールされている状態でクリップボードを操作する場合、「インターネットオプション」-「セキュリティ」-「インターネット」を選択して「レベルのカスタマイズ」-「スクリプトによる貼り付け処理の許可」を有効にしておく必要がある。 **正規表現 [#j8135dce] RegExpオブジェクトを用いることで正規表現が使用可能。~ 特に、VBSはLike演算子を使用できないので、正規表現を替わりに使用することになる。 #code(vb){{ ' RegExp(正規表現)オブジェクト作成 Set objRE = CreateObject("VBScript.RegExp") ' 検索パターン文字列 objRE.Pattern = "^test.*test$" ' 検索対象を指定して実行 if objRE.Test("test_abcde_test") then ' マッチ else ' 非マッチ end if ' オブジェクト解放 Set objRE = Nothing }} **コモンダイアログ [#i5530e34] -ファイル選択ダイアログ #code(vb){{ Set objDlg = WScript.CreateObject("MSComDlg.CommonDialog") With objDlg .Filter = "All Files (*.*)|*.*" .MaxFileSize = 256 .CancelError = false .ShowOpen ' ShowSaveで保存ダイアログ strFileName = .Filename End With }} ※VBがインストールされていないと使えない? **スクリプトの疑似EXEファイル化 [#m6f64bff] Windowsに標準でインストールされている「IExpress.exe」を用いることで、スクリプトを疑似的にEXEファイルとして扱うことができる。~ IExpressは、もともと自己解凍形式の圧縮ファイルを作成するツールである。自己解凍形式の圧縮ファイルをインストーラ目的で使用するために、「解凍時に自動的に実行するファイル」を設定できるため、これを利用する。~ スクリプトファイルを圧縮対象のファイルに含め、「解凍時に自動的に実行するファイル」に指定することで、BAT,VBS,JS等のファイルが自動実行される。~ ※注意~ -VBSやJS等のファイルは、解凍時に自動的に実行するファイル」として直接指定するとエラーになってしまうため、スクリプトを起動するバッチファイルを書いておき、それを指定する。~ -あくまで疑似的なEXE化なので、コマンドライン引数を利用するスクリプトには使用できない。~ **スクリプトの終了 [#m04e6e07] #code(vb){{ WScript.Quit }}