• COM/DCOM开发练习之进程内组件实例


    作者 : 卿笃军


    题目说明:

    仿照例题,在其基础上实现下面功能:
    1)使用C++语言实现进程内组件,组件提供复数的加、减、乘、除等计算服务;client部分包含录入(实部和虚部分开录入)和查询部分。


    2)在VC++环境上利用ATL向导进行开发。


    3)至少实现三种执行模式中的两种。


    4) 程序设计风格良好,有文档凝视,方法凝视,语句凝视。并附带说明文档。
    5)下周六晚10点前统一发至我邮箱。


    开工、首先编写server端利用ATL COM AppWizard开发出 CalcSvr.dll

    第一步:打开VC++6.0选择 ATL COM AppWizard ,然后在project名处输入 CalcSvr  文件夹我们这里选择  E:Ock  

    点击确定。进入下一步后,所有默认,点击完毕!


    第二步:開始创建我们的ATL类了,其作用就是实现.dll的功能。

    点击插入->类    例如以下图:



    然后,開始创建ATL类,类的类型选择 ATL Class,类名称我这里输入CCalcMath。其他不要动,点击确定。


    第三步:加入类方法,看到刚才创建的那个CCalcMath类了吧?右击ICalcMath然后选择Add Method加入方法。


    第四步:输入类名和类參数,注意这里类參数直接用逗号分开即可了,也不须要写成例如以下形式:

    [in] int Num1, [in] int Num2, [out] int *result

    这个[in],[out]是VS里面的。VS里面是设计成了复选框,直接点击的。


    自己仿照上面的加法操作。将减法,乘法。除法,素数~~所有加入好。


    须要注意的是,类參数时依据你自己的须要设定的。比方,你推断一个数字是不是素数,这时候仅仅须要两个參数,一个传进来,一个表示传出结果。


    第五步:实现类功能。类已经所有加入好了,我们如今实现一下类功能就OK了。

    点击InterfaceSupportsErrorInfo能够进入实现页面,当然,你也能够直接点击CCalcMath.cpp


    第六步:分别实现 Add(), Sub(),Mul(), Div(),Sushu() 加,减,乘,除,素数这4个函数的功能:

    以下是所有实现代码,事实上就加入了几行代码~~~你仅仅须要看着四个函数里面加入的内容即可了。

    由于以下的代码,非常多是类向导自己主动生成的。

    // CalcMath.cpp : Implementation of CCalcSvrApp and DLL registration.
    #include "stdafx.h"
    #include "CalcSvr.h"
    #include "CalcMath.h"
    #include <math.h>
    
    /////////////////////////////////////////////////////////////////////////////
    //
    
    STDMETHODIMP CCalcMath::InterfaceSupportsErrorInfo(REFIID riid)
    {
    	static const IID* arr[] = 
    	{
    		&IID_ICalcMath,
    	};
    
    	for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
    	{
    		if (InlineIsEqualGUID(*arr[i],riid))
    			return S_OK;
    	}
    	return S_FALSE;
    }
    
    STDMETHODIMP CCalcMath::Add(double Num1, double Num2, double *result)
    {
    	// TODO: Add your implementation code here
    	*result = Num1 + Num2;
    	return S_OK;
    }
    
    STDMETHODIMP CCalcMath::Sub(double Num1, double Num2, double *result)
    {
    	// TODO: Add your implementation code here
    	*result = Num1 - Num2;
    	return S_OK;
    }
    
    STDMETHODIMP CCalcMath::Mul(double Num1, double Num2, double *result)
    {
    	// TODO: Add your implementation code here
    	*result = Num1 * Num2;
    	return S_OK;
    }
    
    STDMETHODIMP CCalcMath::Div(double Num1, double Num2, double *result)
    {
    	// TODO: Add your implementation code here
    	if (Num2 != 0)
    		*result = Num1 / Num2;
    	return S_OK;
    }
    
    STDMETHODIMP CCalcMath::Sushu(int Num, int *result)
    {
    	// TODO: Add your implementation code here
    	int i = 0;
    
    	for(i = 2; i <= sqrt(Num); i++)   //记得加上 #include <math.h>
        {
            if((Num % i) == 0)
    		{
                *result = 0;    //0表示非素数
    			break;
    		}
        }
    	if (i > sqrt(Num))
    		*result = 1;        //1表示是素数
    
    	return S_OK;
    }
    第七步:编译->链接。好了,我们的server端已经编写好了。

    这时候,你在project文件夹以下的Debug里面会看到CalcSvr.dll,同一时候注意上面的路径。由于你如今要手动注冊CalcSvr.dll


    第八步:注冊CalcSvr.dll。

    调出dos窗体。你能够按住win+R呼出执行,或者直接在開始栏里面点击执行,然后输入 cmd


    运行注冊的时候,须要注意.dll的路径

    首先。进入dll所在的那个磁盘。如我的在E盘,则输入例如以下:

    E:

    然后进入对应的目录,cd表示进入该目录~,输入例如以下命令:

    cd OckCalcSvrDebug


    server端。我们已经编写好了,以下我们来编写client。

    这里就不用MFC了,为了简洁明了起见,直接创建一个win32控制台应用程序。win32控制台应用程序详细创建不说了。仅仅要写过Hello World的都会。


    以下编写client应用程序。

    第一步:win32控制台应用程序 project命名为 CalcClient,然后创建C++ Source File的时候也命名为:CalcClient.cpp。


    第二步:将開始我们编写server端的时候,project文件夹下的CalcSvr.h 和 CalcSvr_i.c两个文件拷贝过来,放在clientproject文件夹以下。


    第三步:在CalcClient.cpp里面。编写client详细实现代码。

    #include <windows.h>
    #include <iostream>
    #include "CalcSvr.h"
    #include "CalcSvr_i.c"
    using namespace std;
    
    template< class T >   //函数模板
    void show( T t )
    {
    	cout << t << endl;
    }
    
    void DCOM()
    {  
    	double data = 0.0;
    	int flag = 0;
    	double a = 0.0, b = 0.0;
    	//初始化COM库
    	HRESULT hr=::CoInitialize(NULL);   //用来告诉Windows以单线程的方式创建COM对象
    	if( !SUCCEEDED( hr ) )
    	{
    		show( "init right failed!" );
    	}
    	ICalcMath *plRF = NULL;
    	hr=::CoCreateInstance(CLSID_CalcMath,NULL,CLSCTX_INPROC_SERVER,IID_ICalcMath,(LPVOID *)&plRF);//用指定的类标识符在本地创建一个未初始化的COM对象
    	if(FAILED(hr))
    	{
    		cout<<"创建组件实例失败"<<endl;
    	}
    	//调用方法
    	cout<<"请选择:1.加;2.减。3.乘;4.除;5.推断素数(注:1表示素数;0表示非素数);0.退出
    __";
    	cin>>flag;
    	while(flag!=0)
    	{
    		switch(flag)
    		{
    		case 1:  
    			{
    				cout<<"请输入要相加的两个数字:" ;
    				cin>>a>>b;
    				plRF->Add(a,b,&data);
    				cout<<"计算结果为:";
    				show( data );
    				break;
    			}
    		case 2:  
    			{
    				cout<<"请输入要相减的两个数字:" ;
    				cin>>a>>b;
    				plRF->Sub(a,b,&data);
    				cout<<"计算结果为:";
    				show( data );
    				break;
    			}
    		case 3: 
    			{
    				cout<<"请输入要相乘的两个数字:" ;
    				cin>>a>>b;
    				plRF->Mul(a,b,&data);
    				cout<<"计算结果为:";
    				show( data );
    				break;
    			}
    		case 4:  
    			{
    				cout<<"请输入要相除的两个数字:" ;
    				cin>>a>>b;
    				if (b-0<1e-5 || 0-b>1e-5)
    				{
    					cout<<"除数不能为0
    ";
    					break;
    				}
    				plRF->Div(a,b,&data);
    				printf("计算结果为:");
    				show( data );
    				break;
    			}
    		case 5:  
    			{
    				cout<<"请输入要进行推断的数字:" ;
    				cin>>a;
    				plRF->Sushu((int)a,(int *)&data);
    				cout<<"推断结果为:";
    				show( data );
    				break;
    			}
    		case 0:break;
    		default:break;
    		}
    		system("pause");
    		system("cls");
    		cout<<"请选择:1.加;2.减;3.乘。4.除;5.推断素数(注:1表示素数;0表示非素数);0.退出
    __";
    		cin>>flag;
    	}
    	plRF->Release();
    	CoUninitialize(); //CoUninitialize关闭当前线程的COM库,卸载线程载入的全部dll,释放不论什么其它的资源,关闭在线程上维护全部的RPC连接。
    }
    int main()
    {
    	DCOM();
    	
    	return 0;
    }
    /*
    ps:
    //#define _WIN32_DCOM //#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM
    */
    第四步:编译->链接->执行。



    附带说明一下关于.dll的自己主动注冊。

    问:既然,能够进入CMD手动注冊dll,那么为什么我们不实现自己主动注冊呢?


    我的.dll被我复制到例如以下文件夹里面了~~以下的说明所有是针对这一文件夹路径的。

    答:事实上自己主动注冊很easy,在主函数里面调用一条例如以下DOS命令即可了:

     system("regsvr32 E:\Ock\CalcClient\CalcSvr.dll /s"); 
    说明:上面的红色字体是路径(注意'\',双斜杠)。 /s表示不弹出注冊成功与否的提示。

    (曾经手动注冊的时候,注冊成功不是还弹出一个对话框吗?/s就是屏蔽这个的)。

    问:可是,这里又遇到一个问题了,将程序移植到别人的电脑上面,路径就不同了~~~
    答:这个问题不难解决呀,曾经不是学过int main()函数传參吗?还记得吧?看看以下这个能想起来么?
    int main(int argc, char *argv[])
    {
    	puts(argv[0]);
    
    	return 0;
    }
    对了。argv[0]打印出来的就是.exe的运行路径了。那这样就好办了。

    以下就是改好后的代码了~~~实现了自己主动注冊.dll
    void regsvr32(char *path)
    {
    	int i = 0, count = 0;
    	char buf[100], regPath[100];
    
    	//找到倒数第二个  反斜杠的位置
    	for (i = strlen(path); i >= 0; --i)
    	{
    		if (path[i] == '\')        
    		{
    			++count;
    			if (count == 2)
    				break;
    		}
    	}
    	strncpy(buf,path,i);   //拷贝出 路径的前 i 位
    	buf[i] = '';
    	sprintf(regPath,"regsvr32 %s\CalcSvr.dll /s",buf); //格式化路径 
    	system(regPath);       //运行注冊 .dll
    }
    
    int main(int argc, char *argv[])
    {
    	
    	regsvr32(argv[0]);   //自己主动注冊
    	DCOM();
    	
    	return 0;
    }
    假设不清楚main參数问题,我的另外一篇博客:http://blog.csdn.net/qingdujun/article/details/24844597 第10个问题中有说明~~~


    參考文献:qipanlimingCSDN博客的专栏。COM/DCOM开发练习之进程内组件实例。http://blog.csdn.net/lican19911221/article/details/7459983。2014年5月13日

  • 相关阅读:
    【业务自动化】iTop,全面支持ITIL流程的一款ITSM工具
    【Hadoop】HDFS源码解读
    【Hadoop】Hadoop RPC框架线程模型
    电商网站项目(一)用户模块---门户
    jdk1.5后枚举类的定义规则
    回顾static与final的作用
    @Springboot搭建项目controller层接收json格式的对象失败
    把一个文件中所有文件名或者文件路径读取到一个txt文件,然后在matlab中读取
    springboot用mybatis-generator自动生成mapper和model
    hibernate、mybatis、spring data 的对比
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5394300.html
Copyright © 2020-2023  润新知