対象製品: IJCAD 2020 以降 (STDグレード以上)
IJCAD 2019 以前はこちら
次の手順で、ARX を使って同心円を描くで紹介したプログラムをゼロから作成します。
1. マイクロソフトのホームページから、Visual Studio 2017 Community Edition をダウンロードします。
2. ハードディスクの容量が十分ある場合は、すべてインストールすることを推奨します。
3. Visual Studio 2017 を起動します。
4. [ファイル(F)]メニューの[新規作成(N)] ► [プロジェクト(P)...]を選択します。
5. [Visual C++]カテゴリから、[MFC/ATL]を選び、[MFC ダイナミックリンク ライブラリ]を選択し、「名前」「場所」「ソリューション名」を指定して[OK]ボタンを押します。
※このサンプルでは「arxSample」という名前でアプリケーションを作成することにします。
6.「MFC DLL」の設定画面に進みます。[DLLの種類(T)]で[MFC 拡張 DLL]を選択します。
7.[OK]ボタンを押すとプロジェクトが自動生成されます。
プロパティシートの追加
プロジェクトにGRX SDK の基本的な設定が定義されているプロパティシートを追加します。
1. [表示(V)]メニューの[その他のウィンドウ(E)] ► [プロパティ マネージャ(N)]を選択します。
2. それぞれの構成で右クリックして、[既存のプロパティシートの追加(E)...]をクリックします。
3. C:\GRXSDK\inc\arx\smx_arx.props ファイルを追加します。
それぞれの構成で[ARX/ADS Settings]という項目が追加されます。
オプションの変更
いくつかのオプションを変更する必要があります。
1. [表示(V)]メニューの[ソリューション エクスプローラー(P)]を選択します。
2. [プロジェクト(P)]メニューの[プロパティ(P)]を選択します。
3. [構成(C):]で[すべての構成]を選択、[プラットフォーム(P):]で[すべてのプラットフォーム]を選択します。
4.[リンカー]の[入力]ページで、[モジュール定義ファイル]のリストボックスから[<親またはプロジェクトの規定値から継承>]を選択して、[適用]ボタンを押します。
モジュール定義ファイルは「.\モジュール名.def」から「$(GRXDIR)\inc\arx\RxExport.def」に変わります。
特別にEXPORTする関数があるときは、「モジュール名.def」を使います。「RxExport.def」に記された関数を先に指定してください。
5.[追加の依存ファイル]のリストボックスから[<編集>]を選び、[追加の依存ファイル]ダイアログで[grxport.lib]を追加します。
6.[OK]ボタンを押して変更を適用すると、[追加の依存ファイル]は[grxport.lib;%(AdditionalDepondencies)]に変わります。
7.[OK]ボタンを押してプロパティページを閉じます。
ソースプログラムの変更
ソースプログラムは次のように変更します。
[arxSample.def] と [targetver.h] は、プロジェクトから削除します。
arxSample.rc
[ソリューションエクスプローラー]から[arxSample]プロジェクトを展開します。
[リソースファイル]フォルダ内にある[arxSample.rc]を右クリックして[コードの表示(C)]を選択します。
[targetver.h] を削除したので、[targetver.h] が含まれる2行をコメントアウトします。
// Microsoft Visual C++ で生成されたリソース スクリプトです。
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE 2 リソースから生成されました。
//
#ifndef APSTUDIO_INVOKED
//#include "targetver.h"
#endif
#include "afxres.h"
#include "verrsrc.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#ifndef APSTUDIO_INVOKED\r\n"
//#include ""targetver.h""\r\n"
"#endif\r\n"
"#include ""afxres.h""\r\n"
"#include ""verrsrc.h""\r\n"
"\0"
END
(略)
stdafx.h
[targetver.h] をコメントアウトして、 _WIN32_WINNT マクロを 0x0601 (Windows 7)に設定します。
[arxHeaders.h] と [AC_DECLARE_EXTENSION_MODULE] をファイルの最後に追加します。
#pragma once
#ifdef _DEBUG
#undef _DEBUG // MFC,ARX はリリース ライブラリを使用するため無効にします
#define NODEBUG
#endif
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Windows ヘッダーから使用されていない部分を除外します。
#endif
//#include "targetver.h"
#define _WIN32_WINNT 0x0601 // Windows 7 以降
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 一部の CString コンストラクターは明示的です。
#include <afxwin.h> // MFC のコアおよび標準コンポーネント
#include <afxext.h> // MFC の拡張部分
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxole.h> // MFC OLE クラス
#include <afxodlgs.h> // MFC OLE ダイアログ クラス
#include <afxdisp.h> // MFC オートメーション クラス
#endif // _AFX_NO_OLE_SUPPORT
#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h> // MFC ODBC データベース クラス
#endif // _AFX_NO_DB_SUPPORT
#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h> // MFC DAO データベース クラス
#endif // _AFX_NO_DAO_SUPPORT
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h> // MFC の Internet Explorer 4 コモン コントロール サポート
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC の Windows コモン コントロール サポート
#endif // _AFX_NO_AFXCMN_SUPPORT
#include "arxHeaders.h"
#ifdef NODEBUG
#define _DEBUG // ユーザーのデバッグ用コードは有効です
#undef NODEBUG
#endif
AC_DECLARE_EXTENSION_MODULE(arxSampleDLL)
※Visual Studioのスケルトンでstdafx.hが生成されない問題について
Visual Studio 2017の最新版でGRXモジュールのスケルトンを生成した場合、プリコンパイル済みヘッダーのファイルが[stdafx.h]ではなく、[pch.h]と[framework.h]が作成されるケースがあります。
この場合、[stdafx.h]に対する変更を[framework.h]に対して修正することで解決します。
dllmain.cpp
GCAD.EXE のインスタンス ハンドルでアクティブなインスタンス ハンドルを初期化してから、
CAcExtensionModule::AttachInstance() を呼ぶことで、MFCの警告ダイアログを出さないようにできます。
// dllmain.cpp : DLL の初期化ルーチンを定義します。
//
#include "stdafx.h"
#include <afxwin.h>
#include <afxdllx.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
AC_IMPLEMENT_EXTENSION_MODULE(arxSampleDLL)
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
arxSampleDLL.AttachInstance(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
arxSampleDLL.DetachInstance();
}
return 1; // OK
}
arxSample.cpp
DEBUG_NEW マクロの定義をコメントアウトします。
ARX を使って同心円を描くプログラムの後に、プログラムの初期化、後処理のコードが必要です。
// arxSample.cpp : DLL の初期化ルーチンです。
//
#include "stdafx.h"
//#ifdef _DEBUG
//#define new DEBUG_NEW
//#endif
void circles()
{
int ret = RTNORM;
AcTransaction *pTrans = actrTransactionManager->startTransaction();
if (pTrans)
{
try
{
// パラメータを用意
ads_point ptres;
ret = ads_getpoint(NULL, _T("中心点: "), ptres);
if (ret != RTNORM)
throw Acad::eUserBreak;
double rad;
ret = ads_getdist(ptres, _T("半径: "), &rad);
if (ret != RTNORM)
throw Acad::eUserBreak;
AcGePoint3d center;
center.set(ptres[0], ptres[1], ptres[2]);
// ブロックテーブルを用意
Acad::ErrorStatus es;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb)
throw Acad::eNoDatabase;
AcDbObject* pObj;
// モデル空間ブロックレコードを用意
AcDbObjectId recId = acdbSymUtil()->blockModelSpaceId(pDb);
es = actrTransactionManager->getObject(pObj, recId, AcDb::kForWrite);
if (es != Acad::eOk)
throw es;
AcDbBlockTableRecord* pSpaceRecord = AcDbBlockTableRecord::cast(pObj);
pObj = 0;
// 1つ目の円を追加
AcDbCircle *pEnt1 = new AcDbCircle(center, AcGeVector3d::kZAxis, rad);
if (!pEnt1)
throw Acad::eOutOfMemory;
pEnt1->setDatabaseDefaults(pDb);
AcDbObjectId id1;
es = pSpaceRecord->appendAcDbEntity(id1, pEnt1);
if (es != Acad::eOk)
{
delete pEnt1;
throw es;
}
actrTransactionManager->addNewlyCreatedDBRObject(pEnt1);
// 2つ目の円を追加
AcDbCircle *pEnt2 = new AcDbCircle(center, AcGeVector3d::kZAxis, rad*2.0);
if (!pEnt2)
throw Acad::eOutOfMemory;
pEnt1->setDatabaseDefaults(pDb);
AcDbObjectId id2;
es = pSpaceRecord->appendAcDbEntity(id2, pEnt2);
if (es != Acad::eOk)
{
delete pEnt2;
throw es;
}
actrTransactionManager->addNewlyCreatedDBRObject(pEnt2);
// 3つ目の円を追加
AcDbCircle *pEnt3 = new AcDbCircle(center, AcGeVector3d::kZAxis, rad*4.0);
if (!pEnt3)
throw Acad::eOutOfMemory;
pEnt3->setDatabaseDefaults(pDb);
AcDbObjectId id3;
es = pSpaceRecord->appendAcDbEntity(id3, pEnt3);
if (es != Acad::eOk)
{
delete pEnt3;
throw es;
}
actrTransactionManager->addNewlyCreatedDBRObject(pEnt3);
actrTransactionManager->endTransaction();
}
catch (Acad::ErrorStatus es)
{
ads_printf(_T("Error : %s\n"), acadErrorStatusText(es));
actrTransactionManager->abortTransaction();
}
}
}
void initApp()
{
acedRegCmds->addCommand( _T("arxSampleGroup"), _T("CIRCLET"), _T("CIRCLET"), ACRX_CMD_MODAL, circles);
}
void unloadApp()
{
acedRegCmds->removeGroup(_T("arxSampleGroup"));
}
extern "C" AcRx::AppRetCode acrxEntryPoint
(AcRx::AppMsgCode msg, void* appId)
{
switch(msg)
{
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
initApp();
break;
case AcRx::kUnloadAppMsg:
unloadApp();
break;
default:
break;
}
return AcRx::kRetOK;
}