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のタイプライブラリの取り込みを行う事で取得できます。