2019年に書いた記事を最新環境でより分かりやすく書いてみることにした。過去記事の全3回分は以下の通りで、ちょっと分かりずらかったというのもあるし、肝心の部分が伏せられていたというのがあるので、この記事を見ればすぐできちゃうという内容にブラッシュアップした。
Teigha改めODAでDWGをDXFに変換するプログラムをつくってみよう!【Part.1】
Teigha改めODAでDWGをDXFに変換するプログラムをつくってみよう!【Part.2】
Teigha改めODAでDWGをDXFに変換するプログラムをつくってみよう!【Part.3】
【開発環境】
Visual Studio Community 2022
※C++ によるデスクトップ開発で、x64用のVisual C++ MFC。
【ODA(Teigha改め)モジュール】
バージョンは2023.10.0.0 ※2022/12/18時点の最新
KernelとDrawingを利用し、それぞれのdll Release版とDebug版が必要となる。
【フォルダ構成】
odaproject ※任意のフォルダ
├─SampleExe ※これから作るアプリケーション
└─oda23.11.0.0 ※ODAモジュールを配置
【手順1:ODAモジュールのダウンロード】
・Drawings_vc17_amd64dll_23.11.zip
・Drawings_vc17_amd64dlldbg_23.11.zip
・Kernel_vc17_amd64dll_23.11.zip
・Kernel_vc17_amd64dlldbg_23.11.zip
「oda23.11.0.0」フォルダ内で解凍。
zip内にはヘッダーやソースコードなどが重複して入っているので解凍時に上書きしてよい。
【手順2.ODAアクティベーションファイルの入手】
ODA Products Activationにアクセスして、自社用のアクティベーションファイルを入手する。Choose release⇒2019.x、Choose api language⇒C++として、Generateボタンを押すと、ファイルOdActivationInfoがダウンロードできる。どこに配置するかは、後で触れる。
【手順3.VisualStudioでMFCプロジェクトを作成】
新しいプロジェクトの作成から、MFCアプリを指定。
アプリケーションの種類:ダイアログベース
MFCの使用:共有DLLでMFCを使用する
その他指定は、なるべくシンプルなものとする。
【手順4.ダイアログテンプレート作成】
「…」ボタンで変換元のdwgファイルを選んで変換実行とすれば、同一パス内にdxfファイルを作るという画面設計。
【手順5.クラスウイザードでコントロール変数など追加】
以下、CSampleExeDlgのメンバー関数およびメンバー変数。追加した結果こうなるというもので、クラスウイザードの詳細操作は省略。関数内のコーディングは重要ではないので、最後に記載するプロジェクト一式をダウンロードして参照されたし。
afx_msg void OnClickedButton1(); afx_msg void OnClickedButton2(); CEdit m_edtFile;
【手順6.64bitプロジェクトになっていることを変更】
以前のVisualStudioでは、デフォルトのプラットフォームがx86であったのに対して、2022ではすでにx64になっていた。x86つまり32bit版アプリの需要はほぼないので妥当な判断。
【手順7.ExServicesをプロジェクトに追加】
ここからがODA固有の処理。C++はアンマネージドコードなので、いろいろと難しいことをしなければいけないという一例。ここでは何も考えずに以下の処理をやる。
プロジェクト内にExServicesという新しいフォルダを作って、後述する14個のファイルを追加する。ソリューションエクスプローラのSampleExeを右クリックして追加⇒新しいフィルターとしてExServicesを作って、14個のファイルを既存項目として追加する。14個のファイルの出元や特徴は以下の通りで、oda23.11.0.0フォルダ内からコピペする。
Kernel:Kernel\Extensions\ExServices
Drawing:Drawing\Extensions\ExServices
『Kernelにあるのをそのまま利用するもの』
・ExGiRasterImage.cpp
・ExGiRasterImage.h
・ExPrintConsole.cpp
・ExPrintConsole.h
・ExSystemServices.cpp ※ただしincludeしているStdAfx.hはpch.hに変更する
・ExSystemServices.h
・OdFileBuf.cpp ※ただしincludeしているStdAfx.hはpch.hに変更する
・OdFileBuf.h
・RxSystemServicesImpl.h
・ExTtfFileNameByDescriptor.h ※使えないはずのGetVersionExが気になるところだが。。
・RxSystemServicesImpl.cpp ※ただしincludeしているStdAfx.hはpch.hに変更する
『Drawingにあるのをそのまま利用するもの』
・ExHostAppServices.cpp ※ただしincludeしているStdAfx.hはpch.hに変更する
・ExHostAppServices.h
『手順2でダウンロードしたアクティベーションファイル』
・OdActivationInfo
【手順8.ODAへの参照設定など】※Debug版とRelease版で同じ設定は説明なし
1)プロジェクトのプロパティで各種設定を変更
『全般⇒出力ディレクトリ』
$(SolutionDir)$(Platform)\$(Configuration)\となっているので、その後に「bin\」を追加。ビルドした結果のexeとODA用バイナリをbinフォルダに整理して入れるための対処。
『C/C++⇒全般⇒追加のインクルードディレクトリ』
../oda23.11.0.0/Kernel/Include
../oda23.11.0.0/KernelBase/Include
../oda23.11.0.0/Drawing/Include
ExServices
./
『C/C++⇒プリプロセッサ⇒プリプロセッサの定義』
_TOOLKIT_IN_DLL_
『[C/C++⇒詳細設定⇒指定の警告を無効にする』
4819
『リンカー⇒全般⇒追加のライブラリディレクトリ』
../oda23.11.0.0/lib/vc17_amd64dlldbg ※Debug版
../oda23.11.0.0/lib/vc17_amd64dll ※Release版
『リンカー⇒入力⇒追加の依存ファイル』
TD_Alloc.lib
TD_Db.lib
TD_Ge.lib
TD_Root.lib
TD_DbRoot.lib
TD_DbCore.lib
TD_key.lib
2)特定cppのプリコンパイル済みヘッダーを変更
『C/C++⇒プリコンパイル済みヘッダー』
「プリコンパイル済みヘッダーを使用しない」にする。
・ExGiRasterImage.cpp
・ExPrintConsole.cpp
以上の設定を終えてビルドすれば、エラーなくビルドができる。でも、実行しようとするとODAバイナリがないからということでエラーが出ちゃう。
【手順9.ODAバイナリのコピー】
odaの以下フォルダから、プロジェクトのbinフォルダにバイナリをコピーする。
Debug版:oda23.11.0.0\exe\vc17_amd64dlldbg⇒SampleExe\x64\Debug\bin
Release版:oda23.11.0.0\exe\vc17_amd64dll⇒SampleExe\x64\Release\bin
以下ファイルが対象で、自分で書くコードによっては増やす必要あり。
・ACCAMERA_23.11_17.tx
・AcMPolygonObj15_23.11_17.tx
・ATEXT_23.11_17.tx
・ISM_23.11_17.tx
・RasterProcessor_23.11_17.tx
・RecomputeDimBlock_23.11_17.tx
・RText_23.11_17.tx
・SCENEOE_23.11_17.tx
・TD_Alloc_23.11_17.dll
・TD_Db_23.11_17.dll
・TD_DbCore_23.11_17.dll
・TD_DbEntities_23.11_17.tx
・TD_DbIO_23.11_17.tx
・TD_DbRoot_23.11_17.dll
・TD_Ge_23.11_17.dll
・TD_Gi_23.11_17.dll
・TD_Root_23.11_17.dll
・TD_SpatialIndex_23.11_17.dll
・WinGDI_23.11_17.txv
・WipeOut_23.11_17.tx
これでやっとデバッグ実行ができるようになる。SampleExe.exeを実行して終了するだけでメモリーリークが出ているのは、実装が中途半端だからなので次のステップで解消する。
【手順10.DWGをDXFに変換するコードを挿入】
1)ODAベースクラス追加
以下ファイルをプロジェクトフォルダにコピーして、ソースファイルとヘッダーファイルに既存項目として追加する。
OdaServices.cpp、OdaServices.h
ODAのベースクラスで、ExSystemServicesとExHostAppServicesを継承した独自クラスを作るということ。ODAサンプルプロジェクトのOdaMfcAppのOdaMfcApp.hなどをもとに作成したものであり、これがODAのキモになる。dwgを開こうとした際にフォントファイルを参照するために、どこのフォルダをみにいけばいいか(findFile)や、暗号化されたファイルを開く際のパスワード入力画面の実装などが可能。このファイルの中身が知りたい場合は、末尾にアップしたzipファイルをダウンロードしてほしい。
2)SampleExeDlg.h修正
『ヘッダー呼び出しに以下2行を追加』
#include "OdaCommon.h" #include "OdaServices.h"
『デストラクタの宣言追加』
~CSampleExeDlg();
『クラスのprivate変数に追加』
OdRxObjectImpl<COdaServices> m_svcs;
3)SampleExeDlg.cpp修正
『ヘッダー呼び出しに以下1行を追加』
#include “OdFileBuf.h”
『変換実行部呼び出し箇所をコメントアウト』
int stat = ExecDwg2Dxf(&m_svcs, strSrc, strDst, emsg);
『OnInitDialogに処理追加』
// ODA初期化 try { odInitialize(&m_svcs); } catch (OdError& e) { OdString err = m_svcs.getErrorDescription(e.code()); AfxMessageBox(_T("ODAエラー:") + err); return FALSE; }
『デストラクタとして処理追加』
CSampleExeDlg::~CSampleExeDlg() { odUninitialize(); }
『変換実行部の関数追加』
OnClickedButton2関数の上に、以下のスタティック関数を追加する。
static bool ExecDwg2Dxf(OdRxObjectImpl<COdaServices>* pSvcs, LPCTSTR pSrc, LPCTSTR pDst, CString& msg) { int stat = false; OdDbDatabasePtr pDb = pSvcs->readFile(pSrc, false, false, Oda::kShareDenyNo); if (!pDb.isNull()) { OdWrFileBuf fb(pDst); OdDb::SaveType st = OdDb::kDxf; pDb->writeFile(&fb, st, pDb->originalFileVersion(), true); stat = true; } return stat; }
以上で実装が完了なので、ビルドしてデバッグ実行してみる。そのままSampleExe.exeを終了させてもメモリーリークは出ないはずが...16 bytes分出ている。一説にはリンクするlibの指定順というのもあるが実態は不明。ODAのバグっぽいが16バイトだったら許せる。
【手順11.DWGをDXFに変換してみる】
デバッグ実行したSampleExe.exeから「…」ボタンを押して適当なdwgファイルを選択。変換実行とすれば、dwgと同じ場所にdxfファイルができる。
最後に、上記手順によって作成したプロジェクト一式をアップしておく。ただし、ODAは有料のライブラリなので、勝手にここで公開できないものもある。詳しくはzip解凍後のreadme.txtで参照されたし。
odaproject