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 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个问题中有说明~~~




本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5394300.html,如需转载请自行联系原作者 
相关文章
|
27天前
|
监控 C++
C++ Qt开发:QProcess进程管理模块
Qt是一个跨平台的C++图形库,简化了窗体应用开发,支持通过拖放组件提升效率。本章节关注`QProcess`组件,它用于控制和管理进程,例如执行命令、运行可执行文件及与外部进程通信。`QProcess`提供多种方法如`start`、`waitForStarted`和`waitForFinished`等,实现启动、监控和交互。示例展示了如何使用`QProcess`获取系统进程和信息,通过`tasklist`和`systeminfo`命令,并将结果展示在`QTreeWidget`中。
28 0
C++ Qt开发:QProcess进程管理模块
|
4月前
|
Windows
5.4 Windows驱动开发:内核通过PEB取进程参数
PEB结构`(Process Envirorment Block Structure)`其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附加进程并遍历这段结构即可得到非常多的有用信息。在应用层下,如果想要得到PEB的基地址只需要取`fs:[0x30]`即可,TEB线程环境块则是`fs:[0x18]`,如果在内核层想要得到应用层进程的PEB信息我们需要调用特定的内核函数来获取。
48 0
5.4 Windows驱动开发:内核通过PEB取进程参数
|
4月前
|
监控 安全 API
7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中`LyShark`一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以`监控进程线程`创建为例,在`Win10`系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原理是创建一个回调事件,当有进程或线程被创建或者注销时,系统会通过回调机制将该进程相关信息优先返回给我们自己的函数待处理结束后再转向系统层。
57 0
7.1 Windows驱动开发:内核监控进程与线程回调
|
4月前
|
存储 Windows
4.6 Windows驱动开发:内核遍历进程VAD结构体
在上一篇文章`《内核中实现Dump进程转储》`中我们实现了ARK工具的转存功能,本篇文章继续以内存为出发点介绍`VAD`结构,该结构的全程是`Virtual Address Descriptor`即`虚拟地址描述符`,VAD是一个`AVL`自`平衡二叉树`,树的每一个节点代表一段虚拟地址空间。程序中的代码段,数据段,堆段都会各种占用一个或多个`VAD`节点,由一个`MMVAD`结构完整描述。
36 0
4.6 Windows驱动开发:内核遍历进程VAD结构体
|
4月前
|
存储 数据安全/隐私保护 Windows
4.5 Windows驱动开发:内核中实现进程数据转储
多数ARK反内核工具中都存在驱动级别的内存转存功能,该功能可以将应用层中运行进程的内存镜像转存到特定目录下,内存转存功能在应对加壳程序的分析尤为重要,当进程在内存中解码后,我们可以很容易的将内存镜像导出,从而更好的对样本进行分析,当然某些加密壳可能无效但绝大多数情况下是可以被转存的。
24 0
4.5 Windows驱动开发:内核中实现进程数据转储
|
4月前
|
监控 Windows
4.4 Windows驱动开发:内核监控进程与线程创建
当你需要在Windows操作系统中监控进程的启动和退出时,可以使用`PsSetCreateProcessNotifyRoutineEx`函数来创建一个`MyCreateProcessNotifyEx`回调函数,该回调函数将在每个进程的创建和退出时被调用。PsSetCreateProcessNotifyRoutineEx 用于在系统启动后向内核注册一个回调函数,以监视新进程的创建和退出,
39 0
4.4 Windows驱动开发:内核监控进程与线程创建
|
4月前
|
监控 安全 Windows
4.3 Windows驱动开发:监控进程与线程对象操作
在内核中,可以使用`ObRegisterCallbacks`这个内核回调函数来实现监控进程和线程对象操作。通过注册一个`OB_CALLBACK_REGISTRATION`回调结构体,可以指定所需的回调函数和回调的监控类型。这个回调结构体包含了回调函数和监控的对象类型,还有一个`Altitude`字段,用于指定回调函数的优先级。优先级越高的回调函数会先被调用,如果某个回调函数返回了一个非NULL值,后续的回调函数就不会被调用。当有进程或线程对象创建、删除、复制或重命名时,内核会调用注册的回调函数。回调函数可以访问被监控对象的信息,如句柄、进程ID等,并可以采取相应的操作,如打印日志、记录信息等。
26 0
4.3 Windows驱动开发:监控进程与线程对象操作
|
28天前
|
Unix Shell Linux
Linux 终端和进程的关系,以及在终端前后台切换进程
Linux 终端和进程的关系,以及在终端前后台切换进程
27 1
|
27天前
|
存储 Shell Linux
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
37 0
|
27天前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 向进程发送信号 kill命令 使用指南
【Shell 命令集合 系统管理 】⭐⭐⭐Linux 向进程发送信号 kill命令 使用指南
31 0

相关实验场景

更多