COM の作成 :【VC++】



ブラウザでダウンロード

COM は、ビルドするとその PC に登録されてしまいます。
リリースしたものは、他の PC で regsvr32.exe で登録します。
以下、Microsoft の regsvr32 的なドキュメント
1) ダウンロード センターから入手可能な Regsvr32.exe
2) Regsvr32.exe の登録し、COM DLL の登録を解除するソースコード
● ATL プロジェクトを作成する






● クラスを追加する








● メソッドを追加





● ビルド環境設定










● 簡単なメソッドの実装


tool.h に lightbox.h の参照を追加して、#pragma の記述を行います
#pragma once
#include "resource.h"
#include "night.h"

#include "lightbox\lightbox.h"

#pragma comment( lib, "lightbox\\lightbox.lib" )
#pragma comment( lib, "shlwapi.lib" )
#pragma comment( lib, "wininet.lib" )   
// *********************************************************
// MsgBox
// *********************************************************
STDMETHODIMP Ctool::MsgBox(BSTR str)
{
	_bstr_t bstr = str;

	::MessageBox( NULL, (LPTSTR)bstr, "", MB_OK );

	return S_OK;
}
テスト用スクリプト
Set obj = CreateObject("night.tool")

obj.MsgBox("OK")
● 戻り値を返すメソッドの実装
何故か、ウィザードでは指定できないようなので、手作業で追加します

場所は 3 箇所あるので注意して下さい。
night.idl
// night.idl : night の IDL ソース
//

// このファイルは、タイプ ライブラリ (night.tlb) およびマーシャリング コードを
// 作成するために MIDL ツールによって処理されます。

import "oaidl.idl";
import "ocidl.idl";

[
	object,
	uuid(56CFD513-9FFE-49F7-BE4F-CCFFD77A260D),
	dual,
	nonextensible,
	helpstring("Itool インターフェイス"),
	pointer_default(unique)
]
interface Itool : IDispatch{
	[id(1), helpstring("メソッド MsgBox")] HRESULT MsgBox([in] BSTR str);
	[id(2), helpstring("メソッド GetClipboard")] HRESULT GetClipboard([out,retval] BSTR *pVal);
};
[
	uuid(246E5E95-954B-4461-A7A8-1677C3412E20),
	version(1.0),
	helpstring("night 1.0 タイプ ライブラリ")
]
library nightLib
{
	importlib("stdole2.tlb");
	[
		uuid(543A98AE-FEFC-4D34-99ED-D8D7FE94823C),
		helpstring("tool Class")
	]
	coclass tool
	{
		[default] interface Itool;
	};
};
id(2) の行が追加されています
戻り値は、[out,retval] BSTR *pVal で表現されます


tool.h
// Ctool

class ATL_NO_VTABLE Ctool :
	public CComObjectRootEx<CComMultiThreadModel>,
	public CComCoClass<Ctool, &CLSID_tool>,
	public IDispatchImpl<Itool, &IID_Itool, &LIBID_nightLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
	Ctool()
	{
	}

DECLARE_REGISTRY_RESOURCEID(IDR_TOOL)


BEGIN_COM_MAP(Ctool)
	COM_INTERFACE_ENTRY(Itool)
	COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()



	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}

	void FinalRelease()
	{
	}

public:

	STDMETHOD(MsgBox)(BSTR str);
	STDMETHOD(GetClipboard)(BSTR *pVal);
};

OBJECT_ENTRY_AUTO(__uuidof(tool), Ctool)
Ctool クラスとしてのメソッド宣言の追加です
仮引数の記述のみを行います


tool.cpp
STDMETHODIMP Ctool::GetClipboard(BSTR *pVal)
{
	_bstr_t bstrValue;
	LboxString LString;
	LboxTool Tool;

	Tool.GetClipboardText( LString );
	bstrValue.operator = (LString.szLboxString);

	*pVal = bstrValue.copy();

	return S_OK;
}
処理本体です。
戻り値のメモリ管理は、受け渡したアプリケーションで行われるので、
copy メソッドにより作成された新しいメモリを渡します。
テスト用スクリプト
Set obj = CreateObject("night.tool")

obj.MsgBox( obj.GetClipboard() )


● 引数を省略可能にするには
以下は、別の COM のサンプルです
interface IMyAPI : IDispatch
{
	[id(1), helpstring("メソッド MsgBox")] HRESULT MsgBox(
		[in] BSTR Message,
		[in,optional] VARIANT Title
	);
};
public:
	STDMETHOD(MsgBox)(
		BSTR Message,
		VARIANT Title
	);
STDMETHODIMP CMyAPI::MsgBox(
	BSTR Message,
	VARIANT Title
)
{
	// 引数省略チェック用
	_variant_t vtWork(Title);

	_bstr_t bstr(Message);
	_bstr_t bstr2;

	// タイトル引数チェック
	if ( vtWork.vt != VT_ERROR ) {
		bstr2.operator = (Title);
	}
	else {
		bstr2.operator = ("デフォルト文字列");
	}

	MessageBox( NULL, (LPTSTR)bstr, (LPTSTR)bstr2, MB_OK );

	return S_OK;
}


● BOOLを返すには
通常の C++ における 真偽値の扱いと違うので( 正確に定義されている )
LboxBool 関数によって変換します。
[id(3), helpstring("メソッド MsgOkCancel")] HRESULT MsgOkCancel(
	[in] BSTR Value,
	[out,retval] BOOL *pVal
);
STDMETHOD(MsgOkCancel)(
	BSTR Value,
	BOOL *pVal
);
STDMETHODIMP CMyAPI::MsgOkCancel(
	BSTR Value,
	BOOL *pVal
)
{
	_bstr_t bstrValue;
	LboxWintool Wintool;

	bstrValue.operator = (Value);

	*pVal = LboxBool( Wintool.MsgOkCancel((LPTSTR)bstrValue) );

	return S_OK;
}
LboxBool
BOOL LboxBool( BOOL bFlg )
{
	BOOL bRet;

	if ( bFlg ) {
		bRet = 0xffffffff;
	}
	else {
		bRet = 0;
	}

	return bRet;
}