DCOM 揭秘之四
2014-01-09 17:49
232 查看
我们已经讨论了DCOM的基本要点,了解了如何创建一个简单的DCOM服务器和一个相关的客户端。你也可以看到这个基本的过程是非常简单的---ATL向导处理了服务器端的大部分细节,要激活服务器,你只需要在客户端写10行左右的代码就可以了。
接下来我们将讨论两个相关的主题。首先是创建你自己的COM客户和服务器,结合第一部分我们所学到的,让你了解要在自己的代码中集成一个DCOM服务器,确实需要做哪些事情。然后我们将快速地看一下由ATL向导产生的代码。
本文的最后将会讲解要创建一个分布式的COM服务器,你需要经过的步骤。所谓分布式的COM服务器,是指该服务器可以处在网络的别处,并且可通过网络非常简单和透明地激活。
创建自己的COM客户和服务器
在第一部分的DCOM介绍中,你可以看到要创建COM客户和服务器是非常简单的。只要在客户和服务器端写入几行代码就可以产生一个完整的COM应用。你现在明白到为什么许多的开发者在创建一个DLL时会使用COM了--因为仅需要大概5分钟,就可以设置好一个进程内的COM DLL,并且令它工作。
本部分的目的是讨论如何创建自己的COM服务器,并且在你创建的真正应用中使用它们。你也会记得,第一部分介绍的客户端代码是非常少的。我们将介绍要创建服务器需要进行的基本步骤,然后看看要正确地激活服务器,你需要在客户端写入哪些代码。
服务器端
ATL向导令COM服务器的创建变得非常的简单。创建一个COM coclass的第一步是要分离出一个或者多个的功能函数,你要从一个应用的代码主体中分离出这些功能函数。至于分离出来的目的,可以是多样的,你可能是想让该函数可以跨越多个应用重新使用,也可能是让一个队伍的编程者更容易地分离出各个独立的工作组,或者是让代码的开发和维护变得更加的简单。不论是出于什么原因,定义功能是第一步。
有一点可能令定义这些边界变得更为简单,这就是COM服务器的运作和一个普通的C++类是几乎一样的。象一个类,你实例化一个COM类,然后可以开始调用它的方法。COM的实例化和方法调用的句法和C++是有点不同的,不过它们的想法是一样的。如果一个服务器仅有一个接口,它事实上的用法就相当于一个类。(不过在访问对象时,你仍然需要遵守COM的规定)
一旦你已经定义了功能和访问它的方法,就可以建立自己的服务器。在第一部分中,我们已经知道,要创建一个服务器,有4个基本的步骤:
1。使用ATL向导来创建你的COM服务器的外壳。你选择该服务器是一个DLL、一个EXE或者是一个服务。
2。在服务器的外壳中创建一个新的COM对象。你将要选择线程的模式,这将会创建可装入方法的接口。
3。在你的对象中加入方法,并且声明它们的参数
4。为你的方法写代码
上面的这些步骤已经在第一部分中的“理解一个简单的COM服务器”中详细介绍过了。
经过第一部分的介绍后,一个常见的问题是关于线程模式,也就是COM对象的独立线程(apartment-threade)和自由线程(free-threaded)之间的区别?要理解它们之间的区别的最简单方法是将独立线程看成为单线程,而将自由线程想象为多线程。
在独立线程中,多个服务器客户的方法调用在服务器端的COM对象中被串行化,也就是说,每个独立的方法调用完成后,才会开始下一个的方法调用。因此独立线程的COM对象天生就是线程安全的,而自由线程的COM对象可同时在COM对象上有多个的方法调用执行。每个客户的方法调用都在一个不同的线程中运行。因此,在一个自由线程的COM对象中,你必须要注意多线程的问题,例如同步。
开始的时候你将更趋向于使用独立的线程,因为它更加简单,不过以后最好转向到自由线程,因为它有着更多的优点。
客户端
第一部分介绍的客户端程序非常清楚和紧凑。不过,它包含很少的错误检测代码,因此要在一个真正的程序中应用是不足够的。让我们再次看一下这些代码,它非常简单,因此可让你清楚地看到要创建一个客户端的必要步骤。
CoInitialize和CoCreateInstance的调用初始化COM,并且得到指向一个接口的指针。然后你就可以调用接口的方法。在完成方法调用后,你就可释放接口并且调用CoUninitialize。整个步骤就完成了。
不过,在一个COM客户尝试启动一个COM服务器时,可出现各种不同的错误。一些常见的问题包括有:
. 客户端不能启动COM
. 客户端不能查找到请求的服务器
. 客户端能查找到请求的服务器,但是不能正确地启动
. 客户端不能找到请求的接口
. 客户端不能找到请求的方法
. 客户端可以找到请求的方法,但在调用时失败
. 客户端不能正确地清除
为了跟踪这些潜在的问题,你必须在每一步作检查,具体是查看HRESULT的值。以上的代码有作检查,不过在出错的时候并没提示。以下的函数补救了这个不足:
该函数拆除了HRESULT的值,并且打印出它的所有成员,包括有极为有用的英语错误信息值ErrorMessage。你可以在任何的时候调用它:
// display HRESULT on screen
ShowStatus( hr );
要完整了解一个简单的COM程序可产生的不同错误模式,以下的客户端解释代码使用了一个MFC对话框应用,可让你控制一些可能的错误信息,并且看到该信息如何影响HRESULT的值。客户端的运行如图1所示。
*************图一*************
左边的单选按钮可让你选择各种的错误,包括有缺少CoInitialize函数,一个错误的class ID,以及一个错误的接口ID。如果你按下运行的按钮,在右边你将可看到客户端的不同函数返回的不同错误对HRESULT的值的影响。
在你使用该例子中的客户端代码时,你将会发现该版本要比我们原来使用的标准客户端代码强壮。它还允许通过DCOM作远程连接。例如,它使用CoInitializeSecurity函数来设置默认的安全性,它还使用CoCreateInstanceEx函数以便另一台机器上的远程服务器可以被调用。研究一下这些代码,在文档中查找这两个函数,你将会惊奇地发现要理解它是非常简单的,你终于对COM有了一些了解。
接下来我们将讨论两个相关的主题。首先是创建你自己的COM客户和服务器,结合第一部分我们所学到的,让你了解要在自己的代码中集成一个DCOM服务器,确实需要做哪些事情。然后我们将快速地看一下由ATL向导产生的代码。
本文的最后将会讲解要创建一个分布式的COM服务器,你需要经过的步骤。所谓分布式的COM服务器,是指该服务器可以处在网络的别处,并且可通过网络非常简单和透明地激活。
创建自己的COM客户和服务器
在第一部分的DCOM介绍中,你可以看到要创建COM客户和服务器是非常简单的。只要在客户和服务器端写入几行代码就可以产生一个完整的COM应用。你现在明白到为什么许多的开发者在创建一个DLL时会使用COM了--因为仅需要大概5分钟,就可以设置好一个进程内的COM DLL,并且令它工作。
本部分的目的是讨论如何创建自己的COM服务器,并且在你创建的真正应用中使用它们。你也会记得,第一部分介绍的客户端代码是非常少的。我们将介绍要创建服务器需要进行的基本步骤,然后看看要正确地激活服务器,你需要在客户端写入哪些代码。
服务器端
ATL向导令COM服务器的创建变得非常的简单。创建一个COM coclass的第一步是要分离出一个或者多个的功能函数,你要从一个应用的代码主体中分离出这些功能函数。至于分离出来的目的,可以是多样的,你可能是想让该函数可以跨越多个应用重新使用,也可能是让一个队伍的编程者更容易地分离出各个独立的工作组,或者是让代码的开发和维护变得更加的简单。不论是出于什么原因,定义功能是第一步。
有一点可能令定义这些边界变得更为简单,这就是COM服务器的运作和一个普通的C++类是几乎一样的。象一个类,你实例化一个COM类,然后可以开始调用它的方法。COM的实例化和方法调用的句法和C++是有点不同的,不过它们的想法是一样的。如果一个服务器仅有一个接口,它事实上的用法就相当于一个类。(不过在访问对象时,你仍然需要遵守COM的规定)
一旦你已经定义了功能和访问它的方法,就可以建立自己的服务器。在第一部分中,我们已经知道,要创建一个服务器,有4个基本的步骤:
1。使用ATL向导来创建你的COM服务器的外壳。你选择该服务器是一个DLL、一个EXE或者是一个服务。
2。在服务器的外壳中创建一个新的COM对象。你将要选择线程的模式,这将会创建可装入方法的接口。
3。在你的对象中加入方法,并且声明它们的参数
4。为你的方法写代码
上面的这些步骤已经在第一部分中的“理解一个简单的COM服务器”中详细介绍过了。
经过第一部分的介绍后,一个常见的问题是关于线程模式,也就是COM对象的独立线程(apartment-threade)和自由线程(free-threaded)之间的区别?要理解它们之间的区别的最简单方法是将独立线程看成为单线程,而将自由线程想象为多线程。
在独立线程中,多个服务器客户的方法调用在服务器端的COM对象中被串行化,也就是说,每个独立的方法调用完成后,才会开始下一个的方法调用。因此独立线程的COM对象天生就是线程安全的,而自由线程的COM对象可同时在COM对象上有多个的方法调用执行。每个客户的方法调用都在一个不同的线程中运行。因此,在一个自由线程的COM对象中,你必须要注意多线程的问题,例如同步。
开始的时候你将更趋向于使用独立的线程,因为它更加简单,不过以后最好转向到自由线程,因为它有着更多的优点。
客户端
第一部分介绍的客户端程序非常清楚和紧凑。不过,它包含很少的错误检测代码,因此要在一个真正的程序中应用是不足够的。让我们再次看一下这些代码,它非常简单,因此可让你清楚地看到要创建一个客户端的必要步骤。
void main() { HRESULT hr; // COM error code IBeepDllObj *IBeep; // pointer to interface hr = CoInitialize(0); // initialize COM if (SUCCEEDED(hr)) // macro to check for success { hr = CoCreateInstance( clsid, // COM class id NULL, // outer unknown CLSCTX_INPROC_SERVER, // server INFO iid, // interface id (void**)&IBeep ); // pointer to interface if (SUCCEEDED(hr)) { hr = IBeep-Beep(800); // call method hr = IBeep-Release(); // release interface } CoUninitialize(); // close COM } |
不过,在一个COM客户尝试启动一个COM服务器时,可出现各种不同的错误。一些常见的问题包括有:
. 客户端不能启动COM
. 客户端不能查找到请求的服务器
. 客户端能查找到请求的服务器,但是不能正确地启动
. 客户端不能找到请求的接口
. 客户端不能找到请求的方法
. 客户端可以找到请求的方法,但在调用时失败
. 客户端不能正确地清除
为了跟踪这些潜在的问题,你必须在每一步作检查,具体是查看HRESULT的值。以上的代码有作检查,不过在出错的时候并没提示。以下的函数补救了这个不足:
// This function displays detailed // information contained in an HRESULT. BOOL ShowStatus(HRESULT hr) { // construct a _com_error using the HRESULT _com_error e(hr); // The hr as a decimal number cout << "hr as decimal: " << hr << endl; // show the 1st 16 bits (SCODE) cout << "SCODE: " << HRESULT_CODE( hr ) << endl; // Show facility code as a decimal number cout << "Facility: " << HRESULT_FACILITY( hr ) << endl; // Show the severity bit cout << "Severity: " << HRESULT_SEVERITY( hr ) << endl; // Use the _com_error object to format a message string. // This is much easier then using ::FormatMessage cout << "Message string: " << e.ErrorMessage() << endl; return TRUE; } |
// display HRESULT on screen
ShowStatus( hr );
要完整了解一个简单的COM程序可产生的不同错误模式,以下的客户端解释代码使用了一个MFC对话框应用,可让你控制一些可能的错误信息,并且看到该信息如何影响HRESULT的值。客户端的运行如图1所示。
*************图一*************
左边的单选按钮可让你选择各种的错误,包括有缺少CoInitialize函数,一个错误的class ID,以及一个错误的接口ID。如果你按下运行的按钮,在右边你将可看到客户端的不同函数返回的不同错误对HRESULT的值的影响。
在你使用该例子中的客户端代码时,你将会发现该版本要比我们原来使用的标准客户端代码强壮。它还允许通过DCOM作远程连接。例如,它使用CoInitializeSecurity函数来设置默认的安全性,它还使用CoCreateInstanceEx函数以便另一台机器上的远程服务器可以被调用。研究一下这些代码,在文档中查找这两个函数,你将会惊奇地发现要理解它是非常简单的,你终于对COM有了一些了解。
相关文章推荐
- MFC程序的启动与死亡顺序:
- 78. Domino Designer 9.0.1升级无忧!
- 关于属性的书写
- matlab函数interp2及其c++代码
- Linux操作系统安装方法
- vi应用小记
- matlab函数interp2及其c++代码
- MipcaActivityCapture代码阅读------surfaceview的生命周期
- Spark 源码分析 -- BlockStore
- myeclipse安装flex插件后代码无自动提示及自动补全无效的解决办法
- Android自定义属性
- SQL Server 2005 安装遇到的错误提示和解决方法
- Linux操作系统怎么样
- android调用高版本api函数的兼容性问题
- redis常用操作
- OpenCascade Modeling Algorithms Fillets and Chamfers
- 【笔记】【从Android Guide温习Android 一】进程和线程(Process And thread)
- linux操作系统
- ubutun apache源码完整安装过程
- ccccc