InDesign Plugin SDK: ICommandInterceptorの実装方法

コマンドの実行に割り込めるという便利な仕組みの ICommandInterceptor だが、なんにしても情報が少なすぎる。sdksamples にも何の言及もないし、ネット上にもまともな情報がほとんどない…。

結論から言うと、StartupShutdownService と一緒に実装するとよい。

ClassDescriptionTableに以下のような感じで記述。

Class
{
	kXXXXXXStartupShutdownServiceBoss,
	kInvalidClass,
	{
		IID_ISTARTUPSHUTDOWN,  kXXXXXXStartupShutdownServiceImpl,
		IID_IK2SERVICEPROVIDER,  kCMainThreadStartupShutdownProviderImpl,
		IID_ICOMMANDINTERCEPTOR, kXXXXXXCommandInterceptorImpl, 
	}
},


CommandInterceptor自体は以下のような感じで記述。
自分の目的のコマンド以外は無視して kCmdNotHandled を返す。

class XXXXXXCommandInterceptor : public CPMUnknown<ICommandInterceptor>
{
public:
	XXXXXXCommandInterceptor(IPMUnknown* boss) : CPMUnknown<ICommandInterceptor>(boss) {}
	virtual ~XXXXXXCommandInterceptor() {}

	virtual InterceptResult InterceptProcessCommand(ICommand *cmd);
	virtual InterceptResult InterceptScheduleCommand(ICommand *cmd) { return kCmdNotHandled; }
	
	virtual InterceptResult InterceptExecuteDynamic(ICommand * cmd) { return kCmdNotHandled; }

	virtual void InstallSelf() {}
	virtual void DeinstallSelf() {}

	virtual InterceptResult InterceptExecuteImmediate(ICommand * cmd) { return kCmdNotHandled; }
};

CREATE_PMINTERFACE(XXXXXXCommandInterceptor, kXXXXXXCommandInterceptorImpl)

ICommandInterceptor::InterceptResult XXXXXXCommandInterceptor::InterceptProcessCommand(ICommand *cmd)
{
	switch (cmd->GetCreatorID()) {
		case kQuitCmdBoss:
		case kCloseAllAndQuitCmdBoss:
			// do something
			break;
	}

	return kCmdNotHandled;
}


StartupShutdownServiceのほうは以下のような感じで記述。
ここで CommandInterceptor のインストール・アンインストールをしている。
(アンインストールが正常に動いているかは不明。そもそもアンインストールは不要かも)

class XXXXXXStartupShutdownService : public CPMUnknown<IStartupShutdownService>
{
public:
	XXXXXXStartupShutdownService(IPMUnknown* boss) : CPMUnknown<IStartupShutdownService>(boss) {}
	virtual ~XXXXXXStartupShutdownService() {}

	virtual void Startup();
	virtual void Shutdown();
};

CREATE_PMINTERFACE(XXXXXXStartupShutdownService, kXXXXXXStartupShutdownServiceImpl)

void XXXXXXStartupShutdownService::Startup()
{
	InterfacePtr<ICommandInterceptor> commandInterceptor(this, UseDefaultIID());
	if (commandInterceptor) {
	InterfacePtr<ICommandProcessor> commandProcessor(GetExecutionContextSession()->QueryCommandProcessor());
		if (commandProcessor) {
			commandProcessor->InstallInterceptor(commandInterceptor);
		}
	}
}

void XXXXXXStartupShutdownService::Shutdown()
{
	InterfacePtr<ICommandInterceptor> commandInterceptor(this, UseDefaultIID());
	if (commandInterceptor) {
	InterfacePtr<ICommandProcessor> commandProcessor(GetExecutionContextSession()->QueryCommandProcessor());
		if (commandProcessor) {
			commandProcessor->DeinstallInterceptor(commandInterceptor);
		}
	}
}