PR

Excel VBAコーディングの安全性とは「(6)オブジェクト モデル・ステートメントなど」

Excel VBAの安全性
この記事は約32分で読めます。

Excelのマクロやアドオンなどを利用する際に「これ使っても大丈夫なんだよね」と気になる事は無いでしょうか?

ではそうなると、「悪くない安全なマクロやアドオンとは?どのようなコーディンクになるのか?」という疑問が沸いてくるのですが、Microsoft ドキュメントの中を探してみても、これに答えてくれるページを見つける事はできませんでした。

そこでシリーズで「Excel VBAコーディングの安全性」について考えて行く事にしました。

シリーズ六回目の今回は、VBAの「オブジェクト モデル」と「ステートメント」及び「アドイン モデル」について取り上げます。

「VBAオブジェクト モデル」には300を超える種類がありますが、今回ご説明するのはApplicationオブジェクトとWorkbookオブジェクトのメソッドが中心になります。アブケーションやブックというExcelそのものを扱うオブジェクトの中には、使い方を考慮した方が良いメソッドが存在していますが、それ以外でも注意が必要なものがありますので合わせてご紹介します。

また「ステートメント」はOffice Visual Basic for Applications (VBA) 言語リファレンスの中のVisual Basic 言語リファレンスの中にあるステートメント(Microsoftドキュメントでは日本語だと「財務諸表」と表記されてしまうのですが)に定義されている80種類弱ある中から注意すべきものをピックアップしてご説明いたします。

最後に「アドイン モデル」ですが、これはVisual Basic エディタ―(VBE)のオブジェクト モデルでメソッドとしては25種類と数は少ないのですが注意が必要なものを取り上げます。

なお、これまでと同様に追加モジュールや環境設定は必要としない前提でご説明いたします。

※動作は32bit版Excel 2016と64bit版Excel 2021の バージョン2312(ビルド 17126.20132)を使用して検証しています。

スポンサーリンク

オブジェクト モデルで気を付けるメソッド

「気を付ける」と言っても、どのような行為に対してかというと、それは決まっているのばなく様々です。

例えば、普通のやり方ではない方法で、読込んだり、保存したり、削除したり、実行したり、設定したりされると、悪意のある行為を見逃してしまうかもしれません。

このような観点から下記の表のオブジェクトとメソッドをピックアップしました。
※ 「オブジェクトのメソッド」だけではなく、「オブジェクトのオブジェクトのメソッド」のパターンも含めていますので、あらかじめお含み置きください。

Noオブジェクトオブジェクトメソッドタイプ説明
1ApplicationRecentFileDelete削除最近使用したファイルの一覧を削除
2ApplicationRun実行マクロ、あるいは、DLL や XLL に含まれる関数を実行
3ApplicationExecuteExcel4Macro実行Microsoft Excel 4.0 マクロ関数を実行
4WorkbookFollowHyperlink読込 ハイパーリンク先の目的の文書をダウンロードして、
適切なアプリケーションで文書を表示
5WorkbookSaveAs保存
設定
ファイルを保護するためのパスワードを設定
15 文字以内の文字列
6WorkbookRunAutoMacros実行ブックに登録された Auto_Openなどのマクロを実行
※以前のバージョンとの互換性を保持するため
7WorkbookPublishObjectAdd設定Webページに保存するブック内のアイテムを表すオブジェクト
作成
8PublishObjectPublish 保存ドキュメント内のアイテムまたはアイテムのコレクションをWeb
ページに保存
9WorkbookXmlMapAdd設定指定されたブックに XML マップを追加
10XmlMapImport読込指定したXML データ ファイルから、指定したXmlMapオブジェクト
マップされているセルにデータをインポート
11AddInsAdd設定アドインの一覧に新しいアドイン ファイルを追加
スクロールできます
オブジェクト モデルで気を付けるメソッド

なおオブジェクトが2つ書かれているのは、動かくメソッドを持つオブジェクトが、上位のオブジェクトのコレクションのメンバーになっているケースになります。
※具体的には後段でご説明いたします。

コーディング事例

今回取り上げるものは全てコーディング事例と呼べるほどのものではありませんが、前節の表に上げたメソッドを動かすための短いコーディンクをご紹介いたします。

①ApplicationのRecentFilesプロパティ/RecentFileオブジェクトのDeleteメソッド

これはファイルを削除するのはKillステートメントだけではない事を表す事例になります。

なおRMicrosoftドキュメントのRecentFilesオブジェクトで次のように説明されています。

ecentFiles コレクションを取得するには、Application オブジェクトの RecentFiles プロパティを使用します。

そしてRecentFileオブジェクトは、RecentFilesコレクションのメンバーになっているので、RecentFileオブジェクトは「RecentFiles(index)」の形式で指定する事ができます。この時のindex はファイルの番号になります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub RecentFiletest()
Dim cnt As Integer
cnt = 4
Application.RecentFiles(cnt).Delete
End Sub
Sub RecentFiletest() Dim cnt As Integer cnt = 4 Application.RecentFiles(cnt).Delete End Sub
Sub RecentFiletest()
Dim cnt As Integer
  cnt = 4
  Application.RecentFiles(cnt).Delete
End Sub

このコーディングでは最近使ったExcelファイルの4番目を削除しますが、「何番目まで指定でるか?」は次のCountプロパティをVBEのイミディエイトウィンドウに入力する事で調べる事ができます。

? application.RecentFiles.Count

②・③ApplicationオブジェクトのRunメソッドとExecuteExcel4Macroメソッド

最初にRunメソッドでは「マクロを実行」するのですが、PublicオプションをつけたSubステートメントで書かれたプロシージャを呼び出します。
※オプションを定しない場合、Subプロシージャは既定でパブリックになります。
※呼び出すSubプロシージャには引数をつけることはできません。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub runTest()
Application.Run ("subgetcell")
End Sub
Sub runTest() Application.Run ("subgetcell") End Sub
Sub runTest()
  Application.Run ("subgetcell")
End Sub

上記で実行しているSubプロシージャ”subgetcell”は、続けてご説明するExecuteExcel4Macroメソッドを含むコーディングになっています。

つぎにExecuteExcel4MacroメソッドはMicrosoft Excel 4.0のマクロ言語で書かれた関数を実行し、関数の結果を返します。

このメソッドはリボンメニューのファイル→オプション→トラストセンター→トラストセンターの設定のマクロの設定で「VBA マクロが有効な場合にExcel4.0のマクロを有効にする」にチェックマークを入れなくても動かすことができます。

なおMicrosoft Excel 4.0のマクロ言語は現在では説明するサイトも少なくなってきており、マクロ言語の中にどのような脅威が含まれているのか?正確には把握できていませんが、もしも使用しなければならないケースがあるのであれば、「何のために必要なのか?」が分かる方にする必要がある認識です。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub subgetcell()
Application.ExecuteExcel4Macro ("OPEN.TEXT(""" & ThisWorkbook.Path & "\test.txt"")")
End Sub
Sub subgetcell() Application.ExecuteExcel4Macro ("OPEN.TEXT(""" & ThisWorkbook.Path & "\test.txt"")") End Sub
Sub subgetcell()
  Application.ExecuteExcel4Macro ("OPEN.TEXT(""" & ThisWorkbook.Path & "\test.txt"")")
End Sub

このコーティングを実行するには、コーディングを書込んだExcelブックを保管しているフォルダーと同じフォルダーの中に”test.txt”とテキストファイルが存在する必要があります。(テキスト形式で読めれば、中身はなんでも大丈夫です)

実行すると対象のファイルをExcelブックとして開き、中身がシート(シート名は拡張子を除いたファイル名)に読み込まれて表示されます。

④WorkbookオブジェクトのFollowHyperlinkメソッド

このメソッドはMicosoftドキュメントで次のように説明されています。

既にダウンロードされている場合は、キャッシュされたドキュメントを表示します。 ダウンロードされていない場合は、ハイパーリンク先の目的の文書をダウンロードして、適切なアプリケーションで文書を表示します。

https://learn.microsoft.com/ja-jp/office/vba/api/excel.workbook.followhyperlink
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub followhyperlinkTest()
ActiveWorkbook.FollowHyperlink Address:="https://www.google.com"
End Sub
Sub followhyperlinkTest() ActiveWorkbook.FollowHyperlink Address:="https://www.google.com" End Sub
Sub followhyperlinkTest()
  ActiveWorkbook.FollowHyperlink Address:="https://www.google.com"
End Sub

実行すると既定のブラウザーでGoogleのページを開きます。

⑤WorkbookオブジェクトのSaveAsメソッド

SaveAsメソッドを使うとブックを別のファイルに保存する事ができます。その際にパスワードを設定する事もできます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub WorksheetSaveAsTest()
With ActiveWorkbook
.SaveAs Filename:=ThisWorkbook.Path & "\passset.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, Password:="password"
End With
End Sub
Sub WorksheetSaveAsTest() With ActiveWorkbook .SaveAs Filename:=ThisWorkbook.Path & "\passset.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, Password:="password" End With End Sub
 Sub WorksheetSaveAsTest()
  With ActiveWorkbook
    .SaveAs Filename:=ThisWorkbook.Path & "\passset.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, Password:="password"
  End With
End Sub

例えば上記のコーディングを実行すると、このコーディンクを保管したExcelブック名を例えば”book.xlsm”とすると、同じディレクトリに”passset.xlsm”というファイル名で保存します。この時、”passset.xlsm”には”password”という文字列でパスワードが設定されます。

この時のブックの動きは、コーディングを実行した”book.xlsm”が閉じられて、それと入れ替わりに”passset.xlsm”が開かれますのでご注意ください。

またこのコーディングを保管していない状態で実行するとエラーが発生して動かすことができません。

上記のファイル形式以外にもさまざまに形式で保存できますが、詳細はMicrosoftドキュメントの「XlFileFormat 列挙体 (Excel)」をご参照ください。

⑥WorkbookオブジェクトのRunAutoMacrosメソッド

拡張子が”.xls”の時の旧バージョンでは”Auto_Open”、”Auto_Close”、”Auto_Activate”、 “Auto_Deactivate”などの名前に設定したsubプロシージャを登録する事で、Open時、Close時、Activate時、Deactivate時などに自動的にマクロを実行できたのですが、このメソッドは、旧バージョン形式のExcelブックに保存されているこれらのマクロの中で指定されたものを実行します。

そうすると以前に作られた”.xls”形式のブックを持っていないといけない話のように思われるかもしれませんが、実は最新のExcelを使って”.xls”形式のブックとして保存する事ができます。

ファイル→名前を付けて保存の保存するファイル形式を選択するプルダウンメニューの中には「Excel 97-2003 ブック(*.xls)」が存在しています。

そこで今回は、”Macro2003.xls”という名前の「Excel 97-2003 ブック(*.xls)」形式のブックを同じディレクトリに作り、標準モジュールを追加して次のsubプロシージャを保存します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub Auto_Open()
MsgBox "Hellow!"
End Sub
Sub Auto_Open() MsgBox "Hellow!" End Sub
Sub Auto_Open()
  MsgBox "Hellow!"
End Sub

その上で、RunAutoMacros メソッドを動かすためのコーディングはつぎのようになります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub RunAutoMacrosTest()
Workbooks.Open ThisWorkbook.Path & "\Macro2003.xls"
ActiveWorkbook.RunAutoMacros xlAutoOpen
End Sub
Sub RunAutoMacrosTest() Workbooks.Open ThisWorkbook.Path & "\Macro2003.xls" ActiveWorkbook.RunAutoMacros xlAutoOpen End Sub
Sub RunAutoMacrosTest()
  Workbooks.Open ThisWorkbook.Path & "\Macro2003.xls"
  ActiveWorkbook.RunAutoMacros xlAutoOpen
End Sub

subプロシージャを実行するには、先ほどご紹介したRunメソッドの他に、Callステートメントを別のプロシージャの中で使用したり、各種イベントのプロシージャの中に記述する事になりますが、今回ご紹介したのはそれとは少し違った形ですので、見落とさないようにする必要があります。

⑦・⑧WorkbookオブジェクトのPublishObjectsプロパティ/PublishObjectオブジェクトのAddメソッドとPublishメソッド

⑦と⑧の2つのメソッドを使ってExcelブック内のアイテムなどをWebページとして保存します。

まず最初にAddメソッドでブックにWeb ページに保存するPublishObjectオブジェクトを作成し、つぎにPublishObjectオブジェクトのPublishメソッドでドキュメント内のアイテムまたはアイテムのコレクションをWeb ページに保存します。

具体的なコーディングとしてはつぎのようになります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub PublishObjectsTest()
With ActiveWorkbook.PublishObjects.Add(SourceType:=xlSourceRange, _
Filename:=ThisWorkbook.Path & "\PublishObjectsTest.html", _
Sheet:="Sheet1", _
Source:="A1:C21", _
HtmlType:=xlHtmlStatic)
.Publish (True)
End With
End Sub
Sub PublishObjectsTest() With ActiveWorkbook.PublishObjects.Add(SourceType:=xlSourceRange, _ Filename:=ThisWorkbook.Path & "\PublishObjectsTest.html", _ Sheet:="Sheet1", _ Source:="A1:C21", _ HtmlType:=xlHtmlStatic) .Publish (True) End With End Sub
Sub PublishObjectsTest()
  With ActiveWorkbook.PublishObjects.Add(SourceType:=xlSourceRange, _
    Filename:=ThisWorkbook.Path & "\PublishObjectsTest.html", _
    Sheet:="Sheet1", _
    Source:="A1:C21", _
    HtmlType:=xlHtmlStatic)
    .Publish (True)
  End With
End Sub

上記のコーディングを実行すると、Sheet1シートのA1:C21のセル範囲をhtml言語に変換して、 コーディンクを保管したExcelブックと同じディレクトリに”PublishObjectsTest.html”というファイル名で保存します。

⑨・⑩ WorkbookオブジェクトのXmlMapsプロパティ/XmlMapオブジェクトのAddメソッドとImportメソッド

前章と同様に2つのメソッドを使って、指定したXMLデータ ファイルをExcelブック内の指定したXmlMapオブジェクトに定義されているセルにインポートします。

なおExcelでXMLを読み込む話題については、つぎの投稿で詳しくご紹介していますので合わせてご一読いただければ幸いです。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub XmlMapsTest()
Dim strSchemaLocation As String
Dim xMap As XmlMap
strSchemaLocation = ThisWorkbook.Path & "\HolidayTable.xsd"
Set xMap = ActiveWorkbook.XmlMaps.Add(strSchemaLocation, "Worksheet")
ActiveSheet.Range("A1:A23").XPath.SetValue xMap, "/Worksheet/Row/Data"
ActiveSheet.Range("B1:B23").XPath.SetValue xMap, "/Worksheet/Row/Note"
ActiveSheet.Range("C1:C23").XPath.SetValue xMap, "/Worksheet/Row/Name"
xMap.Import ThisWorkbook.Path & "\HolidayTable.xml"
End Sub
Sub XmlMapsTest() Dim strSchemaLocation As String Dim xMap As XmlMap strSchemaLocation = ThisWorkbook.Path & "\HolidayTable.xsd" Set xMap = ActiveWorkbook.XmlMaps.Add(strSchemaLocation, "Worksheet") ActiveSheet.Range("A1:A23").XPath.SetValue xMap, "/Worksheet/Row/Data" ActiveSheet.Range("B1:B23").XPath.SetValue xMap, "/Worksheet/Row/Note" ActiveSheet.Range("C1:C23").XPath.SetValue xMap, "/Worksheet/Row/Name" xMap.Import ThisWorkbook.Path & "\HolidayTable.xml" End Sub
Sub XmlMapsTest()
Dim strSchemaLocation As String
Dim xMap As XmlMap
  strSchemaLocation = ThisWorkbook.Path & "\HolidayTable.xsd"
  Set xMap = ActiveWorkbook.XmlMaps.Add(strSchemaLocation, "Worksheet")
  ActiveSheet.Range("A1:A23").XPath.SetValue xMap, "/Worksheet/Row/Data"
  ActiveSheet.Range("B1:B23").XPath.SetValue xMap, "/Worksheet/Row/Note"
  ActiveSheet.Range("C1:C23").XPath.SetValue xMap, "/Worksheet/Row/Name"
  xMap.Import ThisWorkbook.Path & "\HolidayTable.xml"
End Sub

上記のコーディングを実行するためには下記の2つのファイルが必要になります。
※コーディンクを保管したExcelブックと同じディレクトリに保存してください.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Worksheet">
<xs:complexType>
<xs:sequence>
<xs:element name="Year" type="xs:unsignedShort" />
<xs:element maxOccurs="19" name="Row">
<xs:complexType>
<xs:sequence>
<xs:element name="Data" type="xs:date" />
<xs:element name="Note">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Worksheet"> <xs:complexType> <xs:sequence> <xs:element name="Year" type="xs:unsignedShort" /> <xs:element maxOccurs="19" name="Row"> <xs:complexType> <xs:sequence> <xs:element name="Data" type="xs:date" /> <xs:element name="Note"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="3"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="Name"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="10"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Worksheet">
<xs:complexType>
<xs:sequence>
<xs:element name="Year" type="xs:unsignedShort" />
<xs:element maxOccurs="19" name="Row">
<xs:complexType>
<xs:sequence>
   <xs:element name="Data" type="xs:date" />
   <xs:element name="Note">
    <xs:simpleType>
     <xs:restriction base="xs:string">
      <xs:maxLength value="3"/>
     </xs:restriction>
    </xs:simpleType>
   </xs:element>
   <xs:element name="Name">
    <xs:simpleType>
     <xs:restriction base="xs:string">
      <xs:maxLength value="10"/>
     </xs:restriction>
    </xs:simpleType>
   </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

“HolidayTable.xsd”という名前を付けて保存

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?xml version="1.0" encoding="UTF-8"?>
<Worksheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="HolidayTable.xsd">
<Year>2024</Year>
<Row><Data>2024-01-01</Data><Note>(月)</Note><Name>元日</Name></Row>
<Row><Data>2024-01-08</Data><Note>(月)</Note><Name>成人の日</Name></Row>
<Row><Data>2024-02-11</Data><Note>(日)</Note><Name>建国記念の日</Name></Row>
<Row><Data>2024-02-12</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-02-23</Data><Note>(金)</Note><Name>天皇誕生日</Name></Row>
<Row><Data>2024-03-20</Data><Note>(水)</Note><Name>春分の日</Name></Row>
<Row><Data>2024-04-29</Data><Note>(月)</Note><Name>昭和の日</Name></Row>
<Row><Data>2024-05-03</Data><Note>(金)</Note><Name>憲法記念日</Name></Row>
<Row><Data>2024-05-04</Data><Note>(土)</Note><Name>みどりの日</Name></Row>
<Row><Data>2024-05-05</Data><Note>(日)</Note><Name>こどもの日</Name></Row>
<Row><Data>2024-05-06</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-07-15</Data><Note>(月)</Note><Name>海の日</Name></Row>
<Row><Data>2024-08-11</Data><Note>(日)</Note><Name>山の日</Name></Row>
<Row><Data>2024-08-12</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-09-16</Data><Note>(月)</Note><Name>敬老の日</Name></Row>
<Row><Data>2024-09-22</Data><Note>(日)</Note><Name>秋分の日</Name></Row>
<Row><Data>2024-09-23</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-10-14</Data><Note>(月)</Note><Name>スポーツの日</Name></Row>
<Row><Data>2024-11-03</Data><Note>(日)</Note><Name>文化の日</Name></Row>
<Row><Data>2024-11-04</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-11-23</Data><Note>(土)</Note><Name>勤労感謝の日</Name></Row>
</Worksheet>
<?xml version="1.0" encoding="UTF-8"?> <Worksheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="HolidayTable.xsd"> <Year>2024</Year> <Row><Data>2024-01-01</Data><Note>(月)</Note><Name>元日</Name></Row> <Row><Data>2024-01-08</Data><Note>(月)</Note><Name>成人の日</Name></Row> <Row><Data>2024-02-11</Data><Note>(日)</Note><Name>建国記念の日</Name></Row> <Row><Data>2024-02-12</Data><Note>(月)</Note><Name>振替休日</Name></Row> <Row><Data>2024-02-23</Data><Note>(金)</Note><Name>天皇誕生日</Name></Row> <Row><Data>2024-03-20</Data><Note>(水)</Note><Name>春分の日</Name></Row> <Row><Data>2024-04-29</Data><Note>(月)</Note><Name>昭和の日</Name></Row> <Row><Data>2024-05-03</Data><Note>(金)</Note><Name>憲法記念日</Name></Row> <Row><Data>2024-05-04</Data><Note>(土)</Note><Name>みどりの日</Name></Row> <Row><Data>2024-05-05</Data><Note>(日)</Note><Name>こどもの日</Name></Row> <Row><Data>2024-05-06</Data><Note>(月)</Note><Name>振替休日</Name></Row> <Row><Data>2024-07-15</Data><Note>(月)</Note><Name>海の日</Name></Row> <Row><Data>2024-08-11</Data><Note>(日)</Note><Name>山の日</Name></Row> <Row><Data>2024-08-12</Data><Note>(月)</Note><Name>振替休日</Name></Row> <Row><Data>2024-09-16</Data><Note>(月)</Note><Name>敬老の日</Name></Row> <Row><Data>2024-09-22</Data><Note>(日)</Note><Name>秋分の日</Name></Row> <Row><Data>2024-09-23</Data><Note>(月)</Note><Name>振替休日</Name></Row> <Row><Data>2024-10-14</Data><Note>(月)</Note><Name>スポーツの日</Name></Row> <Row><Data>2024-11-03</Data><Note>(日)</Note><Name>文化の日</Name></Row> <Row><Data>2024-11-04</Data><Note>(月)</Note><Name>振替休日</Name></Row> <Row><Data>2024-11-23</Data><Note>(土)</Note><Name>勤労感謝の日</Name></Row> </Worksheet>
<?xml version="1.0" encoding="UTF-8"?>
<Worksheet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="HolidayTable.xsd">
<Year>2024</Year>
<Row><Data>2024-01-01</Data><Note>(月)</Note><Name>元日</Name></Row>
<Row><Data>2024-01-08</Data><Note>(月)</Note><Name>成人の日</Name></Row>
<Row><Data>2024-02-11</Data><Note>(日)</Note><Name>建国記念の日</Name></Row>
<Row><Data>2024-02-12</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-02-23</Data><Note>(金)</Note><Name>天皇誕生日</Name></Row>
<Row><Data>2024-03-20</Data><Note>(水)</Note><Name>春分の日</Name></Row>
<Row><Data>2024-04-29</Data><Note>(月)</Note><Name>昭和の日</Name></Row>
<Row><Data>2024-05-03</Data><Note>(金)</Note><Name>憲法記念日</Name></Row>
<Row><Data>2024-05-04</Data><Note>(土)</Note><Name>みどりの日</Name></Row>
<Row><Data>2024-05-05</Data><Note>(日)</Note><Name>こどもの日</Name></Row>
<Row><Data>2024-05-06</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-07-15</Data><Note>(月)</Note><Name>海の日</Name></Row>
<Row><Data>2024-08-11</Data><Note>(日)</Note><Name>山の日</Name></Row>
<Row><Data>2024-08-12</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-09-16</Data><Note>(月)</Note><Name>敬老の日</Name></Row>
<Row><Data>2024-09-22</Data><Note>(日)</Note><Name>秋分の日</Name></Row>
<Row><Data>2024-09-23</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-10-14</Data><Note>(月)</Note><Name>スポーツの日</Name></Row>
<Row><Data>2024-11-03</Data><Note>(日)</Note><Name>文化の日</Name></Row>
<Row><Data>2024-11-04</Data><Note>(月)</Note><Name>振替休日</Name></Row>
<Row><Data>2024-11-23</Data><Note>(土)</Note><Name>勤労感謝の日</Name></Row>
</Worksheet>

“HolidayTable.xml”という名前を付けて保存

⑪AddinsオブジェクトのAdd メソッド

このメソッドはアドインの一覧に新しいアドイン ファイルを追加します。追加したAddInオブジェクトに対してInstalledプロパティをTrueに設定するとアドインが組み込まれます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub addinAddTest()
Dim myAddin As AddIn
Set myAddin = AddIns.Add(Filename:=ThisWorkbook.Path & "\Macro2024.xlam", CopyFile:=True)
myAddin.Installed = True
End Sub
Sub addinAddTest() Dim myAddin As AddIn Set myAddin = AddIns.Add(Filename:=ThisWorkbook.Path & "\Macro2024.xlam", CopyFile:=True) myAddin.Installed = True End Sub
Sub addinAddTest()
Dim myAddin As AddIn
  Set myAddin = AddIns.Add(Filename:=ThisWorkbook.Path & "\Macro2024.xlam", CopyFile:=True)
  myAddin.Installed = True
End Sub

このコーディングを実行すると①”Macro2024″アドインが登録されて、②リボンに”MyAddin”が追加され、③は”MyAddin”をクリックした時で、④は”メッセージ”をクリックした時に表示されるメッセージになります 。

この動作確認のためには”Macro2024.xlam”のExcelアドインファイルが必要になります。

ただし、サイトにアドイン ファイルのダウンロードリンクを用意したとしても、悪意のあるプログラムかもしれないので、ダウンロードはしていただけない認識です。

そこで、次にこのファイルの作り方を簡単にご説明いたします。

なお追加されるメニューリボンに表示される「シートを開く」「シートを閉じる」は、xlamファイルはxlsxとは異なりデフォルトではワークシートが表示されていないのですが、それを開いたり、閉じたりするための機能を盛り込んでいます。
※具体的なコーディング内容は後段でご紹介していますので、合わせてご確認いただければ幸いです。

“Macro2024.xlam”アドインファイルの作り方

①Exelを起動し、新規で空白ブックを選択し開き、シート名のタブでマウス右ボタンでショートカットメニューを表示して「コード の表示」をクリック

②VBEメニューの挿入→標準モジュールで、下記コーディングをすべてコピーして貼り付けした後、VBEメニューのファイル→Book1の上書き保存

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Option Explicit
' リボンの初期処理(Add-inがonLoadされた時)
Private Sub CustomUIOnload(ribbon As IRibbonUI)
ribbon.Invalidate ' リボンの表示を更新する
End Sub
'設定シートを開くの処理
Private Sub ConfigOpen(control As IRibbonControl)
ThisWorkbook.IsAddin = False
End Sub
'設定シートを閉じるの処理
Private Sub ConfigClose(control As IRibbonControl)
Dim sp_target As Shape
ThisWorkbook.IsAddin = True
End Sub
'バージョンの処理
Private Sub ShowMessage(control As IRibbonControl)
MsgBox "Hellow World!"
End Sub
Option Explicit ' リボンの初期処理(Add-inがonLoadされた時) Private Sub CustomUIOnload(ribbon As IRibbonUI) ribbon.Invalidate ' リボンの表示を更新する End Sub '設定シートを開くの処理 Private Sub ConfigOpen(control As IRibbonControl) ThisWorkbook.IsAddin = False End Sub '設定シートを閉じるの処理 Private Sub ConfigClose(control As IRibbonControl) Dim sp_target As Shape ThisWorkbook.IsAddin = True End Sub 'バージョンの処理 Private Sub ShowMessage(control As IRibbonControl) MsgBox "Hellow World!" End Sub
Option Explicit
' リボンの初期処理(Add-inがonLoadされた時)
Private Sub CustomUIOnload(ribbon As IRibbonUI)
    ribbon.Invalidate ' リボンの表示を更新する
End Sub
'設定シートを開くの処理
Private Sub ConfigOpen(control As IRibbonControl)
    ThisWorkbook.IsAddin = False
End Sub
'設定シートを閉じるの処理
Private Sub ConfigClose(control As IRibbonControl)
Dim sp_target As Shape
    ThisWorkbook.IsAddin = True
End Sub
'バージョンの処理
Private Sub ShowMessage(control As IRibbonControl)
    MsgBox "Hellow World!"
End Sub

③「名前を付けて保存」が開くので、まず最初にファイルの種類は「Excelアドイン(*.xlam)」を選択します。するとデフォルトのアドイン保存先のフォルダーに切り替わりますが、ここではアクセスし易い適当なフォルダーにファイル名”Macro2024.xlam”にして保存します。

その後、VBEもBook1.xlsxも保存せずに終了します。

④保存した”Macro2024.xlam”を選択し、「名前の変更」で、最後に”.zip”を付けて”Macro2024.xlam.zip”にして「はい」ボタンで変更します。

ZIPファイルにアイコン表示が変わったらZIPファイルをダブルクリックで開いて、中身のすべてのフォルダーとファイルをコピーしてから、 ZIP元のフォルダーに戻り、貼り付けします。

⑤”customUI”というフォルダを新規作成して、そのなかに、”customUI14.xml”という名前でテキストドキュメントを新規作成し、メモ帳で開いて、下記のコーディングを貼り付け保存します。文字コードはUTF8に設定します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="CustomUIOnload">
<ribbon>
<tabs>
<tab id="customtab" label="MyAddin">
<group id="mygrp" label="設定">
<button id="cnfgopen" label="シートを開く" imageMso="FileOpen" onAction="ConfigOpen" />
<button id="cnfgclose" label="シートを閉じる" imageMso="FileClose" onAction="ConfigClose" />
<button id="version" label="メッセージ" imageMso="HappyFace" onAction="ShowMessage" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>
<?xml version="1.0" encoding="utf-8"?> <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="CustomUIOnload"> <ribbon> <tabs> <tab id="customtab" label="MyAddin"> <group id="mygrp" label="設定"> <button id="cnfgopen" label="シートを開く" imageMso="FileOpen" onAction="ConfigOpen" /> <button id="cnfgclose" label="シートを閉じる" imageMso="FileClose" onAction="ConfigClose" /> <button id="version" label="メッセージ" imageMso="HappyFace" onAction="ShowMessage" /> </group> </tab> </tabs> </ribbon> </customUI>
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="CustomUIOnload">
  <ribbon>
    <tabs>
      <tab id="customtab" label="MyAddin">
        <group id="mygrp" label="設定">
	  <button id="cnfgopen" label="シートを開く" imageMso="FileOpen" onAction="ConfigOpen" />
	  <button id="cnfgclose" label="シートを閉じる" imageMso="FileClose" onAction="ConfigClose" />
	  <button id="version" label="メッセージ" imageMso="HappyFace" onAction="ShowMessage" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

⑥ ZIP元のフォルダーにある”_rels”のフォルダーを開き、中にある”.rels”ファイルをメモ帳で開きます。

矢印のところに、下記のコーティングを挿入し保存します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<Relationship Id="customUI" Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility" Target="customUI/customUI14.xml"/>
<Relationship Id="customUI" Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility" Target="customUI/customUI14.xml"/>
<Relationship Id="customUI"  Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility"  Target="customUI/customUI14.xml"/>

⑦_relsフォルダーから[Content_Types].xmlファイルまでの5つをすべて選択し、ZIPファイルに圧縮します。

⑧最後に、圧縮されたZIPファイルのファイル名をMacro2024.xlamに変更すれば、 アドインファイルが完成します。

ステートメントで気を付けるメソッド

ステートメントは2つ取り上げます。

その内のKillステートメントは必要に応じて使われるケースがある事と存じますか、除外する訳にもいかないのであらかじめお含み置きください。

Noステートメントタイプ説明
1Kill削除削除する 1 つ以上のファイル名を指定
2SendKeys送信1 つ以上のキーボード操作をアクティブなウィンドウに送信
スクロールできます
ステートメントで気を付けるメソッド

コーディング事例

使い方を具体的にご説明して行きます。

①Killステートメント

削除する対象をディレクトリやフォルダーで指定する事ができますが、削除されるのはファイルで、ディレクトリ自体を削除するにはReDirステートメントを使用します。
※ReDirステートメントはディレクトリにファイルが存在すると削除することはできません。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub killTest()
Kill ThisWorkbook.Path & "\新規 テキスト ドキュメント.txt"
End Sub
Sub killTest() Kill ThisWorkbook.Path & "\新規 テキスト ドキュメント.txt" End Sub
Sub killTest()
  Kill ThisWorkbook.Path & "\新規 テキスト ドキュメント.txt"
End Sub

②Sendkeysステートメント

MicrosoftドキュメントのSendKeysステートメントではつぎのように説明されています。

キーボードから入力したかのように、1 つ以上のキーボード操作をアクティブなウィンドウに送信します。

Microsoftドキュメントを見ていただくと分かるのですが、キーを押したときに表示されない文字や「通常のキーと Shift、Ctrl、および Alt キーの任意の組み合わせ」も指定することはできるのですが、表記の仕方にはルールがあるので実際に使うには試行錯誤が必要になりそうです。

またつぎのような注意書きがされています。

Microsoft WindowsまたはMacintoshで実行するように設計されていないアプリケーションにキーストロークを送信する場合は、SendKeysを使用できません。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub SendkeysTest()
Dim rtn As Long
Dim i As Integer
rtn = Shell("Notepad.exe", 1)
If rtn <> 0 Then
For i = 1 To 3
SendKeys "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
SendKeys "{Enter}"
Next i
SendKeys "%{F4}"
Else
MsgBox "失敗しました"
End If
End Sub
Sub SendkeysTest() Dim rtn As Long Dim i As Integer rtn = Shell("Notepad.exe", 1) If rtn <> 0 Then For i = 1 To 3 SendKeys "ABCDEFGHIJKLMNOPQRSTUVWXYZ" SendKeys "{Enter}" Next i SendKeys "%{F4}" Else MsgBox "失敗しました" End If End Sub
Sub SendkeysTest()
Dim rtn As Long
Dim i As Integer
  rtn = Shell("Notepad.exe", 1)
  If rtn <> 0 Then
    For i = 1 To 3
      SendKeys "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      SendKeys "{Enter}"
    Next i
    SendKeys "%{F4}"
  Else
    MsgBox "失敗しました"
  End If
End Sub

上記のコーディングを実行すると、メモ帳のアプリケーションが起動されて、A~Zと改行キーを3回入力した後にAltキーを押しながらF4キーを押してメモ帳を終了させます。

保存せずに入力途中で終了させているので、手動でメモ帳を起動すると保存するか?のメッセージが表示されます。

アドイン モデルで気を付けるメソッド

Microsoftドキュメントではアドイン モデルについてつぎのように説明しています。

Visual Basic エディターのカスタマイズ方法と、環境を拡張するために使用できるオブジェクト モデル

アドインモデルでは4つのメソッドについて取り上げます。ただし①~③の3つはセキュリティセンターでの設定が必要になるので、標準のまま使用するのであれば脅威にはならない認識です。

Noメソッドタイプ説明
1Import読込ファイルからプロジェクトにコンポーネントを追加
2InsertLines読込コードの指定した場所に、1 行または複数行のコードを挿入
3ReplaceLine置換既存のコード行を指定したコードで置換
4InsertFile読込ファイルからコード モジュールにコードを読込
スクロールできます
アドイン モデルで気を付けるメソッド

コーディング事例

①~③の3つを実際に動かすためには、「ファイル」リボンメニュー→オプション→トラストセンター→トラストセンターの設定→マクロの設定で、「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」にチェック マークを付ける必要がありますので、あらかじめお含み置きください。

①アドイン モデルのImportメソッド

このメソッドについては、実は本シリーズの第2回「(2)EXEやソースの隠蔽」の中の「実行しているExcelファイルと同じフォルダーに置かれたモジュールを追加する」で一度ご紹介していますが、今回の切り口でご説明するにあたり、取り上げないのも網羅性に欠けるので、再度コーディング事例をご紹介いたします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub ImportTest()
With ThisWorkbook.VBProject.VBComponents
.Import ThisWorkbook.Path & "\ModuleX1.bas"
End With
End Sub
Sub ImportTest() With ThisWorkbook.VBProject.VBComponents .Import ThisWorkbook.Path & "\ModuleX1.bas" End With End Sub
 Sub ImportTest()
  With ThisWorkbook.VBProject.VBComponents
    .Import ThisWorkbook.Path & "\ModuleX1.bas"
  End With
End Sub
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Attribute VB_Name = "ModuleX1"
Sub Xmain()
MsgBox "Hallow World!"
End Sub
Attribute VB_Name = "ModuleX1" Sub Xmain() MsgBox "Hallow World!" End Sub
Attribute VB_Name = "ModuleX1"
Sub Xmain()
  MsgBox "Hallow World!"
End Sub

ModuleX1.basの内容

WorkbookオブジェクトのVBProjectプロパティは、対象ブックのVBprojectオブジェクトを返します。

Microsoftドキュメントでは、この”VBproject”はアドイン モデルのオブジェクトの中でつぎのように説明されています。

VBProject オブジェクトを使用して、プロジェクトのプロパティを設定し、VBComponentsコレクションと References コレクションにアクセスします。

https://learn.microsoft.com/ja-jp/office/vba/language/reference/visual-basic-add-in-model/objects-visual-basic-add-in-model

ここでは”VBComponents”コレクションを使用しますが、これにより「プロジェクト内のコンポーネントへのアクセス、追加、または削除」をする事ができるようになります。

Importメソッドは「コンポーネントの追加」の機能になりますが、上記のコーディングを実行すると、標準モジュールに”ModuleX1″が追加されます。

※実行する時、トラストセンターで「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」にチェックがされていないとエラーになります。

②と③アドイン モデルのInsertLinesメソッドとreplacelineメソッド

両者はほぼ同じコーディングになるので1つにまとめた事例をご紹介します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub InsertReplaceLinesTest()
Dim mdl As Object
Dim rtn As Long
Dim st_code As String
Set mdl = ThisWorkbook.VBProject.VBComponents("ModuleX1").CodeModule
st_code = "MsgBox ""Make happy"""
rtn = mdl.InsertLines(3, st_code)
Debug.Print rtn
st_code = "MsgBox ""A happy new year!"""
rtn = mdl.replaceline(2, st_code)
Debug.Print rtn
End Sub
Sub InsertReplaceLinesTest() Dim mdl As Object Dim rtn As Long Dim st_code As String Set mdl = ThisWorkbook.VBProject.VBComponents("ModuleX1").CodeModule st_code = "MsgBox ""Make happy""" rtn = mdl.InsertLines(3, st_code) Debug.Print rtn st_code = "MsgBox ""A happy new year!""" rtn = mdl.replaceline(2, st_code) Debug.Print rtn End Sub
Sub InsertReplaceLinesTest()
Dim mdl As Object
Dim rtn As Long
Dim st_code As String
  Set mdl = ThisWorkbook.VBProject.VBComponents("ModuleX1").CodeModule
  st_code = "MsgBox ""Make happy"""
  rtn = mdl.InsertLines(3, st_code)
  Debug.Print rtn
  st_code = "MsgBox ""A happy new year!"""
  rtn = mdl.replaceline(2, st_code)
  Debug.Print rtn
End Sub

“CodeModule”は”VBComponents”に関わるコードを表すオブジェクトを返します。
※少しややこしいのですが、”CodeModule”は”VBComponents”のプロパティーであり、「コンポーネントの分離コードを表す」オブジェクトでもあります。

上記のコーディングを実行すると、表塾モジュール”ModuleX1″の3行目に「MsgBox “Make happy”」を追加して、2行目を「MsgBox “A happy new year!”」に置き換えます。

※実行する時、トラストセンターで「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」にチェックがされていないとエラーになります。

④アドイン モデルのInsertFileメソッド

最後のInsertFileメソッドは①~③とは異なり、 VBProjectオブジェクトのVBComponentsプロパティ―を使いません。
※アドインモデルのメソッドの中に位置づけられているのですが、”VBComponents”にはInsertFileメソッドはなく、実際にコーディングしてもエラーになります。

ではどこに紐づいているのか?Micosoftドキュメントで検索したところ、「.NET/APIプラウサー/Microsoft.Office.Interop.Excel/」の階層に”Module”があり、そのメソッドに”InserFile”が存在することが解りました。

同じ階層に”Modules.Add”メソッドがあり、どうやらModluesにAddしてから、追加したModuleにInserFileすれば良いそうでしたので次のようなコーディンクを試して見ました。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Sub InsertFileTest()
Dim newModule As Object
Set newModule = Modules.Add
newModule.InsertFile Filename:=ThisWorkbook.Path & "\ModuleX1.bas"
End Sub
Sub InsertFileTest() Dim newModule As Object Set newModule = Modules.Add newModule.InsertFile Filename:=ThisWorkbook.Path & "\ModuleX1.bas" End Sub
Sub InsertFileTest()
Dim newModule As Object
  Set newModule = Modules.Add
  newModule.InsertFile Filename:=ThisWorkbook.Path & "\ModuleX1.bas"
End Sub

これを実行すると①のアドイン モデルのImportメソッドと同じ結果になりました。

まとめと次回の予定

シリーズで六回ほど「Excel VBAコーディングの安全性」について考えてきました。

今回は、VBAの「オブジェクト モデル」と「ステートメント」及び「アドイン モデル」について取り上げましたが、これだけ沢山のメソッドがあると「どのような事に注意すべきなのか?」をまとめる事は難しいので、今回は前段に掲載した一覧表にポイントを記載する形でまとめに変えさせていただきたく存じます。

Noオブジェクトオブジェクトメソッドタイプポイント
1ApplicationRecentFileDelete削除最近使用したファイルが最大50件削除される
2ApplicationRun実行指定したマクロが実行されてしまう。
3ApplicationExecuteExcel4Macro実行Microsoft Excel 4.0 マクロ関数が実行される。
4WorkbookFollowHyperlink読込 ハイパーリンク先をブラウザーに表示してしまう。
5WorkbookSaveAs保存
設定
Excelファイルにパスワードを設定してしまう。
6WorkbookRunAutoMacros実行以前のバージョンのxlsファイルの中にあるマクロが実行される。
7WorkbookPublishObjectAdd設定No7と8で、シートの内容がWeb ページに保存されてしまう。
8PublishObjectPublish 保存
9WorkbookXmlMapAdd設定No9と10で、指定した XML データ ファイルからマップされている
10XmlMapImport読込セルにデータをインポートする。
11AddInsAdd設定アドインの一覧に新しいアドイン ファイルを追加する。
スクロールできます
オブジェクト モデルで気を付けるメソッド
Noステートメントタイプポイント
1Kill削除ファイルを削除する。
2SendKeys送信アクティブなウィンドウにキーボード操作を送信する。
スクロールできます
ステートメントで気を付けるメソッド
Noメソッドタイプポイント
1Import読込ファイルからプロジェクトにコンポーネントを追加する。要トラストセンター
2InsertLines読込コードの指定した場所に、1 行または複数行のコードを挿入する。要トラストセンター
3ReplaceLine置換既存のコード行を指定したコードで置換する。要トラストセンター
4InsertFile読込ファイルからコード モジュールにコードを読込む。
スクロールできます
アドイン モデルで気を付けるメソッド

次回は、これまでのシリーズで取り上げてきた内容の補足と、確認し易いようにできれば一覧にまとめてご紹介したいと思います。

以上最後までご一読いただき誠にありがとうございました。