启动Visual C++并创建一个新工程,选择Win32 Dynamic-Link Library,工程命名为”Server”。
创建了两个抽象类Imath和IAdvancedMath。
//
//imath.h
//
// {03030C27-753F-4374-9A0B-C190D11F56C1} 由GUIDGEN.EXE创建
DEFINE_GUID(CLSID_Math,
0x3030c27, 0x753f, 0x4374, 0x9a, 0xb, 0xc1, 0x90, 0xd1, 0x1f, 0x56, 0xc1);
// {D7AB8963-4081-42cb-96B1-4441140B3D37}
DEFINE_GUID(IID_IMath,
0xd7ab8963, 0x4081, 0x42cb, 0x96, 0xb1, 0x44, 0x41, 0x14, 0xb, 0x3d, 0x37);
// {0249DE54-6989-47ec-8071-C3B4DFBFE1D3}
DEFINE_GUID(IID_IAdvancedMath,
0x249de54, 0x6989, 0x47ec, 0x80, 0x71, 0xc3, 0xb4, 0xdf, 0xbf, 0xe1, 0xd3);
class IMath : public IUnknown
{
public:
STDMETHOD(Add)(long , long , long * ) PURE;//PURE 相当于 "=0"
STDMETHOD(Subtract)(long , long , long * ) PURE;
STDMETHOD(Multiply)(long , long , long * ) PURE;
STDMETHOD(Divide)(long , long , long * ) PURE;
};
class IAdvancedMath : public IUnknown
{
public:
STDMETHOD(Factorial)( short , long * ) PURE;
STDMETHOD(Fibonacci)( short , long * ) PURE;
};
//
//math.h
//
#include "imath.h"
extern long g_lObjs;
extern long g_lLocks;
//组件类的声明
class Math : public IMath , public IAdvancedMath { public: Math(); ~Math(); //IUnknown STDMETHOD(QueryInterface( REFIID , void ** )); STDMETHOD_(ULONG , AddRef()); STDMETHOD_(ULONG , Release()); //IMath STDMETHOD(Add)(long , long , long * ); STDMETHOD(Subtract)(long , long , long * ); STDMETHOD(Multiply)(long , long , long * ); STDMETHOD(Divide)(long , long , long * ); //IAdvancedMath STDMETHOD(Factorial)( short , long * ); STDMETHOD(Fibonacci)( short , long * ); protected: long m_lRef; }; //类工厂的声明 class MathClassFactory : public IClassFactory { public: MathClassFactory(); ~MathClassFactory(); //IUnknown STDMETHOD(QueryInterface( REFIID , void ** )); STDMETHOD_(ULONG , AddRef()); STDMETHOD)(ULONG , Release()); //IClassFactory STDMETHOD(CreateInstance)(LPUNKNOWN , REFIID , void ** ); STDMETHOD(LockServer)(BOOL); protected: long m_lRef; };
//
//Math.cpp
//
#include
#include "math.h"
//
//Math class implenmentation
//
Math::Math()
{
m_lRef = 0;
InterlockedIncrement(&g_lObjs);
}
Math::~Math()
{
InterlockedDecrement(&g_lObjs);
}
STDMETHODIMP Math::QueryInterface( REFIID riid, void ** ppv)
{
*ppv = 0;
if(riid == IID_IUnknown )
*ppv = (IMath * )this;
else if( riid == IID_IMath )
*ppv = (IMath * )this;
else if( riid == IID_IAdvancedMath )
*ppv = (IAdvancedMath *)this;
if( *ppv )
{
AddRef();
return(S_OK);
}
return(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG)Math::AddRef()
{
return InterlockedIncrement( &m_lRef);
}
STDMETHODIMP_(ULONG)Math::Release()
{
if (InterlockedDecrement(&m_lRef) == 0 )
{
delete this;
return 0;
}
return m_lRef;
}
STDMETHODIMP Math::Add( long lOp1 , long lOp2 , long *pResult )
{
*pResult = lOp1 + lOp2;
return S_OK;
}
STDMETHODIMP Math::Subtract( long lOp1 , long lOp2 , long *pResult )
{
*pResult = lOp1 - lOp2;
return S_OK;
}
STDMETHODIMP Math::Multiply( long lOp1 , long lOp2 , long *pResult )
{
*pResult = lOp1 * lOp2;
return S_OK;
}
STDMETHODIMP Math::Divide( long lOp1 , long lOp2 , long *pResult )
{
*pResult = lOp1 / lOp2;
return S_OK;
}
static long calcFactorial( short n)
{
if ( n <= 1 )
{
return 1;
}
return n * calcFactorial( n - 1 );
}
STDMETHODIMP Math::Factorial( short sOp , long * pResult )
{
*pResult = calcFactorial( sOp );
return S_OK;
}
static long calcFibonacci( short n )
{
if ( n <= 1 )
{
return 1;
}
return calcFibonacci(n-1) + calcFibonacci(n-2);
}
STDMETHODIMP Math::Fibonacci( short sOp , long * pResult )
{
*pResult = calcFibonacci(sOp);
return S_OK;
}
MathClassFactory::MathClassFactory()
{
m_lRef = 0;
}
MathClassFactory::~MathClassFactory()
{
}
STDMETHODIMP MathClassFactory::QueryInterface( REFIID riid , void ** ppv )
{
*ppv = 0;
if ( riid == IID_IUnknown || riid == IID_IClassFactory )
*ppv = this;
if ( *ppv )
{
AddRef();
return S_OK;
}
return(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG)MathClassFactory::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
STDMETHODIMP_(ULONG)MathClassFactory::Release()
{
if ( InterlockedDecrement(&m_lRef) == 0 )
{
delete this;
return 0;
}
return m_lRef;
}
STDMETHODIMP MathClassFactory::CreateInstance( LPUNKNOWN pUnkOuter , REFIID riid , void ** ppvObj )
{
Math * pMath;
HRESULT hr;
*ppvObj = 0;
pMath = new Math;
if ( pMath == 0 )
return(E_OUTOFMEMORY);
hr = pMath->QueryInterface( riid , ppvObj);
if( FAILED(hr) )
delete pMath;
return hr;
}
STDMETHODIMP MathClassFactory::LockServer(BOOL fLock)
{
if(fLock)
InterlockedIncrement(&g_lLocks);
else
InterlockedDecrement(&g_lLocks);
return S_OK;
}
//
//server.cpp
//
//
#include
#include
#include "math.h"
long g_lObjs = 0;
long g_lLocks = 0;
STDAPI DllGetClassObject( REFCLSID rclsid , REFIID riid , void ** ppv )
{
HRESULT hr;
MathClassFactory * pCF;
if( rclsid != CLSID_Math )
return(E_FAIL);
pCF = new MathClassFactory;
if( pCF == 0 )
return(E_OUTOFMEMORY);
hr = pCF->QueryInterface( riid , ppv );
if(FAILED(hr))
delete pCF;
return hr;
}
STDAPI DllCanUnloadNow(void)
{
if( g_lObjs || g_lLocks)
return(S_FALSE);
else
return(S_OK);
}
//
//server.cpp
//
//
#include
//Component category support
#include
#include
#include "math.h"
//Our component category GUID
#include "ATLDevGuide.h"
//Used to store the instance handle
//We need this to call the GetModuleFileName API
HINSTANCE g_hinstDLL = 0;
long g_lObjs = 0;
long g_lLocks = 0;
//DLLMain
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason , LPVOID lpvReserved )
{
if( fdwReason == DLL_PROCESS_ATTACH )
g_hinstDLL = hinstDLL;
return TRUE;
}
static BOOL SetRegKeyValue(
LPTSTR pszKey,
LPTSTR pszSubkey,
LPTSTR pszValue)
{
BOOL bOk = FALSE;
LONG ec;
HKEY hKey;
TCHAR szKey[128];
lstrcpy( szKey , pszKey);
if( NULL != pszSubkey )
{
lstrcat( szKey , "\\" );
lstrcat( szKey , pszSubkey );
}
ec = RegCreateKeyEx(
HKEY_CLASSES_ROOT,
szKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if(ERROR_SUCCESS == ec)
{
if(NULL != pszValue )
{
ec = RegSetValueEx(
hKey,
NULL,
0,
REG_SZ,
(BYTE*) pszValue,
(lstrlen(pszValue)+1) * sizeof(TCHAR));
}
if(ERROR_SUCCESS == ec )
bOk = TRUE;
RegCloseKey(hKey);
}
return bOk;
}
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{
ICatRegister* pcr = 0;
HRESULT hr;
hr = CoCreateInstance( CLSID_StdComponentCategoriesMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICatRegister,
(void**)&pcr );
if (FAILED(hr))
return hr;
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409;
int len = wcslen( catDescription );
wcsncpy( catinfo.szDescription, catDescription, wcslen( catDescription ));
catinfo.szDescription[len] = '\0';
hr = pcr->RegisterCategories( 1, &catinfo );
pcr->Release();
return hr;
}
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = 0;
HRESULT hr;
hr = CoCreateInstance( CLSID_StdComponentCategoriesMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICatRegister,
(void**)&pcr );
if (SUCCEEDED(hr))
{
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories( clsid, 1, rgcatid );
pcr->Release();
}
return hr;
}
STDAPI DllRegisterServer(void)
{
HRESULT hr = NOERROR;
CHAR szModulePath[MAX_PATH];
CHAR szID[128];
CHAR szCLSID[128];
WCHAR wszID[128];
WCHAR wszCLSID[128];
GetModuleFileName(
g_hinstDLL,
szModulePath,
sizeof(szModulePath) / sizeof(CHAR) );
StringFromGUID2(CLSID_Math ,wszID , sizeof(wszID));
wcscpy(wszCLSID,L"CLSID\\");
wcscat(wszCLSID,wszID);
wcstombs(szID ,wszID , sizeof(szID));
wcstombs(szCLSID,wszCLSID, sizeof(szID));
//Create the ProgID keys
SetRegKeyValue(
"Chapter2.Math.1",
NULL,
"Chapter2 Math Component");
SetRegKeyValue(
"Chapter2.Math.1",
"CLSID",
szID);
//Create version independent ProgID keys
SetRegKeyValue(
"Chapter2.Math",
NULL,
"Chapter2 Math Component");
SetRegKeyValue(
"Chapter2.Math",
"CurVer",
"Chapter2.Math.1");
SetRegKeyValue(
"Chapter2.Math",
"CLSID",
szID);
//Create entries under CLSID
SetRegKeyValue(
szCLSID,
NULL,
"Chapter 2 Math Component");
SetRegKeyValue(
szCLSID,
"ProgID",
"Chapter2.Math.1");
SetRegKeyValue(
szCLSID,
"VersionIndependentProgID",
"Chapter2.Math");
SetRegKeyValue(
szCLSID,
"InprocServer32",
szModulePath);
//Register our component category
CreateComponentCategory(CATID_ATLDevGuide,
L"ATL Developer's Guide Examples");
RegisterCLSIDInCategory( CLSID_Math , CATID_ATLDevGuide);
return S_OK;
}
STDAPI DllGetClassObject( REFCLSID rclsid , REFIID riid , void ** ppv )
{
HRESULT hr;
MathClassFactory * pCF;
if( rclsid != CLSID_Math )
return(E_FAIL);
pCF = new MathClassFactory;
if( pCF == 0 )
return(E_OUTOFMEMORY);
hr = pCF->QueryInterface( riid , ppv );
if(FAILED(hr))
delete pCF;
return hr;
}
STDAPI DllCanUnloadNow(void)
{
if( g_lObjs || g_lLocks)
return(S_FALSE);
else
return(S_OK);
}
;
;Server.def:Declares the module parameters for the DLL.
;
LIBRARY "SERVER"
DESCRIPTION 'SERVER Windows Dynamic Link Library'
EXPORTS
;Explicit exports can go here
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
; DllUnregiesterServer PRIVATE
// COMClient.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#include
#include "..\server\imath.h"
int main(int argc, char* argv[])
{
cout << "Initializing COM" << endl;
if( FAILED(CoInitialize(NULL)))
{
cout << "Unable to initialize COM" << endl;
return -1;
}
//Get the unique CLSID from the ProgID
CLSID clsid;
HRESULT hr = ::CLSIDFromProgID(L"Chapter2.Math.1" , &clsid );
if( FAILED(hr))
{
cout.setf( ios::hex , ios::basefield);
cout << "Unable to get CLSID from ProgID. HR = " << hr << endl;
return -1;
}
//Get the class factory for the Math class
IClassFactory * pCF;
hr = CoGetClassObject(clsid,
CLSCTX_INPROC,
NULL,
IID_IClassFactory,
(void **) &pCF);
if( FAILED(hr) )
{
cout.setf(ios::hex,ios::basefield);
cout << "Failed to GetClassObject server instance.HR ="
<< hr << endl;
return -1;
}
//Using the class factory interface create an instance of the
//Component and return the IUnknown interface
IUnknown * pUnk;
hr = pCF->CreateInstance( NULL , IID_IUnknown , (void**) &pUnk);
//Release the class factory
pCF->Release();
if(FAILED(hr))
{
cout.setf( ios::hex , ios::basefield);
cout << "Failed to create server instance.HR = " << hr << endl;
return -1;
}
cout << "Instance created" << endl;
IMath * pMath = NULL;
hr = pUnk->QueryInterface(IID_IMath , (void **) &pMath);
pUnk->Release();
if( FAILED(hr))
{
cout << "QueryInterface() for IMath failed" << endl;
CoUninitialize();
return -1;
}
long result;
pMath->Multiply( 100 , 8 , &result);
cout << "100 * 8 is " << result << endl;
pMath->Subtract( 1000, 333 , &result);
cout << "10000 - 333 is " << result << endl;
//Try IAdvancedMath
IAdvancedMath* pAdvMath = NULL;
hr = pMath->QueryInterface( IID_IAdvancedMath , (void **) & pAdvMath);
if( FAILED(hr))
{
cout << "QueryInterface() for IAdvancedMath failed" << endl;
pMath->Release();
CoUninitialize();
return -1;
}
pAdvMath->Factorial(10, &result);
cout << "10! is " << result << endl;
pAdvMath->Fibonacci( 10 , &result);
cout << "The Fibonacci of 10 is " << result << endl;
cout << "Releasing IMath interface " << endl;
pMath->Release();
cout << "Shutting down COM" << endl;
CoUninitialize();
return 0;
}