如何从COM库中将引用作为参数传递给COM接口?
以下是样本:
1)客户端代码成功创建了coclass并在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 :(得分:1)
这个blog post解释了为什么你遇到这个问题,pointer_default(unique)不能做你想象的那样。使用[unique]将子类别参数归类。
答案 1 :(得分:1)
如果我告诉你已经知道的事情,请道歉。
在RPC(和COM)中,proxy是客户端在调用远程过程时实际调用的代码段。代理通常编组输入参数,然后将请求发送到服务器,其中一段代码stub解组参数,然后使用它们来调用被调用的实际过程。
当被调用的过程返回结果时,存根调整out参数和结果,并将响应发送回代理,代理又解组out参数等,并将它们交还给客户端。
无论如何,这是一般模型,事情有时被优化掉(例如,在进程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为您的FunctionDiscovery类执行Iuncnknown for CFunctionInstanceCollection的完整实现。
更新3/16
为了完整起见,我可能还应该提到,以你的方式分配* ppIFunctionInstanceCollection是有效的,但一般来说可能存在风险。
您已经编写了CFunctionInstanceCollection类,因此您知道它直接实现了IFunctionInstanceCollection接口,因此您知道您的分配是安全的。但是在更常见的情况下,你没有编写类,CFunctionInstanceCollection类可能会做一些不太直接的事情 - 例如它可能聚合一些其他实现接口的类。要真正安全,您应该使用QueryInterface来检索IFunctionInstanceCollection接口指针。