InDesign SDKでスクリプトやUXPでは実現できない実務的なプラグインを開発してみた(未解決のプラグイン情報を削除するプラグイン)

前回、何とかInDesign SDK プラグインのWindows開発環境が整ったので、
スクリプトやUXPでは実現できない、実務的なプラグインを開発してみる。
(未解決のプラグイン情報を削除するプラグイン)
※ほぼ全文公開するので興味のあるMacintoshユーザの方、Xcodeでビルドしてみませんか?

空のプロジェクト作成

InDesign SDKに同梱されている「dolly」を使用
JAVAが必要。インストールする

前回のInDesign SDKフォルダ内の
「devtools」→「dolly」内の「dolly.jar」を実行!
(例:C:\AdobeSDK\plugin_sdk_20.0.0.95\devtools\dolly\dolly.jar)

まず名前を決める。
Prefix IDはAdobe(wwds@adobe.com)にメールで申請して取得する。必要事項は下記参照。
Adobe ID:
Company / Developer Name:
Email Address:
Plugin Name:
Plugin Description:
Distribution Method:


つぎにMacintoshのフォルダ設定。一応設定した。


次にWindowsのフォルダ設定
緑マーカーのSourceとHeaderファイルの保存先は2026以降のバージョンでもビルドしたい為に「C:\AdobeSDK\shockPlugin」内に収めるように変更した。
projectファイルを2026のSDKにコピーすれば同じソースでビルドできる。
黄色マーカーのフォルダ名が最終的にInDesignのプラグインフォルダにインストールするフォルダ名になるため「SDK」から「shockPlugin」に変更。もし違うプラグインを開発したらこのフォルダに全部ぶち込む形。
これで空のプロジェクト作成完了

空のプロジェクトslnに追加

「build\win\prj\」にある「SDKsmaple.sln」を開く。
(例:C:\AdobeSDK\plugin_sdk_20.0.0.95\build\win\prj\SDKsmaple.sln)

そんで右クリックから「追加」→「既存プロジェクトを追加」を実行し、
同一フォルダ内にある、先ほど作成した空のプロジェクトの「missingPluginDataDelete.vcxproj」を選択する。

そんで、前回と同じく
ソリューション「SampleSDK」を右クリックして「ソリューションの再ターゲット」を実行しWindows SDKバージョンを「10.0.19041.0」にする
プロジェクトのプロパティから「全般」→「ターゲット名」→「$(ProjectName).sdk」を「$(ProjectName)」にする
を実行

次期バージョンでビルドするには
同一フォルダ内にある、先ほど作成した空のプロジェクトの「missingPluginDataDelete.vcxproj」や「missingPluginDataDelete.vcxproj.filters」など
「missingPluginDataDelete」+「なんかの拡張子」のファイルを全て次期バージョンの「prj」フォルダにコピーして上記の追加をする。
(例CC2026:C:\AdobeSDK\plugin_sdk_21.0.0.192\build\win\prj\)

メニューが作成できない問題

理解力が足りず、どれだけ頑張ってもメニュー「プラグイン」に新規のメニューを作成することができませんでした。
「missingPluginDataDeleteID.h」をいじれば出来るみたいですが分かりません。頭痛いです。
困ったので、デフォルトにあるAboutメニューを転用することを思いつく。

//Header FilesのmissingPluginDataDeleteID.h内

//#define kmissingPluginDataDeleteAboutMenuPath	kSDKDefStandardAboutMenuPath kmissingPluginDataDeleteCompanyKey
//下記に変更する
#define kmissingPluginDataDeleteAboutMenuPath	kSDKDefPlugInsStandardMenuPath kmissingPluginDataDeletePluginsMenuKey

//ついでにPrefixの値をカブらないようにしておく
DECLARE_PMID(kPlugInIDSpace, kmissingPluginDataDeletePluginID, kmissingPluginDataDeletePrefix + 0)
DECLARE_PMID(kClassIDSpace, kmissingPluginDataDeleteActionComponentBoss, kmissingPluginDataDeletePrefix + 1)//元々は0
DECLARE_PMID(kImplementationIDSpace, kmissingPluginDataDeleteActionComponentImpl, kmissingPluginDataDeletePrefix + 2)//元々は0
DECLARE_PMID(kActionIDSpace, kmissingPluginDataDeleteAboutActionID, kmissingPluginDataDeletePrefix + 3)//元々は0

メニューを移動させることに成功。

もう一層削除したかったが、どうしてもできず。今回は諦めることとする。

ついでにメニュー名も変更する。
ソースフォルダの方にある「missingPluginDataDelete_enUS.fr」と「missingPluginDataDelete_jaJP.fr」を
プロジェクトの「Resource Files」フォルダに追加して編集

//Resource FilessのmissingPluginDataDelete_jaJP.fr内

kmissingPluginDataDeleteAboutMenuKey,	"全ドキュメント対象",
kmissingPluginDataDeletePluginsMenuKey,	"環境にないプラグイン情報の削除",

//Resource FilessのmissingPluginDataDelete_jaJP.fr内

kmissingPluginDataDeleteAboutMenuKey,	"For all documents",
kmissingPluginDataDeletePluginsMenuKey,	"Delete plugin information that not",

いよいよInDesignを操作

つぎはAboutメニューを出している部分を探し、処理を書いていく。

//Source FilesのmissingPluginDataDeleteActionComponent.cpp内

void missingPluginDataDeleteActionComponent::DoAbout()
{
	CAlert::ModalAlert
	(
		kmissingPluginDataDeleteAboutBoxStringKey,	// Alert string
		kOKString, 					// OK button
		kNullString, 					// No second button
		kNullString, 					// No third button
		1,						// Set OK button to default
		CAlert::eInformationIcon			// Information icon.
	);
}

の部分みたい。とりあえず
変数kmissingPluginDataDeleteAboutBoxStringKeyを”new plugin start”に変更してみる。

成功

いろいろあって全文掲載

で、「docs\html\index.tml」と格闘してプラグインデータを削除することに成功しました。
Screenさんの「dMissingPluginInfo」さんと違うところは、
全ドキュメント対象にしたのと保存フラグを立てるところ。

void missingPluginDataDeleteActionComponent::DoAbout()
{
	PMString lastText;
	int32 docCount = 0;
	PMString signText = "-----------------------------------\nmissingPluginDataDelete 1.0.0\nWritten by shock tm\nhttps://adodtp.com/";
	do
	{
		InterfacePtr app(GetExecutionContextSession()->QueryApplication());
		if (!app) break;
		InterfacePtr docList(app->QueryDocumentList());
		if (!docList) break;
		docCount = docList->GetDocCount();
		if (docCount == 0)
		{
			lastText.Append("No documents.\n\n");
			lastText.Append(signText);
			break;
		}
		int32 allCount = 0;
		for (int32 i = 0; i < docCount; i++)
		{
			InterfacePtr doc(docList->GetNthDoc(i), UseDefaultIID());
			if (!doc) continue;
			PMString docName;
			doc->GetName(docName);
			InterfacePtr contentAccess(doc, UseDefaultIID());
			if (!contentAccess)
				continue;
			InterfacePtr contentMgr(contentAccess->QueryContentMgr());
			if (!contentMgr)
				continue;
			int32 missingCount = contentMgr->GetMissingPluginCount();
			if (missingCount > 0) {
				lastText.Append("[");
				lastText.Append(docName);
				lastText.Append("]\n");
				PMString num;
				num.AppendNumber(missingCount);
				lastText.Append(" delete pluguin -> ");
				lastText.Append(num);
				lastText.Append("\n");
				for (int32 n = missingCount - 1; n >= 0; n--)
				{
					IContentMgr::PluginInfo info = {};
					PluginID pid = contentMgr->GetNthMissingPlugin(n, &info);
					lastText.Append("  - ");
					lastText.Append(info.fPluginName);
					lastText.Append("\n");
					allCount = 1;
				}
			}
		}
		if (allCount == 0)
		{
			lastText = "No plugins to remove.\n\n";
			lastText.Append(signText);
			docCount = 0;
		}
		break;
	} while (false);
	if (docCount == 0)
	{
		CAlert::ModalAlert
		(
			lastText,
			kOKString,
			kNullString,
			kNullString,
			1,
			CAlert::eInformationIcon
		);
	}
	else {
		int32 alertInt = 0;
		lastText.Append("\nDelete OK?");
		alertInt = CAlert::ModalAlert
		(
			lastText,
			kYesString,
			kCancelString,
			kNullString,
			1,
			CAlert::eQuestionIcon
		);
		if (alertInt == 1) {
			do
			{
				InterfacePtr app(GetExecutionContextSession()->QueryApplication());
				if (!app) break;
				InterfacePtr docList(app->QueryDocumentList());
				if (!docList) break;
				docCount = docList->GetDocCount();
				if (docCount == 0)
				{
					break;
				}
				for (int32 i = 0; i < docCount; i++)
				{
					InterfacePtr doc(docList->GetNthDoc(i), UseDefaultIID());
					if (!doc) continue;
					InterfacePtr contentAccess(doc, UseDefaultIID());
					if (!contentAccess)
						continue;
					InterfacePtr contentMgr(contentAccess->QueryContentMgr());
					if (!contentMgr)
						continue;
					int32 missingCount = contentMgr->GetMissingPluginCount();
					if (missingCount > 0) {
						for (int32 n = missingCount - 1; n >= 0; n--)
						{
							IContentMgr::PluginInfo info = {};
							PluginID pid = contentMgr->GetNthMissingPlugin(n, &info);
							contentMgr->RemovePlugin(pid);
						}
						InterfacePtr layerList(doc, UseDefaultIID());
						if (!layerList)
							return;
						InterfacePtr layer(layerList->QueryLayer(0));
						bool16 visible = layer->IsVisible();
						layer->SetVisible(!visible);
						layer->SetVisible(visible);
					}
				}
				break;
			} while (false);
			CAlert::ModalAlert
			(
				"success!\n\n" + signText,
				kOKString,
				kNullString,
				kNullString,
				1,
				CAlert::eInformationIcon
			);
		}
	}
}

無駄な部分もあるかと思うがとりあえず不具合もなく動いているのでこれでヨシとする。

ビルドしたWindows専用の2025版と2026版はgithubに公開しています。

スポンサーリンク

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です