适合新手入門,也可以作為一份模闆供經驗豐富的開發者使用,可節省大量的時間。官方網站上給出了架構的基本結構,如下圖所示:
COM元件和ActiveX控件示例

資料通路示例
庫示例
程序間通信示例
花了2個小時粗略閱讀了代碼,記錄下學習心得:
1)先來說ActiveX這條線,它裡面使用了ATL(這裡有2種實作,程序内和程序外),MFC,C#,VB四種技術來實作。功能就是四點:一個傳回字元串的HelloWorld方法,一個float類型的屬性FloatProperty,一個傳回程序号和線程号的GetProcessThreadID方法,一個FloatPropertyChanging事件。
頭檔案的修改
“ActiveX 控件向導”将下列代碼放置在控件頭檔案中。聲明了 factory 對象的兩個成員函數,其中一個成員函數驗證控件 .LIC 檔案是否存在,而另一個成員函數則對包含該控件的應用程式中使用的許可證密鑰進行檢索:
BEGIN_OLEFACTORY(CMFCActiveXCtrl) // Class factory and guid
virtual BOOL VerifyUserLicense();
virtual BOOL GetLicenseKey(DWORD, BSTR FAR*);
END_OLEFACTORY(CMFCActiveXCtrl)
實作檔案的修改
“ActiveX 控件向導”将下面兩條語句放置在控件實作檔案中,以聲明許可檔案名和許可字元串:
static const TCHAR BASED_CODE _szLicFileName[] =
_T("License.lic");
static const WCHAR BASED_CODE _szLicString[] =
L"Copyright (c) 2000 ";
注意:如果以任何方式修改 szLicString,則必須也修改控件 .LIC 檔案的第一行,否則授權将無法正确運作。
“ActiveX 控件向導”将下列代碼放置在控件實作檔案中,以定義控件類的 VerifyUserLicense 函數和 GetLicenseKey 函數:
// CMFCActiveXCtrl::CMFCActiveXCtrlFactory::VerifyUserLicense -
// Checks for existence of a user license
BOOL CMFCActiveXCtrl::CMFCActiveXCtrlFactory::VerifyUserLicense()
{
return AfxVerifyLicFile(AfxGetInstanceHandle(), _szLicFileName,
_szLicString);
}
// CMFCActiveXCtrl::CMFCActiveXCtrlFactory::GetLicenseKey -
// Returns a runtime licensing key
BOOL CMFCActiveXCtrl::CMFCActiveXCtrlFactory::GetLicenseKey(DWORD dwReserved,
BSTR FAR* pbstrKey)
if (pbstrKey == NULL)
return FALSE;
*pbstrKey = SysAllocString(_szLicString);
return (*pbstrKey != NULL);
最後,“ActiveX 控件向導”修改控件項目 .IDL 檔案。将關鍵字 licensed 添加到控件的 coclass 聲明中,如下例所示:
[ uuid(E389AD6C-4FB6-47AF-B03A-A5A5C6B2B820), licensed,
helpstring("MFCActiveX Control"), control ]
coclass MFCActiveX
3)作者封裝了一個方法AutoWrap來調用COM元件公開出來的屬性或方法。
HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,
LPOLESTR ptName, int cArgs
)
// Begin variable-argument list
va_list marker;
va_start(marker, cArgs);
if (!pDisp)
{
_putts(_T("NULL IDispatch passed to AutoWrap()"));
_exit(0);
}
// Variables used
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
HRESULT hr;
char szName[200];
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
// Get DISPID for name passed
hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT,
&dispID);
if (FAILED(hr))
_tprintf(_T(
"IDispatch::GetIDsOfNames(/"%s/") failed w/err 0x%08lx/n"
), szName, hr);
return hr;
// Allocate memory for arguments
VARIANT *pArgs = new VARIANT[cArgs+1];
// Extract arguments
for(int i=0; i<cArgs; i++)
pArgs[i] = va_arg(marker, VARIANT);
// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Handle special-case for property-puts
if (autoType & DISPATCH_PROPERTYPUT)
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
// Make the call
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
autoType, &dp, pvResult, NULL, NULL);
if (FAILED(hr))
"IDispatch::Invoke(/"%s/"=%08lx) failed w/err 0x%08lx/n"
), szName, dispID, hr);
// End variable-argument section
va_end(marker);
delete[] pArgs;
return hr;
4)DLL的延遲加載使得我們不需要使用LoadLibrary和GetProcAddress。這樣的好處是直到程式調用DLL中的函數時才加載此DLL。
#include <Delayimp.h>
解除安裝延遲加載的DLL的代碼:
PCSTR pszDll = "CppDllExport.dll";
_tprintf(_T("__FUnloadDelayLoadedDLL2 => %d/n"),
__FUnloadDelayLoadedDLL2(pszDll));