【Excel VBA】リボンの自作タブをアドインファイル(xlam)に埋め込む

# 概要
Microsoft Officeの各ソフトにはリボンというツールバーがあります．これに自作のタブを追加したりマクロを登録したりするとき，個人であれば[設定から1つずつ追加](https://support.microsoft.com/ja-jp/office/%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AB%E3%83%9E%E3%82%AF%E3%83%AD%E3%82%92%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E3%82%8B-728c83ec-61d0-40bd-b6ba-927f84eb5d2c)すればよいです．
しかし，常に表示される必要はない機能も多くあり「必要なときに1クリックでタブを追加してほしい」というときもあります．
![Excelのリボン例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/bfce463f-4185-5f22-4d5c-05c762f015db.png)

この記事では「"アドイン名.xlam"を開いたときにリボンにタブを追加する方法」を説明します．

# バージョン
動作確認した環境は以下の通りです．
* OS
    * Windows 11 Home 
    * バージョン　`23H2`
* Excel
    * Microsoft 365
    * バージョン　`2402 ビルド 16.0.17328.20124` (64 ビット)

# 初期設定手順
以下のような流れで行います．
1. 事前準備(開発タブの表示)
1. アドインファイル(アドイン名.xlam)を用意
1. アドインを"開く"
1. 内部ファイルを書き換え
1. アドインを"閉じる"
1. 起動テスト

## 事前準備(開発タブの表示)
すでに開発タブを表示している方は次へ進んでください．

これはExcelのオプションから「リボンのユーザー設定」にある「開発」にチェックを入れるだけでよいです．
![開発タブの表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/a44e0101-9175-2f4e-4aa4-2dd8a3268950.png)

## アドインファイル(アドイン名.xlam)を用意
Excelのアドインファイルを用意しましょう．
新しく空白のブックを開きます．

:::note info
既存のブックも使えますがシートが見えなくなります
:::

### 新しくブックを作成する場合
#### VBE 起動
開発タブから「Visual Basic」をクリックしてVBEを開きます．
![VisualBasicボタンの位置](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/1d63498d-4162-a36d-9004-99f1144e25e1.png)
こんなのが出てくるはずです↓
![VBE起動後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/a4f1bbf0-d905-cc2d-fd4f-5ba8b3ee6a65.png)

::: note info
もし左の「プロジェクト」や「プロパティ」などが見つからない場合は上のメニューの **「表示」＞「プロジェクトエクスプローラー」** や **「表示」＞「プロパティウィンドウ」** から表示させることが出来ます．
:::

#### ThisWorkbookのIsAddinをTrueに変更
VBEを開いたら，「プロジェクト - VBEProject」から「ThisWorkbook」を見つけてクリック，プロパティを表示し，そこから「IsAddin」という設定を探して(はじめはFalseになっているはずなので)Trueに変更します(図では縦長にならないように横に並べています)．
![IsAddinをTrueに変更する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/a2cef852-3389-f007-7e65-76bcb1753c09.png)


::: note info
「VBAProject (Book 1)しか見えない」という場合は，アイコンの左にある **ちっちゃいプラスマーク($+$)から下位のファイルを見ることが出来ます** ．
:::

::: note info
うまくいっていれば，IsAddinをTrueにすると後ろにあるExcelのシートが見えなくなります．
:::

#### ブックをアドインとして保存
それができたらVBE側で「ファイル」＞「？？？？の上書き保存」で保存します．

新しくブックを作成した場合は保存場所がないのでこのタイミングで保存場所を確認させられます．好きな場所に好きな名前で保存してよいです．保存場所はあまり関係ありませんが **クラウドへの保存はお勧めしません** [^saveDir]．

::: note warn
保存するとき，ファイルの種類を「Excelアドイン (.xlam)」に必ず変えてください．
![ファイルの種類をXLAMに変更](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/6f2ca107-3614-8a92-34b2-fa32f83cafd2.png)
:::

::: note warn
Excelの仕様上，ファイルの種類を変更すると保存先が
`C:\Users\****\AppData\Roaming\Microsoft\AddIns`
のような場所に移動してしまいます．
~~面倒ですが~~ 好きな場所まで移動して保存するようにしましょう．
:::

---

### 既存のブックで作業していた場合
ブックを開いた状態で，「名前を付けて保存」を選択し，ファイルの種類を「Excelアドイン (.xlam)」にして保存するだけでよいです．

::: note warn
1つ前のノートの通り，ファイルの種類を変えるとフォルダが移動するので注意してください．
:::

[^saveDir]: OneDriveやGoogleDriveなど，クラウドのフォルダだとうまく動作しないことがあります．そのため，アドインファイルはローカルのフォルダ(Cドライブなど)に保存することをお勧めします．
---

### ここまででうまくできているか確認
アドインファイルを用意出来たら動作確認のため，一度ブックを閉じ，再度開きます．

:::note info
既に名前を付けて保存していても「変更内容を保存しますか？」と確認されることがありますが，気にせず(保存せず)閉じて問題ありません．
:::

:::note info
アドインを開いたときにセキュリティに関する警告が出ることがありますが，自分で作ったものなので(このページで書いていないようなよほどの変なことをしていなければ)「マクロを有効にする」を押して問題ありません．
![セキュリティ通知の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/a69bc393-25cd-9f75-64d7-0251d538ca9a.png)
:::

シートが表示されず，Excelのウィンドウが開いたらここまでは問題ありません．

ここからファイル自体を変更するのでいちどウィンドウは閉じておきましょう．

## アドインを"開く"
ここからリボンの準備を行います．

### ファイル名の変更
用意したアドインファイル(Book1.xlam とします)の拡張子を(警告は無視して)zipに変更します．
こんな感じ→　![名前を変更したBook1.xlam](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/ec309445-5467-d539-6b9d-2507db043400.png)

:::note info
もし，拡張子が表示されていない場合にはエクスプローラーの「表示」＞「ファイル名拡張子」などから拡張子を表示させてください．
:::

### ZIPファイルの展開
Book1.zipを適当な場所に展開(解凍)しておきましょう．
中身にはフォルダ3つとファイル1つが入っています．

![Book1.zipの中身](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/203a462f-65cb-d8ec-4646-847e8fcdfa29.png) 
(↑展開されてできたBook1フォルダの中身)

## 内部ファイルを書き換え
具体的に書き換える必要があるのは2か所です．
* `_rels`内の`.rels`
* アドイン用フォルダ`myaddin`内の`customUI.xml`(←フォルダもファイルも新しく作る)

このうち，`.rels`はアドインを初めて用意するときだけ書き換える必要があるものです．
また，アドインフォルダ名`myaddin`はある程度自由に決定できます(`mysoshake`や`abcdefg`など)．
(既存のフォルダと同じ名前だとその中に`customUI.xml`を作ることになるのでやめたほうがいいです)

### .relsの書き換え
`.rels`ファイルは右クリックしてメモ帳で開きましょう．
最初に開くと改行が入っておらず読みにくいですが，下のような内容だと思います．
```xml:.rels
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
</Relationships>
```
一番下の`</Relationships>`の真上の行に以下のコードを追加します．
```xml:
<Relationship
    Id="rIdMysoShake" 
    Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" 
    Target="/mysoshake/customUI.xml" 
/>
```

:::note info
Idは英数字なら自由に決めて問題ありませんが，1文字目が数字だとうまく動かないかもしれません
:::

:::note warn
Targetのフォルダ名(上では`mysoshake`)は後で作るフォルダ名と同じでないといけません．覚えておきましょう．
:::

↓こんな感じになります(改行の代わりにスペースを入れても動作します[^xmlnotion])．
```xml:.rels
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
<Relationship Id="rIdMysoShake" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="/mysoshake/customUI.xml" />
</Relationships>
```

[^xmlnotion]:スペースも改行も区切り文字として処理されるからだと思いますが筆者は理解できていません． XML講座ではないのでゆるしてください．

### customUI.xml の作成

まずはBook1フォルダに戻り，そこに新しく(先ほど決めた名前の)フォルダを作ります．
![カスタムUI用のフォルダ作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/84794804-107d-88ba-cd07-4437873fd995.png)

そのなかに，新しくテキストファイルを作り，名前と拡張子を変更して`customUI.xml`とします．
![新しい テキストドキュメント.txtを作成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/56a5c742-296a-3e9c-e5d6-f3ce0bf11040.png)　→　![customUI.xmlに変更](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/c1beca61-b030-cc4d-efd6-5fecf1379eb8.png)
これもまたメモ帳で開きそのなかにリボンの設定を書いていけばよいです．

#### ホームタブを消すcustomUI.xml
ここでは試しに「ホーム」タブを非表示にするように設定します．
```xml:customUI.xml
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
	<tab idMso="TabHome" visible="false" />
</tabs>
</ribbon>
</customUI>
```
入力が出来たら`.rels`や`customUI.xml`は保存して閉じておきます．

## アドインを"閉じる"
ここからファイルたちをxlamファイルに戻します．

### ファイルたちを圧縮してzipファイルにする
Book1フォルダのすべてのファイルを選んで圧縮しましょう．
![ファイルを圧縮](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/4a5266c9-9b93-3be0-494f-1376d06381e6.png)
(ZIPファイルはデスクトップに出来ることがあります)

:::note warn
圧縮するとき， **Book1フォルダを圧縮するとうまく動作しません** ．
かならず複数選択した状態で圧縮するようにしてください．
:::

### アドインファイルに変換する
圧縮が出来たら，拡張子をxlamに戻します．
![ZIPになったファイルたち](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/8eeda563-fc68-13d2-e5d4-42037a911b94.png)　→　![アドインファイルに変換した後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/8b134cfc-a2a2-a9fe-55ef-f848f7aa3cc0.png)

## 起動テスト
ここまでうまくできていれば，起動した際に「ホーム」タブが消えるはずです．
![セキュリティ通知があるときはホームタブはある](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/79bcdcf4-c3b6-06fc-d1df-36f1326e24b4.png)
↓マクロを有効にするとタブがなくなります
![ホームが消えた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/74e944e4-bab7-e91e-618e-73afddc3f31b.png)

:::note info
**すべての** Excelファイルを閉じてから開きなおせばタブは元に戻ります．
:::

# 本題
ここからは，リボンにタブやボタン，チェックボックスを追加してVBAマクロと連携します．

## customUI.xmlで独自のタブを追加する
次のような記述で何もないタブを追加できます．
```xml
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
	<tab id="TabMysoShake" label="独自に作られたタブ">
	</tab>
</tabs>
</ribbon>
</customUI>
```
入力が終わったら保存して閉じ，先ほどのように圧縮してアドインファイルに変換しましょう．
起動してみるとしたの用にタブが追加されます．
![空のタブ追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/ce086f8e-1144-84f5-f01b-1743d47054f6.png)

:::note info
タブのidは(もともとあるタブや自分が追加したタブなど)他のタブと被るとうまく動作しません．ユニークな名前にしておきましょう．
:::
タブは何も指定しない場合は一番後ろに追加されます．例えば「ホームの後ろに独自タブを配置したい」というときは
```xml
<tab id="TabMysoShake" label="独自に作られたタブ" insertAfterMso="TabHome">
```
というように`insertAfterMso="タブ名"`と書けばよいです．

:::note info
既存のタブの名前は[公式のドキュメント](https://msopenspecs.azureedge.net/files/MS-CUSTOMUI/%5bMS-CUSTOMUI%5d.pdf) (直接リンク)にあります．
:::
上のノートで紹介しているドキュメントを見ればボタンの追加方法やマクロとの連携方法がすべて書いてあります．
いくつかの例を紹介しておきます．

## タブにボタンを追加する
何の機能もないボタンを追加してみましょう．
```xml:customUI.xml
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
	<tab id="TabMysoShake" label="独自に作られたタブ" insertAfterMso="TabHome">
	<button id="mysoButton" label="独自のボタン"/>
	</tab>
</tabs>
</ribbon>
</customUI>
```
タブにグループが作られ，そこにボタンが配置されます．
![無機能のボタンを追加](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/fa6aed7e-a797-7c15-fe1b-36cec8dfea3d.png)

:::note warn
ボタンなどのリボンに配置されるものは，何かのグループに分類しなければなりません(見た目が崩れないように)．そのため，`<tab></tab>`の中に直接ボタンを追加しようとしてもエラーとなり， **アドインファイルに変換してもタブが追加されず，何も起こりません**． **customUIではミスがあっても警告などは出ないので覚えておきましょう** ．
:::

### ボタンにマクロを結びつける
今はボタンをクリックしても何も起きません．
そのため，customUI.xml内でどのマクロを呼ぶのかを指定しなければなりません．
まずは呼び出されるマクロを作りましょう．
#### OnActionを作る
**「開発」＞「VisualBasic」** を開いて，新しい「標準モジュール」を作りましょう．
![標準モジュール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/b5f14760-bcbe-1def-fff3-364393189024.png)

カスタムUIから呼ばれる場合，プロシージャは次の形式で書きます．
```vb:好きなモジュール
Public Sub MysoOnAction(control As IRibbonControl) 
    '何かの処理 ↓例えば
    If control.Id = "mysoButton" Then
        Call MsgBox("mysoButtonが押されました")
    End If
End Sub
```
このようにしてVBEを上書き保存します．
![打ち込んだ例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/89f8f150-b7d5-b90a-42ac-a7fc15193544.png)

:::note info
値が入るテキストボックスやチェックボックス，またはコールバック(マクロ側でcustomUIの中身を変化させる方法)を使うときは引数が増えることはありますが，通常は1つだけ引数をとります．
:::

ここで，上書き保存が終了したらExcelを終了し，再び「zipに変換→展開」という作業を行いましょう．

:::note info
これをしないで先ほどのファイルを書き換えていると今作ったVBAのソースも消えてしまいます．
:::

#### customUI.xmlでOnActionを呼ぶように設定する
次にcustomUI.xml側の設定です．ボタンの部分にOnActionの設定が増えています．
```xml:customUI.xml
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon>
<tabs>
	<tab id="TabMysoShake" label="独自に作られたタブ" insertAfterMso="TabHome">
		<group id="mysoGroup" label="独自グループ"> 
			<button id="mysoButton" label="独自のボタン" onAction="MysoOnAction"/>
		</group> 
	</tab>
</tabs>
</ribbon>
</customUI>
```

#### 動作チェック
これで再度アドインファイルに変換して起動．動作チェックをすると次のようになります．
![ボタンを押した動作](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/590223dc-75db-af46-f9b6-7e2de0566230.png)

# まとめ
以上のようにしていくことで次々とマクロを登録できます．
コールバックやそのほかの機能(msoImageやkeytipなど)も使いこなせるととても便利になるようですのでぜひ活用していきましょう．

<b>(2024年10月18日)</b>ちょっとした追記
今回はExcelで追加をしましたが，Word(マクロ有効文書 docm)などでも拡張子をzipにかえてあげると同じように処理ができるみたいです(未確認)．

# 参考になるサイト
1. [[MS-CUSTOMUI]: Custom UI XML Markup Specification](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-customui/31f152d6-2a5d-4b50-a867-9dbc6d01aa43)
1. [3.4.1.3 CustomUI Part](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/2d3ee2da-8f77-4b08-bc2b-651e568af3ab)
1. [IRibbonControl オブジェクト (Office)](https://learn.microsoft.com/ja-jp/office/vba/api/office.iribboncontrol)
1. [Excel のリボンUIを業務アプリとして使う](https://qiita.com/tomochan154/items/3614b6f3ebc9ef947719)
1. [Excel VBA 第2回 リボンとアドイン作成](https://qiita.com/Mount/items/36c2b0d3af3654ab28d7)