• com学习2——正式接触com


    前面的com学习是从原理上来理解com,原理看上去很简单,但是com是很强大的。它不仅是一套标准,微软还提供了com的开发库—com库。com库包装了com的底层的很多细节,开发者用com开发的时候只要调用com库中的函数,可以很方便进行开发。com库中为了提供一种通用的调用对象的函数,引入了类厂(classfactory)的概念。类厂是为了上面的函数的通用调用而屏蔽掉下面的具体差异。其实很简单,就是每个实现接口的对象对应一个类厂,这个类厂用来调用该对象。因为每个对象都有区别,调用它也可能会有区别,这样用户来调用这些对象都要为每个对象实现调用方法,因此就没有标准和通用性,而通过类厂来调用就不一样了,用户只要调用类厂来生成对象就行。不需要接触到对象,这样具体的差异就被屏蔽掉了。com中除了引入了类厂机制外,它还有引出函数,这是外界调用com对象的唯一通道。com对象中用DllGetClassObject来调用类厂,并将DllGetClassObject引出,客户程序有两个函数来调用这个引出函数,一个是CoCreateInstance,另一个是CoGetClassObject,而CoCreateInstance是用户来调用的,CoCreateInstance去调用CoGetClassObject,CoGetClassObject去调用DllGetClassObject,DllGetClassObject去调用类厂,类厂调用对象,这就形成了一套调用机制,而对用户来说也非常方便,只要调用CoCreateInstance就能调用com对象。com库中为了更方便调用,用到了注册表,就是将com对象注册到注册表中,这样用户调用的时候只要根据com对象在注册表中注册的名字直接来获得com对象标识符,并通过标识符来调用com对象。这是非常方便的。
     
    程序例子:
    com程序

     
    代码:
    接口:IOuter.h
    #ifndef __IOuter_H__
    #define __IOuter_H__
     
    #include "Unknwn.h"
     
    extern "C" const GUID IID_Outer;
     
    class IOuter : public IUnknown
    {
    public:
    virtual BOOL __stdcall Outer() = 0;
    };
     
    #endif
     
    com对象:Object.h
    #ifndef __Object_H__
    #define __Object_H__
     
     
    #ifndef __IOuter_H__
    #include "IOuter.h"
    #endif
     
    class CObject : public IOuter
    {
    public:
    CObject();
    ~CObject();
     
    public:
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();
     
    virtual BOOL __stdcall Outer();
     
    private:
    int m_Ref;
    };
     
     
    #endif
     
    类厂实现:Factory.h
    #ifndef __Factory_H__
    #define __Factory_H__
     
    #include "Unknwn.h"
     
    class CObjectFactory : public IClassFactory
    {
    protected:
    ULONG m_Ref;
     
    public:
    CObjectFactory();
    ~CObjectFactory();
     
    HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
     
    HRESULT __stdcall CreateInstance(IUnknown*, const IID& iid, void** ppv);
    HRESULT __stdcall LockServer(BOOL);
    };
     
    #endif
     
    Factory.cpp
    #include "stdafx.h"
    #include "Factory.h"
    #include "Object.h"
     
    extern ULONG g_LockNumber;
    extern ULONG g_ObjectNumber;
     
     
     
    CObjectFactory::CObjectFactory()
    {
    m_Ref = 0;
    }
     
     
    CObjectFactory::~CObjectFactory()
    {
     
    }
     
     
    HRESULT CObjectFactory::QueryInterface(const IID& iid, void** ppv)
    {
    if(iid == IID_IUnknown)
    {
    *ppv = (IUnknown*) this;
    ((IUnknown*)(*ppv))->AddRef();
    }
    else if(iid == IID_IClassFactory)
    {
    *ppv = (IClassFactory*) this;
    ((IClassFactory*)(*ppv))->AddRef();
    }
    else
    {
    *ppv = NULL;
    return E_NOINTERFACE;
    }
     
    return S_OK;
    }
     
     
    ULONG CObjectFactory::AddRef()
    {
    m_Ref++;
    return (ULONG) m_Ref;
    }
     
     
    ULONG CObjectFactory::Release()
    {
    m_Ref--;
    if(m_Ref == 0)
    {
    delete this;
    return 0;
    }
     
    return (ULONG) m_Ref;
    }
     
     
    HRESULT CObjectFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv)
    {
    CObject* pObj;
    HRESULT hr;
     
    *ppv = NULL;
    hr = E_OUTOFMEMORY;
     
    if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
     
    pObj = new CObject();
    if(pObj == NULL) return hr;
     
    hr = pObj->QueryInterface(iid, ppv);
    if(hr != S_OK)
    {
    g_ObjectNumber--;
    delete pObj;
    }
     
    return hr;
    }
     
    HRESULT CObjectFactory::LockServer(BOOL bLock)
    {
    if(bLock) g_LockNumber++;
    else g_LockNumber--;
     
    return NOERROR;
    }
     
    注册表相关:Registry.h
    #ifndef __Registry_H__
    #define __Registry_H__
    //
    // Registry.h
    // - Helper functions registering and unregistering a component.
    //
    // - These helper functions were borrowed and modifed from
    // Dale Rogerson's book Inside COM.
     
    // This function will register a component in the Registry.
    // DllRegisterServer function should call this function.
    HRESULT RegisterServer(const CLSID& clsid,
    const char *szFileName,
    const char* szProgID,
    const char* szDescription,
    const char* szVerIndProgID) ;
     
    // This function will unregister a component. Components
    // DllUnregisterServer function should call this function.
    HRESULT UnregisterServer(const CLSID& clsid,
    const char* szProgID,
    const char* szVerIndProgID) ;
     
    #endif
     
    Registry.cpp
     
    #include "stdafx.h"
    #include <objbase.h>
    #include <assert.h>
     
    #include "Registry.h"
     
    ////////////////////////////////////////////////////////
    //
    // Internal helper functions prototypes
    //
    // - These helper functions were borrowed and modifed from
    // Dale Rogerson's book Inside COM.
     
    // Set the given key and its value.
    BOOL SetKeyAndValue(const char* pszPath,
    const char* szSubkey,
    const char* szValue) ;
     
    // Convert a CLSID into a char string.
    void CLSIDtoString(const CLSID& clsid,
    char* szCLSID,
    int length) ;
     
    // Delete szKeyChild and all of its descendents.
    LONG DeleteKey(HKEY hKeyParent, const char* szKeyString) ;
     
    ////////////////////////////////////////////////////////
    //
    // Constants
    //
     
    // Size of a CLSID as a string
    constint CLSID_STRING_SIZE = 39 ;
     
    /////////////////////////////////////////////////////////
    //
    // Public function implementation
    //
     
    //
    // Register the component in the registry.
    //
    HRESULT RegisterServer(const CLSID& clsid, // Class ID
    const char *szFileName, // DLL module handle
    const char* szProgID, // IDs
    const char* szDescription, // Description String
    const char* szVerIndProgID) // optional
     
    {
    // Convert the CLSID into a char.
    char szCLSID[CLSID_STRING_SIZE] ;
    CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;
     
    // Build the key CLSID\\{...}
    char szKey[64] ;
    strcpy(szKey, "CLSID\\") ;
    strcat(szKey, szCLSID) ;
     
    // Add the CLSID to the registry.
    SetKeyAndValue(szKey, NULL, szDescription) ;
     
    // Add the server filename subkey under the CLSID key.
    SetKeyAndValue(szKey, "InprocServer32", szFileName) ;
     
    // Add the ProgID subkey under the CLSID key.
    if (szProgID != NULL) {
    SetKeyAndValue(szKey, "ProgID", szProgID) ;
    SetKeyAndValue(szProgID, "CLSID", szCLSID) ;
    }
     
    if (szVerIndProgID) {
    // Add the version-independent ProgID subkey under CLSID key.
    SetKeyAndValue(szKey, "VersionIndependentProgID",
    szVerIndProgID) ;
     
    // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
    SetKeyAndValue(szVerIndProgID, NULL, szDescription) ;
    SetKeyAndValue(szVerIndProgID, "CLSID", szCLSID) ;
    SetKeyAndValue(szVerIndProgID, "CurVer", szProgID) ;
     
    // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
    SetKeyAndValue(szProgID, NULL, szDescription) ;
    SetKeyAndValue(szProgID, "CLSID", szCLSID) ;
    }
     
    return S_OK ;
    }
     
    //
    // Remove the component from the registry.
    //
    HRESULT UnregisterServer(const CLSID& clsid, // Class ID
    const char* szProgID, // IDs
    const char* szVerIndProgID) // Programmatic
    {
    // Convert the CLSID into a char.
    char szCLSID[CLSID_STRING_SIZE] ;
    CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;
     
    // Build the key CLSID\\{...}
    char szKey[64] ;
    strcpy(szKey, "CLSID\\") ;
    strcat(szKey, szCLSID) ;
     
    // Delete the CLSID Key - CLSID\{...}
    LONG lResult = DeleteKey(HKEY_CLASSES_ROOT, szKey) ;
     
    // Delete the version-independent ProgID Key.
    if (szVerIndProgID != NULL)
    lResult = DeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;
     
    // Delete the ProgID key.
    if (szProgID != NULL)
    lResult = DeleteKey(HKEY_CLASSES_ROOT, szProgID) ;
     
    return S_OK ;
    }
     
    ///////////////////////////////////////////////////////////
    //
    // Internal helper functions
    //
     
    // Convert a CLSID to a char string.
    void CLSIDtoString(const CLSID& clsid,
    char* szCLSID,
    int length)
    {
    assert(length >= CLSID_STRING_SIZE) ;
    // Get CLSID
    LPOLESTR wszCLSID = NULL ;
    HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;
    assert(SUCCEEDED(hr)) ;
     
    // Covert from wide characters to non-wide.
    wcstombs(szCLSID, wszCLSID, length) ;
     
    // Free memory.
    CoTaskMemFree(wszCLSID) ;
    }
     
    //
    // Delete a key and all of its descendents.
    //
    LONG DeleteKey(HKEY hKeyParent, // Parent of key to delete
    const char* lpszKeyChild) // Key to delete
    {
    // Open the child.
    HKEY hKeyChild ;
    LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
    KEY_ALL_ACCESS, &hKeyChild) ;
    if (lRes != ERROR_SUCCESS)
    {
    return lRes ;
    }
     
    // Enumerate all of the decendents of this child.
    FILETIME time ;
    char szBuffer[256] ;
    DWORD dwSize = 256 ;
    while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
    NULL, NULL, &time) == S_OK)
    {
    // Delete the decendents of this child.
    lRes = DeleteKey(hKeyChild, szBuffer) ;
    if (lRes != ERROR_SUCCESS)
    {
    // Cleanup before exiting.
    RegCloseKey(hKeyChild) ;
    return lRes;
    }
    dwSize = 256 ;
    }
     
    // Close the child.
    RegCloseKey(hKeyChild) ;
     
    // Delete this child.
    return RegDeleteKey(hKeyParent, lpszKeyChild) ;
    }
     
    //
    // Create a key and set its value.
    //
    BOOL SetKeyAndValue(const char* szKey,
    const char* szSubkey,
    const char* szValue)
    {
    HKEY hKey;
    char szKeyBuf[1024] ;
     
    // Copy keyname into buffer.
    strcpy(szKeyBuf, szKey) ;
     
    // Add subkey name to buffer.
    if (szSubkey != NULL)
    {
    strcat(szKeyBuf, "\\") ;
    strcat(szKeyBuf, szSubkey ) ;
    }
     
    // Create and open key and subkey.
    long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
    szKeyBuf,
    0, NULL, REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS, NULL,
    &hKey, NULL) ;
    if (lResult != ERROR_SUCCESS)
    {
    return FALSE ;
    }
     
    // Set the Value.
    if (szValue != NULL)
    {
    RegSetValueEx(hKey, NULL, 0, REG_SZ,
    (BYTE *)szValue,
    strlen(szValue)+1) ;
    }
     
    RegCloseKey(hKey) ;
    return TRUE ;
    }
     
    com对象实现:dllmain.cpp
    #include "stdafx.h"
    #include <comutil.h>
    #include <stdio.h>
    #include "objbase.h"
    #include "olectl.h"
     
    #include "Factory.h"
    #include "Registry.h"
    #include "Object.h"
     
     
     
     
     
    ULONG g_LockNumber = 0;
    ULONG g_ObjectNumber = 0;
    HANDLE g_hModule;
     
     
    // {AAF8166B-826D-41F3-A035-A3D540AD418D}
    extern "C" const GUID CLSID_Object =
    { 0xaaf8166b, 0x826d, 0x41f3,
    { 0xa0, 0x35, 0xa3, 0xd5, 0x40, 0xad, 0x41, 0x8d } };
     
    extern "C" const GUID IID_Outer =
    { 0xaaf8166c, 0x826d, 0x41f3,
    { 0xa0, 0x35, 0xa3, 0xd5, 0x40, 0xad, 0x41, 0x8d } };
     
    BOOL APIENTRY DllMain( HMODULE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
    )
    {
     
    g_hModule = hModule;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    break;
    }
    return TRUE;
    }
     
     
    extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)
    {
    if(clsid == CLSID_Object)
    {
    CObjectFactory* pFactory = new CObjectFactory;
    if(pFactory == NULL) return E_OUTOFMEMORY;
     
    HRESULT result = pFactory->QueryInterface(iid, ppv);
    return result;
    }
    else return CLASS_E_CLASSNOTAVAILABLE;
    }
     
     
    extern "C" HRESULT __stdcall DllCanUnloadNow(void)
    {
    if((g_ObjectNumber == 0) && (g_LockNumber == 0)) return S_OK;
    else return S_FALSE;
    }
     
    extern "C" HRESULT __stdcall DllRegisterServer()
    {
    char szModule[1024];
    DWORD dwResult = ::GetModuleFileNameA((HMODULE)g_hModule, szModule, 1024);
    if(dwResult == 0) return SELFREG_E_CLASS;
     
    return RegisterServer(CLSID_Object, szModule, "Object.Object", "Object Component", NULL);
    }
     
    extern "C" HRESULT __stdcall DllUnregisterServer()
    {
    return UnregisterServer(CLSID_Object, "Object.Object", NULL);
    }
     
     
    CObject::CObject()
    {
    m_Ref = 0;
    g_ObjectNumber++;
    }
     
     
    CObject::~CObject()
    {
     
    }
     
     
    HRESULT CObject::QueryInterface(const IID& iid, void** ppv)
    {
    if(iid == IID_IUnknown)
    {
    *ppv = (IOuter*) this;
    ((IOuter*)(*ppv))->AddRef();
    }
    else if(iid == IID_Outer)
    {
    *ppv = (IOuter*) this;
    ((IOuter*)(*ppv))->AddRef();
    }
    else
    {
    *ppv = NULL;
    return E_NOINTERFACE;
    }
     
    return S_OK;
    }
     
     
    ULONG CObject::AddRef()
    {
    m_Ref++;
    return (ULONG) m_Ref;
    }
     
     
    ULONG CObject::Release()
    {
    m_Ref--;
    if(m_Ref == 0)
    {
    g_ObjectNumber--;
    delete this;
    return 0;
    }
     
    return (ULONG) m_Ref;
    }
     
     
    BOOL CObject::Outer()
    {
    printf("Hello World!");
    return true;
    }
     
    def模板实现:3_com.def
    LIBRARY "Object"
     
    EXPORTS
    DllGetClassObject PRIVATE
    DllCanUnloadNow PRIVATE
    DllRegisterServer PRIVATE
    DllUnregisterServer PRIVATE
     
    解释:当然这里建的工程是动态库工程。类厂中有两个额外的函数,一个是CreateInstance,另一个是LockServer。CreateInstance是用来生成com对象的,LockServer则是用来控制类厂的生成周期的。因为一个类厂可能对应多个对象,只有当所有的com对象都释放掉的时候,才能释放类厂。注册表那个Registry.h和Registry.cpp则是用来注册表用的,它是固定的,任何程序都可以用。当然根据经验,在用vs 2010 开发com程序的时候可能会报一些错,这些错误要么是头文件中少了"stdafx.h",要么就是编码问题,在项目属性里修改编码就能解决。最后完成之后,运行,将.dll注册到注册表,注册命令regsvr32.exe xx.dll。当然xx.dll前面要有路径。
     
     
    客户调用程序
     

     
    代码:
    接口声明:IOuter.h
    #ifndef __IOuter_H__
    #define __IOuter_H__
     
    #include "Unknwn.h"
     
    extern "C" const GUID IID_Outer;
     
    class IOuter : public IUnknown
    {
    public:
    virtual BOOL __stdcall Outer() = 0;
    };
     
    #endif
     
    调用:call.cpp
     
    #include "windows.h"
    #include <stdio.h>
    #include <comutil.h>
    #include <conio.h>
     
     
    #include "IOuter.h"
     
     
    /*extern "C" const GUID CLSID_Object =
    { 0xaaf8166b, 0x826d, 0x41f3,
    { 0xa0, 0x35, 0xa3, 0xd5, 0x40, 0xad, 0x41, 0x8d } };*/
     
    extern "C" const GUID IID_Outer =
    { 0xaaf8166c, 0x826d, 0x41f3,
    { 0xa0, 0x35, 0xa3, 0xd5, 0x40, 0xad, 0x41, 0x8d } };
     
     
    void main()
    {
    IUnknown* pUnknown;
    IOuter* pOuter;
    BOOL bResult;
    HRESULT hResult;
    GUID objectCLSID;
     
    if(CoInitialize(NULL) != S_OK)
    {
    printf("Initialize COM library failed!\n");
    return;
    }
     
    hResult = ::CLSIDFromProgID(L"Object.Object", &objectCLSID);
    if(hResult != S_OK)
    {
    printf("Can't find the Object CLSID!\n");
    return;
    }
     
    hResult = CoCreateInstance(objectCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**) &pUnknown);
    if(hResult != S_OK)
    {
    printf("Create object failed!\n");
    return;
    }
     
    hResult = pUnknown->QueryInterface(IID_Outer, (void**) &pOuter);
    if(hResult != S_OK)
    {
    pUnknown->Release();
    printf("QueryInterface IOuter failed!\n");
    return;
    }
     
    pUnknown->Release();
    pOuter->Outer();
    pOuter->Release();
     
    getch();
    return;
    }
     
    解释:CoInitialize这个是用来初始化com库的,在使用com库之前必须进行初始化。CLSIDFromProgID这个是根据注册表中的注册名字来获取com对象的唯一标识符。CoCreateInstance来生成com对象,并获得接口指针。
     
    运行结果:
     

  • 相关阅读:
    把一个数组 赋值给一个新数组
    上传图片时进行压缩
    input上传文件 显示进度条
    vue 后台接口返回文件流地址的下载
    时间戳转换
    JS 两个含有部分相同属性的对象如何快速给对应的key赋值
    javascript中把一个数组的内容全部赋值给另外一个数组
    微信小程序wxs如何使用
    优化内存
    解决position:fiexd相对父元素定位
  • 原文地址:https://www.cnblogs.com/waterhsu/p/com_library.html
Copyright © 2020-2023  润新知