标准MFC WinSock ActiveX控件开发实例.docx

上传人:b****4 文档编号:4344303 上传时间:2022-11-30 格式:DOCX 页数:13 大小:238.87KB
下载 相关 举报
标准MFC WinSock ActiveX控件开发实例.docx_第1页
第1页 / 共13页
标准MFC WinSock ActiveX控件开发实例.docx_第2页
第2页 / 共13页
标准MFC WinSock ActiveX控件开发实例.docx_第3页
第3页 / 共13页
标准MFC WinSock ActiveX控件开发实例.docx_第4页
第4页 / 共13页
标准MFC WinSock ActiveX控件开发实例.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

标准MFC WinSock ActiveX控件开发实例.docx

《标准MFC WinSock ActiveX控件开发实例.docx》由会员分享,可在线阅读,更多相关《标准MFC WinSock ActiveX控件开发实例.docx(13页珍藏版)》请在冰豆网上搜索。

标准MFC WinSock ActiveX控件开发实例.docx

标准MFCWinSockActiveX控件开发实例

摘要:

本文主要介绍如何开发一个ActiveX控件,提供接口,与相应事件挂钩。

文中涉及到VARIANT,SAFEARRAY,BSTR的详细使用方法。

另外还提供了WinSock的详细开发步骤,以及如何响应网络超时,网络断开的事件方法以及在VC,VB调用该控件的方法。

关键字:

ActiveX,Socket,VARIANT,SAFEARRAY,BSTR。

一、MFCActiveX控件开发步骤(VC6.0):

1.New->Projects->MFCActiveXControlWizard,然后输入MFCWinSock工程名。

如下图:

图一创建工程

2.一路狂按Next,直至Finsh出现,再按下OK,如下图:

   

图二创建完成

二、架设Socket环境:

1.首先在StdAfx.h文件中加入下面这句代码:

#include//MFCsocketextensions

2.打开MFCWinSock.cpp文件,添加代码,看起来如下:

////////////////////////////////////////////////////////////////////////////

//CMFCWinSockApp:

:

InitInstance-DLLinitialization

BOOLCMFCWinSockApp:

:

InitInstance()

{

BOOLbInit=COleControlModule:

:

InitInstance();

if(bInit)

{

//TODO:

Addyourownmoduleinitializationcodehere.

if(!

AfxSocketInit())

{

AfxMessageBox("无法初始化Socket,请检查!

");

returnFALSE;

}

WSADATAwsaData;

WORDwVersion=MAKEWORD(1,1);//设定为Winsock1.1版

interrCode;

errCode=WSAStartup(wVersion,&wsaData);//启动Socket服务

if(errCode)

{

AfxMessageBox("无法找到可以使用的WSOCK32.DLL");

returnFALSE;

}

}

returnbInit;

}

 

////////////////////////////////////////////////////////////////////////////

//CMFCWinSockApp:

:

ExitInstance-DLLtermination

intCMFCWinSockApp:

:

ExitInstance()

{

//TODO:

Addyourownmoduleterminationcodehere.

WSACleanup();//结束网络服务

returnCOleControlModule:

:

ExitInstance();

}

三,提供控件接口和事件

1.在MFCWinSockCtl.cpp加入如下代码:

2.#ifndefWM_MYWINSOCK

3.#defineWM_MYWINSOCKWM_USER+1888

4.#endif

5.View->ClassWizard->Automation->AddMethod…如下图:

图三创建接口

这个时候,我们为这个控件添加了一个Connect()的接口,出于通用性,安全性和扩展性的考虑,我们采用了VARIANT类型的参数,

很多人可能都不太了解该类型,又或者有接触过,但被吓怕了,那么我们来看清它的本来面目:

6.structtagVARIANT

7.{

8.union

9.{

10.struct__tagVARIANT

11.{

12.VARTYPEvt;

13.WORDwReserved1;

14.WORDwReserved2;

15.WORDwReserved3;

16.union

17.{

18.LONGlVal;

19.BYTEbVal;

20.SHORTiVal;

21.FLOATfltVal;

22.DOUBLEdblVal;

23.VARIANT_BOOLboolVal;

24._VARIANT_BOOLbool;

25.SCODEscode;

26.CYcyVal;

27.DATEdate;

28.BSTRbstrVal;

29.IUnknown__RPC_FAR*punkVal;

30.IDispatch__RPC_FAR*pdispVal;

31.SAFEARRAY__RPC_FAR*parray;

32.BYTE__RPC_FAR*pbVal;

33.SHORT__RPC_FAR*piVal;

34.LONG__RPC_FAR*plVal;

35.FLOAT__RPC_FAR*pfltVal;

36.DOUBLE__RPC_FAR*pdblVal;

37.VARIANT_BOOL__RPC_FAR*pboolVal;

38._VARIANT_BOOL__RPC_FAR*pbool;

39.SCODE__RPC_FAR*pscode;

40.CY__RPC_FAR*pcyVal;

41.DATE__RPC_FAR*pdate;

42.BSTR__RPC_FAR*pbstrVal;

43.IUnknown__RPC_FAR*__RPC_FAR*ppunkVal;

44.IDispatch__RPC_FAR*__RPC_FAR*ppdispVal;

45.SAFEARRAY__RPC_FAR*__RPC_FAR*pparray;

46.VARIANT__RPC_FAR*pvarVal;

47.PVOIDbyref;

48.CHARcVal;

49.USHORTuiVal;

50.ULONGulVal;

51.INTintVal;

52.UINTuintVal;

53.DECIMAL__RPC_FAR*pdecVal;

54.CHAR__RPC_FAR*pcVal;

55.USHORT__RPC_FAR*puiVal;

56.ULONG__RPC_FAR*pulVal;

57.INT__RPC_FAR*pintVal;

58.UINT__RPC_FAR*puintVal;

59.struct__tagBRECORD

60.{

61.PVOIDpvRecord;

62.IRecordInfo__RPC_FAR*pRecInfo;

63.}__VARIANT_NAME_4;

64.}__VARIANT_NAME_3;

65.}__VARIANT_NAME_2;

66.DECIMALdecVal;

67.}__VARIANT_NAME_1;

68.};

它先是一个结构体,里面有一个重要成员VARTYPEvt;vt即是指明当前的数据类型,比如整型或者字符型,当指明vt后,

后面看到各种变量类型包括在一个联合体当中,也就是说指明vt后,你只能使用对应的其中之一变量类型。

看着这众多的各种不同

类型变量集中在一起,确实让人吓了一跳,但细细看来,大多数变量跟我们平时的用法相似。

值得一提的是SAFEARRAY__RPC_FAR*parray;

也许有很多人还没有接触过SAFEARRAY类型的变量,SAFEARRAY实际上也是一个结构,大家可以参考MSDN,我也将在后面介绍它的具体使用方法。

69.用同样的方法创建DisConnect()接口

70.创建两个事件,FireCloseWinsock()响应网络断开事件,FireRecvSockEvent()响应网络有数据到达的事件。

创建方法如下图:

图四创建事件

71.重载控件消息处理函数WindowProc(),在View->ClassWizard中打开类向导,在消息映射中找到WindowProc,如下图:

图五重载WindowProc()

四、编写代码

1.编写VariantToLong()转换函数,该函数代码如下:

2.//类型转换,将VARIANT类型转换成Long类型

3.longCMFCWinSockCtrl:

:

VariantToLong(constVARIANT&var)

4.{

5.longr;

6.switch(var.vt)

7.{

8.caseVT_UI2:

//USHORT

9.r=var.uiVal;

10.break;

11.caseVT_UI4:

//ULONG

12.r=var.ulVal;

13.break;

14.caseVT_INT:

//INT

15.r=var.intVal;

16.break;

17.caseVT_UINT:

//UINT

18.r=var.uintVal;

19.break;

20.caseVT_I4:

//LONG

21.r=var.lVal;

22.break;

23.caseVT_UI1:

//BYTE

24.r=var.bVal;

25.break;

26.caseVT_I2:

//SHORT

27.r=var.iVal;

28.break;

29.caseVT_R4:

//FLOAT

30.r=(long)var.fltVal;

31.break;

32.caseVT_R8:

//DOUBLE

33.r=(long)var.dblVal;

34.break;

35.default:

36.r=-1;//无法转换该值

37.break;

38.}

39.returnr;

40.}

41.

大家可以看到,该函数将最基本的若干中数据类型转换成了long类型,但VARIANT决不是个简单的谱,我将在后面继续揭开它的神秘面纱.

42.编写我们刚才的接口Connect(),代码代码如下:

在MFCWinSockCtrl.h中加入

43.SOCKETOnlySock;//建立的唯一Socket,不允许重复建立多个

44.boolisOnlyConnect;//是否建立了连接

然后再编写Connect(),看起来如下:

BOOLCMFCWinSockCtrl:

:

Connect(constVARIANTFAR&RemoteHost,constVARIANTFAR&RemotePort)

{

//TODO:

Addyourdispatchhandlercodehere

if(isOnlyConnect)//该连接已建立,还没有断开

returnFALSE;

CStringIPAddress;

intPort;//转换成整型的端口

switch(RemoteHost.vt)

{

caseVT_BSTR:

//字符串型

IPAddress=CString(RemoteHost.bstrVal);

break;

caseVT_BYREF|VT_I1:

//CHAR*

IPAddress.Format("%s",RemoteHost.pcVal);//RemoteHost.pbstrVal);

break;

default:

IPAddress="";

returnFALSE;

}

Port=VariantToLong(RemotePort);//我们编写的一个VARIANT转换成long类型的函数

if(Port<=0)

returnFALSE;

_TCHAR*ip=0;

structhostent*host=0;

structsockaddr_inaddr;

ULONGdotIP=inet_addr(IPAddress);

OnlySock=socket(AF_INET,SOCK_STREAM,0);

//判断是否为点IP地址格式

if(OnlySock==INVALID_SOCKET)

{

shutdown(OnlySock,0x02);

closesocket(OnlySock);//释放占有的SOCK资源

returnFALSE;

}

memset(&addr,0,sizeof(structsockaddr_in));

//设定SOCKADDR_IN结构的内容

//如果通讯协议是选择IPProtocol,那此值固定为AF_INET

//AF_INET与PF_INET这两个常量值相同

addr.sin_family=AF_INET;

addr.sin_port=htons(Port);

addr.sin_addr.S_un.S_addr=dotIP;

if(dotIP==INADDR_NONE)

{

host=gethostbyname(IPAddress);

if(!

host)

{

shutdown(OnlySock,0x02);

closesocket(OnlySock);//释放占有的SOCK资源

returnFALSE;

};

ip=inet_ntoa(*(structin_addr*)(*host->h_addr_list));

addr.sin_addr.S_un.S_addr=inet_addr(ip);

}

//开始连线

if(connect(OnlySock,(LPSOCKADDR)&addr,sizeof(SOCKADDR)))

{

shutdown(OnlySock,0x02);

closesocket(OnlySock);//释放占有的SOCK资源

returnFALSE;

}

intiError=WSAAsyncSelect(OnlySock,m_hWnd,WM_MYWINSOCK,FD_READ|FD_CLOSE);//只对网络断开和数据到达通知感兴趣

if(iError==SOCKET_ERROR)//无法绑定Winsock的事件通知

{

shutdown(OnlySock,0x02);

closesocket(OnlySock);//释放占有的SOCK资源

returnFALSE;

}

isOnlyConnect=true;

returnTRUE;

}

有必要提一下WSAAsyncSelect(),这里接收网络数据到达和断开的两个消息,我们收到WM_MYWINSOCK消息时将处理该消息并作为事件传送给调用者.

第二个参数,窗口句柄,我们传送了m_hWnd,这是因为MFCActiveX也属于一个窗口,并且是可见的,因此可以成功。

45.编写WindowProc(),代码看起来如下:

46.LRESULTCMFCWinSockCtrl:

:

WindowProc(UINTmessage,WPARAMwParam,LPARAMlParam)

47.{

48.//TODO:

Addyourspecializedcodehereand/orcallthebaseclass

49.switch(message)

50.{

51.caseWM_MYWINSOCK:

//响应自定义的消息

52.switch(WSAGETSELECTEVENT(lParam))

53.{

54.caseFD_READ:

//有新数据到达

55.FireRecvSockEvent();

56.break;

57.caseFD_CLOSE:

//对方已断掉当前连接

58.FireCloseWinsock();

59.break;

60.}

61.break;

62.default:

63.break;

64.}

65.returnCOleControl:

:

WindowProc(message,wParam,lParam);

66.}

本部分结束语:

好了,现在一个可以运行的控件已经完成,里面提供有Connect()和DisConnect()接口,和RecvSockEvent()及CloseWinsock()事件。

以及WinSock的使用方法。

在下一部分(高级篇)将讲解两个重要接口SendData()和GetData(),下期内容如下:

1.longSendData(constVARIANTFAR&Data,constVARIANTFAR&DataType,constVARIANTFAR&DataLength,constVARIANTFAR&TimeOut)

2.longGetData(VARIANTFAR*Data,constVARIANTFAR&DataType,constVARIANTFAR&DataMaxLength,constVARIANTFAR&TimeOut)

3.VARIANT和SAFEARRAY的复杂用法。

4.控件开发出来后在VC和VB环境下的使用方法。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1