up
解决方案 »
- 用CMake编译时出错
- 实时监控当前活动的浏览器的url?
- VC 怎么使对话框全屏?(或者对话框最大化时盖住任务栏)
- VC调用.c文件的问题
- 打开dsw文件时如何弹出对话框加载另外一个dsp文件??
- 50分! 巨简单! 做一个对话框项目,上面放一个tab 控件,有两页,随便画点什么!
- 怎样让对话框里的一个STATIC控件的字体很大?
- 请问我在VC中从配置中读取中文信息为什么是乱码?是否编码方式被改,那应如何改过来呢?请大侠们指教
- 基础问题 .h与.cpp文件都什么时候调用?
- 关于CFile写入文件问题
- 谁有windows95程序设计指南(候杰的)a developer's guide (jeffrey richter)的源代码
- 在线等待,如何指定vc可以去寻找的头文件目录?
http://www.vckbase.com/document/viewdoc.asp?id=212
保你会COM编程,不过COM是一种思想,最重要的是理解COM思想
projectname_h:对接口的CLSID和IID定义
dlldata:生成代理文件需要dlldata.obj
然后编译代理文件,
语法 nmake -f projectnamePS.mk 需要dlldata.obj,projectname_i.obj,projectname_p.obj
2:客户端
#include "mfcserver_i.h" //对接口IAdd的描述
void CMFCClientDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
const IID IID_IAdd = {0x3F153D2D,0xF707,0x429B,0x97,0x69,0xED,0xD5,0xAE,0xF0,0x82,0x1E};//interface Id
const CLSID CLSID_Add ={0xE8B5BD5A,0xC013,0x44FA,0x99,0x8F,0x59,0xA5,0x00,0x4E,0xEC,0x77};//com class id
BSTR bstrHostName;
CString str;
str.Format("%s","192.168.0.2");
bstrHostName=str.AllocSysString();//为bstr类型分配内存
COSERVERINFO si;//设置服务器信息
si.dwReserved1=si.dwReserved2=0;
si.pwszName=bstrHostName;
si.pAuthInfo=NULL;
MULTI_QI mqi[1];
mqi[0].pIID=&IID_IAdd;
mqi[0].pItf=NULL;
mqi[0].hr=0;
IAdd *g=NULL;
CoInitialize(NULL);//初始化com资源,必须的 HRESULT hr;
hr=CoCreateInstanceEx(
CLSID_Add,
NULL,
CLSCTX_REMOTE_SERVER,
&si,
1,
mqi
);
if(hr!=S_OK)
MessageBox("create error!");
else
{
g=(IAdd *)mqi->pItf;
CoCreateInstance(CLSID_show,NULL,CLSCTX_LOCAL_SERVER,IID_Ishow,(void **)&p);
g->addvice(p);//传入回调函数
g->Add(8700,100);
g->AddRef();
}
CoUninitialize();//释放com资源
}
3:代理
nmake -f projectnamePS.mk生成.dll文件
用projectnamePS.dll注册
4:注册
EXE服务器注册:
exefilename.exe /regserver
exefilename.exe /unregserver
DLL代理注册:
regsvr32 dllfilename.dll
注意事项:
VC7.0的MFC生成的.mk文件需要复制以下代码覆盖以前的:
.c.obj:
cl /c /Ox /DWIN32 /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL \
$<
回调接口应将对接口的定义文件包含到IDL文件中,不然会遇到接口类型未知的错误。 可以在项目属性的[自定义生成步骤]中加入nmake -f projectnamePS.dll 输出为projectnamePS.dll 执行 编译
ATL远程服务器的注册:
1。运行com viewer改变对象的属性:把inproc server设为代理projectnamePS.dll
2。把代理进程改为 EXE服务器对应的位置
3。最后一步:运行dcomcnfg配置
a.运行DCOM服务器
b.默认身份验证级别改为 无
建议:
编写服务器部分应使用ATL编写,MFC嵌入ATL编程存在无法DCOM配置的问题
使用IDispatch接口,在传递过程中会出错。!!
客户端代码:
CoUninitialize();
CoUninitialize();
//将IP地址转换为BSTR 类型
BSTR bstrHostName;
CString m_IP;
m_IP.Format("%s","192.168.0.2");
bstrHostName=m_IP.AllocSysString();
//初始化服务器信息
COSERVERINFO si;
si.dwReserved1=si.dwReserved2=0;
si.pwszName=bstrHostName;
si.pAuthInfo=NULL;
//要获得的接口指针
MULTI_QI mqi[1];
mqi[0].pIID=&IID_IDual_str;
mqi[0].pItf=NULL;
mqi[0].hr=0;
//定义iGame接口
IDual_str *game=NULL;
GetDlgItem(IDC_SERVERSTATE)->SetWindowText("正在连接...");
HRESULT hr=CoCreateInstanceEx(CLSID_Dual_str,NULL,CLSCTX_REMOTE_SERVER,&si,1,mqi);
//处理返回
if(hr!=S_OK)
{
GetDlgItem(IDC_SERVERSTATE)->SetWindowText("连接失败");
}
else
{
game=(IDual_str *)mqi->pItf;
if(game==NULL){GetDlgItem(IDC_SERVERSTATE)->SetWindowText("无法连接");return;}
STR g;
game->getstr(&g);
MessageBox((char *)g.str);
game->Release();//释放COM对象
}
typedef struct
{
int l;
char df[200];
}MYSTRUCT;
2.建立客户端,复制IID,CLSID定义文件,并包含接口定义文件.c
这时使用OLE/COM viewer将该接口对象设置为LOCAL型,实现本地调用ocreateInstance(..LOCAL_SERVER..), 这时候还不能实现COM的远程调用,因为还没有注册代理/存根文件。3.编译代理文件,nmake -f ps.mk生成大约24k的ps.dll文件,然后用regsvr32 ps.dll注册它。
目前为止,已经可以运行客户程序,但是会出现乱字符等问题,代理没有正常运行,问题出在代理上,需要将返回的参数用[out]标记,这样汇集器便能正常工作了。
4.对注册表的修改,最好使用DCOMCNFG和OLE/COM viewer配置
(1)将接口对象的进程内服务器设为代理DLL文件
(2)将代理进程设为server.EXE文件,本地服务器可以不设
(3)修改DCOMCNFG,将DCOM设为[开启],默认身份验证为[无],模拟级别为匿名5.现在可以使用分布通信了,客户只要安装 代理和GUI 就可以了6.要在定制接口中使用字符串,必须在IDL文件中使用[string][in]
你用的是什么向导?
dll?
atl?
mfc?
对于理解com,编写com 可能会有帮助:
(转自:http://expert.csdn.net/Expert/topic/1334/1334607.xml?temp=.6936304)回复人: fanchka(狼仔) ( ) 信誉:100 2003-01-08 11:36:00 得分:0 to:HardWorking () 其实,这个问题就是对com的疑惑. 换句话说,既然有了dll,干吗还要com形式的dll?那偶就做个导游,说一些.
dll在传统的程序员眼里,就是一个建个win32 dll工程,写个dllmain(),写个
导出函数,一编译,就ok拉. 一个dll,是不是很简单? 确实,exe调用dll也是
很简单,它(dll)更象一个函数体,来供exe调用.当然,它们处在同一个进程内.好,下面就提问题了:我能不能写个第二版本的dll,来直接替换? 如果我导出的
是一个类的构造函数,和它的一个成员函数,并且再二版中,我又给它(类)加了
一个私有变量,这样直接替换行不行?先说问题1: 最终结果很难说. 你替换之后,可能会正常工作,可能会出现莫名其妙
的返回值,可能会死掉进程,可能会死机,可能会格式化硬盘...不可测. 你会问
为什么? 看第二个问题.问题2: 在版本1,我导出一个构造函数,和它的一个成员函数,在exe中,按常规
方式我把编译dll时的.h 和 .lib嵌入进来,编译好,运行正常. 好进行2版的
替换,我直接把dll复制过来,替换原先的dll. 假设,在exe中你是这样写的代码:
int main() {
CMydll mydll;
for(int i=0;i<10000;++i)
itest = mydll.MenberFunc();
... ...
}那么,for会进入死循环.(我测试过) 你会问 why?? i的 内存被重复i和
新添的哪个私有变量轮换霸占,它俩都在不断的写入自己的值. 死循环.你有会问,为什么? 记得你嵌入的.h 和.lib吗? exe在编译时期会根据这些
信息"决定CMydll对象的大小"! 记得咱们在 2版时加入的私有变量吧?
那么"CMydll对象的大小"变大了吧? 可是exe不知道啊,它很笨,还是按原先
的方式分内存的.... 悲剧如上上映. 你会问我,花了这么多口水,一个com没提,不是废话吗? com要解决的一个重
大问题,就是二进制的可替换性!! 那你又会问,上面这种问题如何解决?
呵呵,com来了,姗姗来迟的这种. 接口!! 什么是接口? (用c++说) 抽象基类.
里面全部是纯虚拟函数,没有任何成员变量. 有问,为什么要这样? c++编译器
厂商大战的结局. 那群乌鸦对类的内存分布,各持己见 (主指vtbl). 而有的
乌鸦,把成员变量放在内存虚拟表的首位,有的在末位...所以com不许有成员变量.如此以来,不仅解决了替换问题,还为跨语言,跨平台提供了基础. 继续.
为了在 真正意义上实现重用性,需要有种标准,不能a公司的代码,那到b公司
就不能用了,就出现了统一接口: IUnknown. 为了exe不管dll具体在什么位置
而能够调用,就采用了windows的注册表,和GUID. 为了实现跨编程语言,而
定义IDispatch. 为了实现远程调用,而用RPC和代理/存根.呼... 看看,Com的dll 和常见的dll,还有什么不同?
哦,com+ 和com的不同是: 通常的com对系统明显的依赖是注册表.
com+可多的多了. 它在com的基础上,进一步发展,为的是解决 同步,事务...
这些都要依靠win2k的鼎立支持: mts msmq... 诺,你看到了,尽是服务
(系统给的). 当然,com+为了能够利用这些服务,只有一个IUnknown和
IDispatch是不够的,它又开发了许多系统接口,象OC(组件对象环境)所拥有
的个个固定接口,咱们可以访问,当然.