VS2012創建ATL工程及使用MFC測試COM組件

一、創建ATL工程

1、創建ATL項目,取名爲MyATL


2、在ATL項目嚮導中,勾選【支持MFC】(利用MFC測試用)、【支持 COM+ 1.0】和【支持部件註冊器】,其餘的選項默認,點擊完成。


3、右鍵工程名稱,選擇添加類,接下來選擇【ATL簡單對象】。

4、在【ATL簡單對象嚮導】對話框中填入下面內容(可更改爲自己喜歡的類名稱),然後直接點擊完成。


5、切換到類視圖,爲剛剛添加的接口IMyATLClass添加方法。


6、現在來添加2個方法,分別用來計算兩個數之和和彈出MFC對話框。



7、切換到【解決方案資源管理器】,可以看到SumPopupDialog的定義。

interface IMyATLClass : IDispatch{
	[id(1)] HRESULT Sum([in] LONG para1, [in] LONG para2, [in] LONG* sum);
	[id(2)] HRESULT PopupDialog([in] CHAR* text);
};

將參數[in] LONG* sum修改爲[out] LONG* sum,表示這是一個需要輸出的值。

8、打開MyATLClass.cpp,實現添加的兩個方法。

STDMETHODIMP CMyATLClass::Sum(LONG para1, LONG para2, LONG* sum)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: 在此添加實現代碼
	*sum = para1 + para2;

	return S_OK;
}

STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: 在此添加實現代碼
	AfxMessageBox((LPCTSTR)text);

	return S_OK;
}

9、生成該工程,得到MyATL.dll並在註冊表中註冊。

二、測試ATL組件

1、在上面的工程中添加測試項目。


2、添加用於測試的MFC工程TestATL

3、運行MFC應用程序嚮導,爲簡單起見,選擇對話框工程,其餘默認,點擊完成。

4、將生成的對話框中【確定】、【取消】按鈕修改如下。


5、雙擊上面的按鈕,在系統生成的函數裏刪除掉代碼CDialogEx::OnOK();如下。

void CTestATLDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知處理程序代碼

}

void CTestATLDlg::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知處理程序代碼

}

6、在TestATL工程中引入由MyATL工程中生成的“MyATL_i.h”、“MyATL_i.c”(這個文件主要用來查看CLSID_MyATLClassIID_IMyATLClass的值),並在TestATLDlg.cpp中添加MyATL_i.h的引用。

#include "..\MyATL\MyATL_i.h"

7、生成TestATL工程,會出現如下錯誤。

1>d:\projects\test\myatl\myatl\myatl_i.c : fatal error C1853: “Debug\TestATL.pch”預編譯頭文件來自編譯器的早期版本,或者預編譯頭爲 C++ 而在 C 中使用它(或相反)

解決方法是右鍵“MyATL_i.c->屬性->C/C++->預編譯頭,將“使用(/Yu)”修改爲“不使用預編譯頭”。

再次生成TestATL就不會報錯了。

8、實現Sum按鈕的響應方法。

void CTestATLDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知處理程序代碼
	HRESULT hr = S_OK;
	hr = CoInitialize(NULL);

	ITypeLib* pTypeLib = NULL;
	hr = ::LoadTypeLib(L"..\\Debug\\MyATL.dll", &pTypeLib); //加載並註冊類型庫
	if (FAILED(hr))
	{
		return;
	}

	int nTypeInfoCount = pTypeLib->GetTypeInfoCount();
	if (nTypeInfoCount <= 0) //返回類型庫中的類型說明的數量
	{
		return;
	}

	ITypeInfo* pTypeInfo = NULL;
	TYPEATTR* pTypeAttr = NULL;

	//!!!此處一定要注意導出類在.idl文件中的順序!!!
	hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
	hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
	CLSID clsid = pTypeAttr->guid;

	hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
	hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
	IID iid = pTypeAttr->guid;

	IMyATLClass* pMyATLClass = NULL;
	hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&pMyATLClass);
	hr = CoCreateInstance(CLSID_MyATLClass, NULL, CLSCTX_INPROC_SERVER, IID_IMyATLClass, (void **)&pMyATLClass);

	int sum = 0;
	pMyATLClass->Sum(2, 3, (LONG*)&sum);

	pTypeInfo->ReleaseTypeAttr(pTypeAttr);
	pTypeInfo->Release();
	CoUninitialize();
}

9、將TestATL設置爲啓動項,在CoCreateInstance設置斷點跟蹤調試。啓動應用後,點擊Sum按鈕,進入斷點,在監視窗口看到clsid、iid是和CLSID_MyATLClass、IID_IMyATLClass一一對應的,這就說明在調用pTypeLib->GetTypeInfo的時候,其參數值index是正確的。

10、註釋掉含有CLSID_MyATLClass那一行對CoCreateInstance的調用,添加對Sum的測試代碼,調試運行在監視窗口可以看到運算結果。

11、添加對Popup Dialog的測試,過程略,結果如下。

pMyATLClass->PopupDialog("test ATL");

考慮到編碼問題,將MyATLClass.cpp中對PopupDialog的實現修改爲:

STDMETHODIMP CMyATLClass::PopupDialog(CHAR* text)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: 在此添加實現代碼
	CString str(text);
	AfxMessageBox((LPCTSTR)str);

	return S_OK;
}

重新生成MyATL,並啓動TestATL測試如下。

12、再看pTypeLib->GetTypeInfo的調用。

程序中的調用是:

	hr = pTypeLib->GetTypeInfo(2, &pTypeInfo);
	hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
	CLSID clsid = pTypeAttr->guid;

	hr = pTypeLib->GetTypeInfo(3, &pTypeInfo);
	hr = pTypeInfo->GetTypeAttr(&pTypeAttr);
	IID iid = pTypeAttr->guid;

注意到其中index的值分別是23,表示第34個值。另外,

int nTypeInfoCount = pTypeLib->GetTypeInfoCount();

nTypeInfoCount的值爲4,這下就可以知道pTypeLib中前2TypeInfo並不是所期望的,而第34個纔是我們需要的,爲什麼會這樣?

再次找到MyATL工程中的MyATL.idl文件,找到library MyATLLib的定義,

library MyATLLib
{
	importlib("stdole2.tlb");
	[
		uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)		
	]
	coclass CompReg
	{
		[default] interface IComponentRegistrar;
	};
	[
		uuid(03677350-0273-42BA-8F16-C7701493C1DC)		
	]
	coclass MyATLClass
	{
		[default] interface IMyATLClass;
	};
};

可以看到首先定義的是CompReg這個類,它使得生成的dll完成了在註冊表中的註冊,並且它的兩部分也正是pTypeLib->GetTypeInfo的前兩部分,因此GetTypeInfoindex就變成了23

下面修改CompRegMyATLClass類定義的順序,

library MyATLLib
{
	importlib("stdole2.tlb");
	[
		uuid(03677350-0273-42BA-8F16-C7701493C1DC)		
	]
	coclass MyATLClass
	{
		[default] interface IMyATLClass;
	};
	[
		uuid(59E6B9BA-489E-417A-BCE9-2AFFE61F57D1)		
	]
	coclass CompReg
	{
		[default] interface IComponentRegistrar;
	};
};

在調用pTypeLib->GetTypeInfo的時候,將參數設置爲01,這時候也會成功運行。

最後,我們知道了在library MyATLLib中類定義的順序決定了GetTypeInfoindex參數的值,注意不到這個問題,如果在接口自動化中隨意寫index參數的值,就會一直找不到方向,白白浪費時間。


附:

源碼地址:網盤代碼 | CSDN代碼

參考出處VS2010創建ATL工程及使用C++測試COM組件

發佈了45 篇原創文章 · 獲贊 11 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章