在深入到教程第五步之前,让先花一点时间来揭开连接点的神秘面纱。图1展示了一个通用的场景,适用于COM、DCOM,甚至是函数回调。
图1:一个源和一个接收器。这涉及到两个对象,一个“源”和一个“接收器”。将“源”想象成家中厨房水槽的水龙头。转动把手,就会有东西流出来(希望是水)。它流向哪里?如果没有堵塞,水就会流到底部并进入排水口(可以想象成“接收器”)。在DCOM中,有一个“客户端”,在网络的某个地方,还有一个“服务器”,也在网络的某个地方。如果不使用连接点,事情只会单向流动:方法调用取代了水,客户端取代了水龙头,服务器取代了排水口。这大大简化了事情,但用户“转动把手”(例如,点击一个按钮),“东西”(即方法调用)“从”客户端“出来”。然后这些“出来的东西”通过DCOM在网络中“流动”。这些调用“流动”到服务器,服务器收集它们并像“排水口”或接收器一样工作。图2几乎和图1完全一样,但是把客户端放在了“源”的位置,服务器放在了“接收器”的位置,网络在中间:
图2:客户端和服务器作为源和接收器。现在有了像水一样流动的方法调用;很好。然而,当客户端调用方法时,服务器可能会做很多有趣的事情。所以服务器到处触发事件。如果客户端不在乎服务器触发事件,它就会忽略它们。然而,如果它在乎,它就会Advise()服务器。然后图2中的源-接收器关系可以反过来想象:
图3:图2的反面。连接点在有以下情况时出现:客户端是方法调用的源,服务器是方法调用的接收器。一个“事件调用”从现在的服务器-源出来。客户端接收事件调用并做一些事情。正如看到的,这是一个往返。一个方法调用从客户端到服务器,然后一个事件调用从服务器到客户端,如图4所示。
图4:一个往返。Advise()步骤是在上述第1项之前完成的,Unadvise()步骤(客户端变得冷漠)发生在第4项之后。客户端和服务器的接触点以及Advise()和Unadvise()的步骤一起形成了...一个连接点!!呼...真是一个启示...让开始第五步,在变得太激动之前...
第五步:将OnSayHello事件添加到事件源接口DHelloWorldEvents。让开始吧?要向源添加一个事件,真的,真的很容易。只需使用Visual C++向导!打开ClassView,右键单击DHelloWorldEvents图标,然后单击添加方法。添加方法到接口对话框出现。在方法名称框中键入OnSayHello,在参数框中键入[in] BSTR bstrHost,如图5所示。
图5:向DHelloWorldEvents事件接口添加OnSayHello()事件。完成后,单击确定。ClassView应该看起来像图6。现在单击FileView,找到HelloServ.idl文件,在源文件文件夹下。右键单击它,然后选择编译。观察编译器在输出窗口中的工作,并等待构建完成。
图6:添加OnSayHello事件后的ClassView。构建完成后,单击ClassView。右键单击CHelloWorld类,然后单击实现连接点。实现连接点对话框出现。如果还没有像告诉那样编译IDL文件,Visual C++会提示这样做。
图7显示了如何指定希望服务器能够触发其OnSayHello事件:图7。指定希望为DHelloWorldEvents事件接口实现连接点。当一切看起来像图7时,单击确定。Visual C++ IDE现在将为生成所有服务器端代码,需要连接点。每次更改DHelloWorldEvents事件接口中的事件,需要做(1)编译IDL,(2)右键单击CHelloWorld并选择实现连接点,(3)勾选DHelloWorldEvents旁边的复选框,(4)单击确定步骤。
STDMETHODIMP CHelloWorld::SayHello()
{
USES_CONVERSION;
//
获取此计算机的网络名称
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize = MAX_COMPUTERNAME_LENGTH +
1
;
if
(!GetComputerName(szComputerName, &dwSize))
return
E_FAIL;
//
未能获取此计算机的名称
//
向客户端说Hello
Fire_OnSayHello(T2OLE(szComputerName));
return
S_OK;
}