DelphiでAutoCAD 2012バージョン

いよいよAutoCAD 2012対応を開始しました。
コマンド登録用のARXもAutoCAD2012対応処理を行いましたのでその情報をメモ。

基本的には、charで宣言していたものをACHARに変更、std::stringをstd::basic_stringに変更。
文字列リテラルを、_TEXTマクロで囲む。
後は、AutoCADのCOMオブジェクトを取得する処理が変わってます。

以上の変更で問題無く移行出来ました。
delphi側(2009以降)の関数定義は前回のものがそのまま使用できます。

//コマンド名と関数ポインタのマップ
typedef std::map<std::basic_string<ACHAR>, CMDFUNC> COMMANDS_MAP;
//文字列リスト
typedef std::vector<std::basic_string<ACHAR> > STRINGARRAY;
//登録コマンドと関数ポインタのペアを保持する
COMMANDS_MAP cmds;
//登録グループのリスト
STRINGARRAY groups;

bool GetAcadApp(AutoCAD::IAcadApplication **pAcadApp)
{
	HRESULT hr = NOERROR;
        // LPDISPATCH pDisp = acedGetAcadWinApp()->GetIDispatch(TRUE);
	LPDISPATCH pDisp = acedGetIDispatch(TRUE);
	hr = pDisp->QueryInterface(AutoCAD::IID_IAcadApplication, (void**)pAcadApp);
	pDisp->Release();

	return SUCCEEDED(hr);
}

bool EnumCommands(HINSTANCE hPin, const ACHAR* pName)
{
	bool bContinue = true;
	REGSETUP pRegSetup;
	REGINIT pRegInit;

	pRegInit = (REGINIT)::GetProcAddress(hPin, "RegInit");
	if (pRegInit)
		pRegInit();

	pRegSetup = (REGSETUP)::GetProcAddress(hPin, "RegSetup");
	if(!pRegSetup)
		return false;

	pRegSetup(adsw_acadMainWnd());

	return true;
}

bool __stdcall CommandRegister(const ACHAR* Group, const ACHAR* Cmd, const int CmdFlags, CMDFUNC Func)
{
	size_t length;
	LPTSTR pBuffer;
	bool result = false;

	// コマンド登録時 グループ・コマンド名を大文字化して登録する
	::StringCbLength(Group, 50, &length);
	pBuffer = new ACHAR[length+1];
	::StringCbCopy(pBuffer, 50, Group);
	::CharUpper(pBuffer);

	if(std::find(groups.begin(), groups.end(), pBuffer) == groups.end())
		groups.push_back(pBuffer);
	delete [] pBuffer;

	::StringCbLength(Cmd, 50, &length);
	pBuffer = new ACHAR[length+1];
	::StringCbCopy(pBuffer, 50, Cmd);
	::CharUpper(pBuffer);

	if(cmds.find(pBuffer) == cmds.end())
	{
		acedRegCmds->addCommand(Group, pBuffer, pBuffer, CmdFlags, CommandTemplate);
		cmds[pBuffer] = Func;
		result = true;
	}else{
		acutPrintf(u_ng_l::LoadString(IDS_E_CMDCONFLICT, _hdllInstance).c_str(), pBuffer);
	}
	delete [] pBuffer;
	return result;
}

void CommandTemplate()
{
	// 実行されたコマンド名を取得する
	struct resbuf rb;
	acedGetVar(_TEXT("CMDNAMES"), &rb);
	std::basic_string<ACHAR>  cmd = rb.resval.rstring;
	free(rb.resval.rstring);

	AutoCAD::IAcadApplication *pApp;
	if(GetAcadApp(&pApp))
	{
		// 実行コマンドを UndoMark で挟む
		AcTransaction *pTrans = actrTransactionManager->startTransaction();

		cmds[cmd](pApp);
		pApp->Release();

		if(pTrans != NULL)
			actrTransactionManager->endTransaction();
	}
}

void EnumPlugins(void)
{
	std::basic_string<ACHAR>path = u_ng_l::GetApplicationPath(_hdllInstance);
	WIN32_FIND_DATA fd;
	AString searchpath = path + _TEXT("\\*.dll");

	HANDLE hFind = ::FindFirstFile(searchpath.c_str(), &fd);
	HINSTANCE hDll = NULL;
	if(hFind != INVALID_HANDLE_VALUE)
	{
		do{
			searchpath = path + _TEXT("\\") + fd.cFileName;
			hDll = ::LoadLibrary(searchpath.c_str());
			if(EnumCommands(hDll, fd.cFileName))
				hDlls.push_back(hDll);
			else
			{
				// EnumCommands に失敗した場合は、解放する
				::FreeLibrary(hDll);
			}
		}while(0 != ::FindNextFile(hFind, &fd));
		::FindClose(hFind);
	}
}

void ReleasePlugins(void)
{
	// dax の解放
	for(STRINGARRAY::iterator i=groups.begin(); i!=groups.end(); ++i)
		acedRegCmds->removeGroup((*i).c_str());

	groups.clear();
	cmds.clear();

	REGINIT pRegFinal;
	for(DLLHANDLES::iterator i=hDlls.begin(); i!=hDlls.end(); ++i)
	{
		pRegFinal = (REGINIT)::GetProcAddress(*i, "RegFinal");
		if (pRegFinal)
			pRegFinal();
		::FreeLibrary(*i);
	}

	hDlls.clear();
}

2011/05/26 追記
AutoCADのインターフェースの事を書くのを忘れていました。AutoCADのインターフェースについては、ここから、該当のObjectARXをダウンロードして展開すると、中にAutoCAD2012だとacax18ENU.tlbてファイルが入ってますのでこれを、Delphiのタイプライブラリの取り込みを行う事で取得できます。