作者 : 卿笃军

题目说明:

仿照例题,在其基础上实现下面功能:

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 Ock\CalcSvr\Debug

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.退出\n__\b\b";
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\n";
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.退出\n__\b\b";
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] = '\0';
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日

COM/DCOM开发练习之进程内组件实例的更多相关文章

  1. 【转载】进程内COM与进程外COM

    原文:http://www.cnblogs.com/jyz/archive/2009/03/08/1406229.html 1.进程内和进程外Com COM/DCOM 组件可以在DLL 或EXE 文档 ...

  2. 进程内COM与进程外COM

    1.进程内和进程外Com COM/DCOM 组件可以在DLL 或EXE 文档中实现. 其中在 DLL 中实现的COM/DCOM组件称为 In-Process Server,因为这些组件是加载到使用它们 ...

  3. 在VC6.0下如何调用Delphi5.0开发的进程内COM

    因为本人的语言水平很差,考大学时150的总分,我考了个60分.外语也是,初中及格过一次,会考及格过一次.其它的时间好像从没有及格过.所以我不写文章,因我一百字的文章给我写,至少要出八九个错别字.哈哈… ...

  4. Android开发-API指南-进程与线程

    Processes and Threads 英文原文:http://developer.android.com/guide/components/processes-and-threads.html ...

  5. android开发3:四大基本组件的介绍与生命周期

    android开发3:四大基本组件的介绍与生命周期 Android四大基本组件分别是Activity,Service服务,Content Provider内容提供者,BroadcastReceiver ...

  6. 自己实现一个Electron跨进程消息组件

    我们知道开发Electron应用,难免要涉及到跨进程通信,以前Electron内置了remote模块,极大的简化了跨进程通信的开发工作,但这也带来了很多问题,具体的细节请参与我之前写的文章: http ...

  7. Android源码——Activity进程内启动

    进程内启动Activity MainActivity组件向ActivityManagerService发送一个启动SubActivityInProcess组件的进程间通信请求: ActivityMan ...

  8. [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推)

    [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推) 内部推荐职位 高级JAVA技术经理: 岗位职责: 负责项目管理(技术方向),按照产品开发流 ,带领研发团队,制定 ...

  9. .NET跨平台实践:再谈用C#开发Linux守护进程

    Linux守护进程是Linux的后台服务进程,相当于Windows服务进程,对于为Linux开发服务程序的朋友来说,Linux守护进程相关技术是必不可少的,因为这个技术不仅仅是开发守护进程,还可以拓展 ...

随机推荐

  1. python网络编程--进程线程

    一:什么是进程 一个程序执行时的实例被称为一个进程. 每个进程都提供执行程序所需的资源.一个进程有一个虚拟地址空间.可执行代码.对系统对象的开放句柄.一个安全上下文.一个独特的进程标识符.环境变量.一 ...

  2. centos7联网

    一般centos安装(在虚拟机上安装)完成后需要自己配置服务,下面我就讲下如何配置 配置联网步骤 首先,打开虚拟机的两个服务,右击我的电脑-->管理--->找到服务-->右击启动 两 ...

  3. ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述

    ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述 Rviz Rviz是ROS数据可视化工具,可以将类似字符串文本等 ...

  4. C# 在RichTextBox根据内容自动调整高度

    private void richTextBox1_ContentsResized(object sender, ContentsResizedEventArgs e)   {   richTextB ...

  5. linux 101 hacks 第一章cd命令

    本系列来源于<linux 101 hacks>,作者还写了其他101 hacks教程,读了几章,觉得技巧都还不错,很实用,做个总结收藏. cdpath 设置基目录 [ramesh@dev- ...

  6. Numpy的简单用法

    Numpy的简单用法 import numpy as np 一.创建ndarray对象 列表转换成ndarray: >>> a = [1,2,3,4,5] >>> ...

  7. Winsock—I/O模型之选择模型(一)

    Winsock中提供了一些I/O模型帮助应用程序以异步方式在一个或多个套接字上管理I/O. 这样的I/O模型有六种:阻塞(blocking)模型,选择(select)模型,WSAAsyncSelect ...

  8. TCP、UDP、HTTP、SOCKET之间的区别与联系

    IP:网络层协议: TCP和UDP:传输层协议: HTTP:应用层协议: SOCKET:TCP/IP网络的API. TCP/IP代表传输控制协议/网际协议,指的是一系列协议. TCP和UDP使用IP协 ...

  9. 【*】Redis常见问题汇总

    1.什么是Redis? Redis是一个开源.高性能.基于键值对的缓存与存储系统. 2.Redis相比memcached有哪些优势? 劣势:Redis是单线程,Memcached是多线程,在多核服务器 ...

  10. 深度学习基础系列(十)| Global Average Pooling是否可以替代全连接层?

    Global Average Pooling(简称GAP,全局池化层)技术最早提出是在这篇论文(第3.2节)中,被认为是可以替代全连接层的一种新技术.在keras发布的经典模型中,可以看到不少模型甚至 ...