设置我的 ATL COM 回调函数
Setting up my ATL COM callback functions
作为 的后续,我有以下 CerberusNative.idl
文件(这是一个用 Visual C++ 编写的 ATL 项目,它公开了一个 COM 对象):
[
object,
uuid(AECE8D0C-F902-4311-A374-ED3A0EBB6B49),
nonextensible,
pointer_default(unique)
]
interface ICallbacks : IUnknown
{
[id(1)] HRESULT UserExit([in] int errorCode, [in] BSTR errorMessage);
[id(2)] HRESULT UserAttemptingReconnection();
[id(3)] HRESULT UserReconnected();
};
[
object,
uuid(B98A7D3F-651A-49BE-9744-2B1D8C896E9E),
dual,
nonextensible,
pointer_default(unique)
]
interface ICerberusSession : IDispatch {
...
[id(5)] HRESULT SetCallbacks([in] ICallbacks* callbacks);
};
我正在尝试创建一个接口来设置回调方法,该回调方法从 COM 对象路由回调用方所述方法的实现。
我正在尝试 运行 以下代码:
HRESULT prolonguedDisconnection(int code, BSTR *message) {
std::wcout << code << ": " << message << std::endl;
}
HRESULT reconnecting() {
std::wcout << "Reconnecting." << std::endl;
}
HRESULT reconnected() {
std::wcout << "Reconnected." << std::endl;
}
...
CoInitialize(NULL);
CerberusNativeLib::ICallbacksPtr callbacks;
callbacks.CreateInstance(__uuidof(CerberusNativeLib::ICallbacks));
callbacks->UserExit = prolonguedDisconnection;
callbacks->UserAttemptingReconnection = reconnecting;
callbacks->UserReconnected = reconnected;
CerberusNativeLib::ICerberusSessionPtr session;
session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
session->SetCallbacks(callbacks);
但是,我不确定如何正确设置回调方法。关于如何做到这一点的任何想法?我在 callbacks->UserExit = prolonguedDisconnection;
:
等行收到此编译器错误
Error C2659 '=': function as left operand
您将 ICallbacks
定义为接口,实现 ICerberusSession
的对象接受 ICallbacks
指针,以便它可以调用某些事件的回调。这是一个很好的设计并且效果很好。但是,它通常假设您的代码(底部的最后一个代码片段)像您一样通过 CreateInstance
实例化会话对象,并且在您这边实现了另一个带有回调方法的接口。
您的代码实现了一个 COM 对象,该对象又实现了 ICallbacks
。您创建此类 COM 对象的实例(尤其是没有 CoCreateInstace
- 它通常是您这边的客户端代码),然后将 ICallbacks
接口作为参数传递给 SetCallbacks
调用。请注意,不涉及分配。期望会话对象进行调用,例如ICallbacks::UserExit
在提供的指针上,这就是您的代码通过回调接口接收控制的方式 - ICallbacks
的客户端代码实现调用了其 UserExit
方法。
我只需要在单独的 class:
中实现接口
class Callbacks : public CerberusNativeLib::ICallbacks {
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(IID, IID_ICallbacks, 0xAECE8D0C, 0xF902, 0x4311, 0xA3, 0x74, 0xED, 0x3A, 0x0E, 0xBB, 0x6B, 0x49);
public:
HRESULT(*user_exit) (int, BSTR) = NULL;
HRESULT(*user_attempting_reconnection) () = NULL;
HRESULT(*user_reconnected) () = NULL;
Callbacks::Callbacks(HRESULT(*disconnected)(int, BSTR), HRESULT(*reconnecting)(), HRESULT(*reconnected)()) : m_cRef(0) {
user_exit = disconnected;
user_attempting_reconnection = reconnecting;
user_reconnected = reconnected;
}
HRESULT __stdcall UserExit(int ErrorCode, BSTR ErrorMessage) {
return user_exit(ErrorCode, ErrorMessage);
}
HRESULT __stdcall UserAttemptingReconnection() {
return user_attempting_reconnection();
}
HRESULT __stdcall UserReconnected() {
return user_reconnected();
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) {
if (!ppvObject)
return E_INVALIDARG;
*ppvObject = NULL;
if (riid == IID_IUnknown || riid == IID_ICallbacks)
{
*ppvObject = (LPVOID)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() {
InterlockedIncrement(&m_cRef);
return m_cRef;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG ulRefCount = InterlockedDecrement(&m_cRef);
if (0 == m_cRef)
delete this;
return ulRefCount;
}
private:
ULONG m_cRef;
};
然后,使用它:
HRESULT result = CoInitialize(NULL);
if (result != S_OK)
{
std::wcout << "Failed to initialize the COM library on the current thread or to identify the concurrency model as single-thread apartment (STA)." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
Callbacks *callbacks = new Callbacks(&prolonguedDisconnection, &reconnecting, &reconnected);
CerberusNativeLib::ICerberusSessionPtr session;
result = session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
if (result != S_OK)
{
std::wcout << "Failed to create a new Cerberus session." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
result = session->SetCallbacks(callbacks);
if (result != S_OK)
{
std::wcout << "Failed to set Cerberus session callbacks." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
作为 CerberusNative.idl
文件(这是一个用 Visual C++ 编写的 ATL 项目,它公开了一个 COM 对象):
[
object,
uuid(AECE8D0C-F902-4311-A374-ED3A0EBB6B49),
nonextensible,
pointer_default(unique)
]
interface ICallbacks : IUnknown
{
[id(1)] HRESULT UserExit([in] int errorCode, [in] BSTR errorMessage);
[id(2)] HRESULT UserAttemptingReconnection();
[id(3)] HRESULT UserReconnected();
};
[
object,
uuid(B98A7D3F-651A-49BE-9744-2B1D8C896E9E),
dual,
nonextensible,
pointer_default(unique)
]
interface ICerberusSession : IDispatch {
...
[id(5)] HRESULT SetCallbacks([in] ICallbacks* callbacks);
};
我正在尝试创建一个接口来设置回调方法,该回调方法从 COM 对象路由回调用方所述方法的实现。
我正在尝试 运行 以下代码:
HRESULT prolonguedDisconnection(int code, BSTR *message) {
std::wcout << code << ": " << message << std::endl;
}
HRESULT reconnecting() {
std::wcout << "Reconnecting." << std::endl;
}
HRESULT reconnected() {
std::wcout << "Reconnected." << std::endl;
}
...
CoInitialize(NULL);
CerberusNativeLib::ICallbacksPtr callbacks;
callbacks.CreateInstance(__uuidof(CerberusNativeLib::ICallbacks));
callbacks->UserExit = prolonguedDisconnection;
callbacks->UserAttemptingReconnection = reconnecting;
callbacks->UserReconnected = reconnected;
CerberusNativeLib::ICerberusSessionPtr session;
session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
session->SetCallbacks(callbacks);
但是,我不确定如何正确设置回调方法。关于如何做到这一点的任何想法?我在 callbacks->UserExit = prolonguedDisconnection;
:
Error C2659 '=': function as left operand
您将 ICallbacks
定义为接口,实现 ICerberusSession
的对象接受 ICallbacks
指针,以便它可以调用某些事件的回调。这是一个很好的设计并且效果很好。但是,它通常假设您的代码(底部的最后一个代码片段)像您一样通过 CreateInstance
实例化会话对象,并且在您这边实现了另一个带有回调方法的接口。
您的代码实现了一个 COM 对象,该对象又实现了 ICallbacks
。您创建此类 COM 对象的实例(尤其是没有 CoCreateInstace
- 它通常是您这边的客户端代码),然后将 ICallbacks
接口作为参数传递给 SetCallbacks
调用。请注意,不涉及分配。期望会话对象进行调用,例如ICallbacks::UserExit
在提供的指针上,这就是您的代码通过回调接口接收控制的方式 - ICallbacks
的客户端代码实现调用了其 UserExit
方法。
我只需要在单独的 class:
中实现接口class Callbacks : public CerberusNativeLib::ICallbacks {
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(IID, IID_ICallbacks, 0xAECE8D0C, 0xF902, 0x4311, 0xA3, 0x74, 0xED, 0x3A, 0x0E, 0xBB, 0x6B, 0x49);
public:
HRESULT(*user_exit) (int, BSTR) = NULL;
HRESULT(*user_attempting_reconnection) () = NULL;
HRESULT(*user_reconnected) () = NULL;
Callbacks::Callbacks(HRESULT(*disconnected)(int, BSTR), HRESULT(*reconnecting)(), HRESULT(*reconnected)()) : m_cRef(0) {
user_exit = disconnected;
user_attempting_reconnection = reconnecting;
user_reconnected = reconnected;
}
HRESULT __stdcall UserExit(int ErrorCode, BSTR ErrorMessage) {
return user_exit(ErrorCode, ErrorMessage);
}
HRESULT __stdcall UserAttemptingReconnection() {
return user_attempting_reconnection();
}
HRESULT __stdcall UserReconnected() {
return user_reconnected();
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) {
if (!ppvObject)
return E_INVALIDARG;
*ppvObject = NULL;
if (riid == IID_IUnknown || riid == IID_ICallbacks)
{
*ppvObject = (LPVOID)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() {
InterlockedIncrement(&m_cRef);
return m_cRef;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG ulRefCount = InterlockedDecrement(&m_cRef);
if (0 == m_cRef)
delete this;
return ulRefCount;
}
private:
ULONG m_cRef;
};
然后,使用它:
HRESULT result = CoInitialize(NULL);
if (result != S_OK)
{
std::wcout << "Failed to initialize the COM library on the current thread or to identify the concurrency model as single-thread apartment (STA)." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
Callbacks *callbacks = new Callbacks(&prolonguedDisconnection, &reconnecting, &reconnected);
CerberusNativeLib::ICerberusSessionPtr session;
result = session.CreateInstance(__uuidof(CerberusNativeLib::CerberusSession));
if (result != S_OK)
{
std::wcout << "Failed to create a new Cerberus session." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}
result = session->SetCallbacks(callbacks);
if (result != S_OK)
{
std::wcout << "Failed to set Cerberus session callbacks." << std::endl;
std::wcout << result << ": " << _com_error(result).ErrorMessage() << std::endl;
std::wcout << "Press the enter key to exit." << std::endl;
std::cin.get();
return 0;
}