2011-03-13 35 views
2

如何从COM库中将引用作为参数传递给COM接口?从COM库传递对COM接口的引用

这里的样品:

1)客户端代码成功地创建组件类和接收接口指针在pFunctionDiscovery如下:

hr = CoCreateInstance(
     __uuidof(FunctionDiscovery), 
     NULL, 
     CLSCTX_INPROC_SERVER, 
     __uuidof(IFunctionDiscovery), 
     (LPVOID*)&pFunctionDiscovery); 

if (FAILED(hr)) 
{ 
    TRACE_MESSAGE(Error,"Failed to get IFunctionDiscovery COM %08x\n",hr); 
    goto Exit; 
} 

2)pFunctionDiscovery的立即呼叫的成员函数,如下给出错误消息: 800706f4,它对应于一个空引用指针被传递给存根。

hr = pFunctionDiscovery->GetInstanceCollection(
     FCTN_CATEGORY_DEVICEDISPLAYOBJECTS, 
     NULL, 
     FALSE, 
     &pFICollection); 

3)COM库写入与ATL库的援助,代码如下:

// The module attribute is specified in order to implement DllMain, 
// DllRegisterServer and DllUnregisterServer 
[ module(dll, name = "MyServer", helpstring = "MyServer 1.0 Type Library") ]; 
[ emitidl ]; 

///////////////////////////////////////////////////////////////////////////// 

// IFunctionInstanceCollection interface 
[ 
    object, 
    uuid("F0A3D895-855C-42A2-948D-2F97D450ECB1"), 
    oleautomation, 
    helpstring("IFunctionInstanceCollection Interface"), 
    pointer_default(unique) 
] 
__interface IFunctionInstanceCollection : IUnknown 
{ 
public: 
    virtual HRESULT STDMETHODCALLTYPE GetCount(__RPC__out DWORD *pdwCount) = 0; 
}; 


// IFunctionDiscovery interface 
[ 
    object, 
    uuid("4df99b70-e148-4432-b004-4c9eeb535a5e"),\ 
    oleautomation, 
    helpstring("IFunctionDiscovery Interface"), 
    pointer_default(unique) 
] 
__interface IFunctionDiscovery : IUnknown 
{ 
    virtual HRESULT GetInstanceCollection(
     __RPC__in_string const WCHAR* functionCategory, 
     __RPC__in_opt_string const WCHAR* subcategory, 
     BOOL fIncludeAllSubCategories, 
     __RPC__deref_out_opt IFunctionInstanceCollection **ppIFunctionInstanceCollection 
     ) = 0; 
}; 


///////////////////////////////////////////////////////////////////////////// 
// FunctionDiscovery class 
[ 
    coclass, 
    threading(apartment), 
    vi_progid("FunctionDiscovery.Discovery"), 
    progid("FunctionDiscovery.Discovery.1"), 
    version(1.0), 
    uuid("C72BE2EC-8E90-452c-B29A-AB8FF1C071FC"), 
    helpstring("FunctionDiscovery Class") 
] 
class ATL_NO_VTABLE FunctionDiscovery : 
    public IFunctionDiscovery 
{ 
public: 
    FunctionDiscovery() {}; 
    virtual ~FunctionDiscovery(){}; 

    virtual HRESULT GetInstanceCollection(
     __RPC__in_string const WCHAR* functionCategory, 
     __RPC__in_opt_string const WCHAR* subcategory, 
     BOOL fIncludeAllSubCategories, 
     __RPC__deref_out_opt IFunctionInstanceCollection **ppIFunctionInstanceCollection 
     ) 
    { 
     printf("GetInstanceCollection called"); 
     return 0; 
    } 
    DECLARE_PROTECT_FINAL_CONSTRUCT() 
    HRESULT FinalConstruct() 
    { 
     return S_OK; 
    } 

    void FinalRelease() 
    { 
    } 

    static BOOL DllMainAttach(); 
    static void DllMainDetach(); 
}; 

请让我知道问题出在哪里?

感谢 尼克

好了,路过一个非空字符串从客户端调用,运行良好。我将对象分配给* ppIFunctionInstanceCollection的方式如下:

在服务器端,我声明了一个像这样的新类,并从GetInstanceCollection中创建一个对象。当客户端调用GetInstanceCOllection时,返回该创建的对象。我确实在服务器端获得了一个有效的实例,但在客户端,它显示为NULL。

1)

class CFunctionInstanceCollection : public IFunctionInstanceCollection 
{ 
public: 
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID IID, void **pv) throw() 
    { return 0; }; 
    ULONG STDMETHODCALLTYPE AddRef(void) throw() 
    { return 0; }; 
    ULONG STDMETHODCALLTYPE Release(void) throw() 
    { return 0; }; 
    virtual HRESULT STDMETHODCALLTYPE GetCount(__RPC__out DWORD *pdwCount) 
    { return 10; }; 
}; 

2)从内GetInstanceCollection,我做的:

*ppIFunctionInstanceCollection = new CFunctionInstanceCollection();

我希望CFunctionInstanceCollection的)上述分配有效的实例为GetInstanceCollection的最后一个参数(方法,它是* ppIFunctionInstanceCollection。我已经在服务器端验证了这一点,并且它打印了有效指针,其中类的大小为4(虚拟函数的存在使类大小为4)。

但在客户端,值为NULL。我认为在客户端/服务器之间传递参数更多。如果你看到其他东西,请让我知道。谢谢!!!

+0

非常感谢汉斯编辑代码!我是COM新手,也是这个组。我现在知道发布代码格式。 – Nick 2011-03-13 01:03:35

回答

1

这个blog post解释了为什么你有这个问题,pointer_default(唯一)不会做你认为它的作用。使用[unique]来指定子类别参数。

+0

我以后通过博客获得了关于参数的“唯一”关键字,但没有任何区别。感谢指针。 你能告诉我如何将接口指针传递给'GetInstanceCollection'吗?这是我的问题: - 我正在使用ATL库和C++编码COM服务器。无法创建接口实例。那么,我该如何将指针传递给一个有效的实例作为COM客户端调用的GetInstanceCollection的最后一个参数呢? 感谢 -Nick – Nick 2011-03-14 06:00:54

0

道歉,如果我告诉你你已经知道的事情。

在RPC(和COM)中,proxy是客户端在调用远程过程时实际调用的代码片段。代理通常编组输入参数,然后将请求发送到服务器,在那里一段名为stub的代码取消编组参数,然后使用它们调用正在调用的实际过程。

当被调用的过程返回一个结果时,存根会封送出参数和结果,并将该响应发送回代理,然后解析出参数等。并把它们交还给客户。

这无论如何是一般模型,事情有时优化掉(例如,在过程中的COM对象的情况下)在这种情况下,可能不存在一个实际的存根和实际代理。不过,这是我们可以用来了解“代理”和“存根”的背景。

的“空引用的指针传递给存根”错误表明问题是在存根(即,服务器)侧发生。可能传递给存根的两段代码是代理,GetInstanceCollection的实现更可能是罪魁祸首。

我怀疑你的问题是,GetInstanceCollection实现不赋值给* ppIFunctionInstanceCollection。

尝试添加代码GetInstanceCollection返回之前分配* ppIFunctionInstanceCollection。


更新3/15

你更新getCount将实施返回值10。但是,将被解释为HRESULT 10未计数值10 getCount将的实施真的应该是这个样子这...

virtual HRESULT STDMETHODCALLTYPE GetCount(__RPC__out DWORD *pdwCount) 
{ 
    *pdwCount = 10; 
    return S_OK; 
}; 

这就是说,它真的是没有接到虚了IUnknown方法(的QueryInterface,AddRef和Release),因为你可以打破各种事情出乎意料地是个好主意。例如,每次调用GetInstanceCollection时,程序都会泄漏一个CFunctionInstanceCollection实例,因为它会被创建并且永远不会销毁。

你的代码对于一个实验来说是可以的,但最好使用ATL为CFunctionInstanceCollection完全实现IUnknown,就像你为你的FunctionDiscovery类一样。


更新3/16

为了完整起见,我应该还提到,分配* ppIFunctionInstanceCollection你的方式是有效的,但在一般的潜在的风险。

你写的CFunctionInstanceCollection类,所以你知道它直接实现IFunctionInstanceCollection接口,让你知道你的任务是安全的。但是在更一般的情况下,如果你没有编写这个类,那么CFunctionInstanceCollection类可能会做一些不那么简单的事情 - 例如它可能会聚合一些实现接口的其他类。要真的很安全,你应该使用QueryInterface来检索IFunctionInstanceCollection接口指针。

+0

感谢您的代理/存根介绍。这是我的怀疑,我试图解决创建 – Nick 2011-03-13 04:55:06

+0

我意识到这个问题的问题,但你能告诉我如何将一个接口指针传递给“GetInstanceCollection”? - 我使用ATL库和C++编码COM服务器。无法创建接口实例。那么,我该如何将指针传递给一个有效的实例作为COM客户端调用的GetInstanceCollection的最后一个参数呢? 感谢 -Nick – Nick 2011-03-14 06:04:47

+0

我们可以在这里绊倒术语,但客户不应该一个指针传递给一个有效的实例作为GetInstanceCollection的最后一个参数。从函数名称和参数定义中,它看起来像GetInstanceCollection函数是为了返回指向最后一个参数中有效实例的指针。 – 2011-03-14 18:52:15