最近需要用到COM组件的知识,看了看COM编程指南,感觉还不错,把我的学习心得记录下来。这是我根据教程写的demo
StopWatch接口实现部分,接口部分我的项目是动态库,主要源码如下:
完整demo见:http://download.csdn.net/detail/davidsu33/7750101
stopwatch.h
#pragma once #include <Windows.h> #include <MMSystem.h> #include <Unknwn.h> #include <WinBase.h> #include "timer_i.h" class stopwatcher { public: stopwatcher(void); ~stopwatcher(void); }; class IStopWatch : public IUnknown { public: //virtual unsigned long _stdcall Release() = 0; virtual HRESULT _stdcall Start() = 0; virtual HRESULT _stdcall ElaspedTime(float *elaspedtime) = 0; }; class CStopWatch : public IStopWatch { public: CStopWatch() { m_nRefValue = 0; m_nFreq.QuadPart = 0; QueryPerformanceFrequency(&m_nFreq); AddRef(); } public: //virtual unsigned long _stdcall Release() //{ // delete this; // return 0; //}; //创建对应的接口对象 virtual HRESULT STDMETHODCALLTYPE QueryInterface( /* [in] */ REFIID riid, /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) { if(riid == IID_IStopWatch) { *ppvObject = static_cast<IStopWatch*>(this); return S_OK; } else if(riid == IID_IUnknown) { *ppvObject = static_cast<IUnknown*>(this); return S_OK; } *ppvObject = NULL; return E_NOINTERFACE; }; //增加引用 virtual ULONG STDMETHODCALLTYPE AddRef( void) { InterlockedIncrement(&m_nRefValue); return m_nRefValue; }; //解除引用 virtual ULONG STDMETHODCALLTYPE Release( void) { InterlockedDecrement(&m_nRefValue); if(m_nRefValue == 0) delete this; return m_nRefValue; }; virtual HRESULT _stdcall Start() { BOOL bOK = QueryPerformanceCounter(&m_nStartTime); if(!bOK) return S_FALSE; return S_OK; }; virtual HRESULT _stdcall ElaspedTime(float *elaspedtime) { LARGE_INTEGER nStopTime; BOOL bOK = QueryPerformanceCounter(&nStopTime); if(!bOK) return S_FALSE; *elaspedtime = ((float)(nStopTime.QuadPart - m_nStartTime.QuadPart))/m_nFreq.QuadPart; return S_OK; }; private: LARGE_INTEGER m_nFreq; LARGE_INTEGER m_nStartTime; volatile unsigned long m_nRefValue; }; //return IStopWatch interface object extern "C" HRESULT _stdcall DllGetClassObject(REFCLSID rcsid, REFIID rid, LPVOID* lpvoid) { if(rcsid == CLSID_CStopWatch) { *lpvoid = static_cast<IStopWatch*>(new CStopWatch); return S_OK; } *lpvoid = NULL; return CLASS_E_CLASSNOTAVAILABLE; }
#include "../stopwatch/stopwatcher.h" #include "../stopwatch/timer_i.h" #include <iostream> #include <cstring> #include <cassert> #define TIMERDLL L"../Debug/stopwatch.dll" #define PROCNAME "DllGetClassObject" typedef HRESULT (_stdcall* GETOBJFUNC)(REFCLSID , REFIID , LPVOID* ); using namespace std; void trace(const char *str) { cout<<str<<endl; } void trace(const string& s) { cout<<s.c_str()<<endl; } HRESULT CreateInstance(void **p, HMODULE *rhMod) { HMODULE hMod = LoadLibrary(TIMERDLL); if(!hMod) return E_FAIL; GETOBJFUNC proc = (GETOBJFUNC)GetProcAddress(hMod, PROCNAME); if(!proc) return E_FAIL; *p = proc; *rhMod = hMod; return S_OK; } void FreeInstance(HMODULE hMod) { assert(FreeLibrary(hMod)); } void testInstance() { void *fptr = NULL; HMODULE hMod = NULL; HRESULT hr = CreateInstance(&fptr, &hMod); if(FAILED(hr)) { trace("CreateInstace failed"); return; } GETOBJFUNC proc = (GETOBJFUNC)(fptr); IUnknown *ptr = NULL; //首先得到类实例 //然后根据类实例得到IUnknown //最后通过IUnknown调取QueryInterface接口来得到其子类的接口对象 //调用子类的接口对象 hr = proc(CLSID_CStopWatch, IID_IUnknown, (LPVOID*)&ptr); if(FAILED(hr)) { trace("GetObject failed"); return; } if(!ptr) { trace("ptr is null"); return; } IStopWatch *ptrSW = NULL; hr = ptr->QueryInterface(IID_IStopWatch, (void**)&ptrSW); assert(SUCCEEDED(hr)); hr = ptrSW->Start(); assert(SUCCEEDED(hr)); int m=0; for(int i=0; i<10000000; ++i) ++m; float elaspedtime = 0; hr = ptrSW->ElaspedTime(&elaspedtime); assert(SUCCEEDED(hr)); cout<<"ElaspedTime:"<<elaspedtime<<endl; //释放对象本身 ptrSW->Release(); FreeInstance(hMod); } int main(int argc, char *argv[]) { testInstance(); getchar(); return 0; }
原文:http://blog.csdn.net/davidsu33/article/details/38539479