回顧:在上一篇文章《标準MFC WinSock ActiveX控件開發執行個體》中我們詳細介紹了控件的開發過程,以及接口和事件的添加和響應方法。現在我們将繼續上次沒有寫完的控件繼續進行開發,并完善作為一個WinSock控件應該具備的功能。
二、按照前一篇文章提到的知識,現在我們來添加兩個新的接口分别是SendData()和GetData(),它們看起來如下:
01.
//網絡資料發送,在指定的逾時時間内進行發送然後傳回,成功傳回實際發送位元組數,否則傳回負數
02.
long
CMFCWinSockCtrl::SendData(
const
VARIANT FAR& Data,
03.
const
VARIANT FAR& DataType,
04.
const
VARIANT FAR& DataLength,
05.
const
VARIANT FAR& TimeOut)
06.
{
07.
// TODO: Add your dispatch handler code here
08.
09.
return
0;
10.
}
11.
12.
//擷取資料,并指定擷取資料的逾時時間,傳回實際擷取到的資料長度,否則傳回負數
13.
long
CMFCWinSockCtrl::GetData(VARIANT FAR* Data,
14.
const
VARIANT FAR& DataType,
15.
const
VARIANT FAR& DataMaxLength,
16.
const
VARIANT FAR& TimeOut)
17.
{
18.
// TODO: Add your dispatch handler code here
19.
20.
return
0;
21.
}
兩個接口的參數除了第一個參數外,其它都類似。SendData()是發送資料,不要求将資料帶回,是以直接用 VARIANT,而GetData()則要求将資料帶回來給調用者,是以定義為 VARIANT *類型,第二個參數DataType故名思義是定義所傳送或接收資料的類型,第三個參數是傳送或接收資料的長度,這裡的長度以char作為一個長度,假如傳入的類型是int類型,則長度為4,如果定義的是字元串,一個中文字元占用2個長度。最後一個參數,是網絡發送或讀取時的逾時時間。
三、為Connect()接口添加源代碼,看起來如下:
01.
//網絡資料發送,在指定的逾時時間内進行發送然後傳回,成功傳回實際發送位元組數,否則傳回負數
02.
long
CMFCWinSockCtrl::SendData(
const
VARIANT FAR& Data,
03.
const
VARIANT FAR& DataType,
04.
const
VARIANT FAR& DataLength,
05.
const
VARIANT FAR& TimeOut)
06.
{
07.
// TODO: Add your dispatch handler code here
08.
if
(!OnlySock)
09.
return
-1;
//網絡尚未開始建立連接配接
10.
11.
int
gDataType = VariantToLong(DataType);
12.
long
gDataLength = VariantToLong(DataLength);
13.
int
gTimeOut = VariantToLong(TimeOut);
14.
if
(gDataType < 0)
15.
return
-2;
16.
if
(gDataLength >24)&0xff;
17.
buffer[m++] = (gData.lVal>>16)&0xff;
18.
buffer[m++] = (gData.lVal>>8)&0xff;
19.
buffer[m++] = gData.lVal&0xff;
20.
}
21.
}
22.
else
//long = char*1 //資料可能溢出
23.
{
24.
buffer =
new
char
[gDataLength];
25.
for
(m=0,n=0; n< gDataLength; n++)
26.
27.
{
28.
SafeArrayGetElement(Data.parray,&n,&gData.lVal);
29.
buffer[n] = (
char
)gData.lVal;
30.
}
31.
}
32.
break
;
33.
case
VT_ARRAY|VT_INT:
//以整型數組發送
34.
gData.vt = VT_INT;
35.
if
(gDataType != 0)
36.
{
37.
//一個int等于四個char
38.
buffer =
new
char
[gDataLength];
39.
for
(m=0,n=0; n< gDataLength/4; n++)
40.
{
41.
SafeArrayGetElement(Data.parray,&n,&gData.intVal);
42.
buffer[m++] = (gData.intVal>>24)&0xff;
43.
buffer[m++] = (gData.intVal>>16)&0xff;
44.
buffer[m++] = (gData.intVal>>8)&0xff;
45.
buffer[m++] = gData.intVal&0xff;
46.
}
47.
}
48.
else
49.
{
50.
buffer =
new
char
[gDataLength];
51.
for
(n=0; n< gDataLength; n++)
52.
{
53.
SafeArrayGetElement(Data.parray,&n,&gData.intVal);
54.
buffer[n] = (
char
)gData.intVal;
55.
}
56.
}
57.
break
;
58.
case
VT_ARRAY|VT_UI1:
//以BYTE數組發送
59.
gData.vt = VT_UI1;
//一個char等于一個BYTE不必進行轉換
60.
buffer =
new
char
[gDataLength];
61.
for
(n=0; n< gDataLength; n++)
62.
{
63.
SafeArrayGetElement(Data.parray,&n,&gData.bVal);
64.
buffer[n] = gData.bVal;
65.
}
66.
break
;
67.
default
:
//在這裡沒有一一列出其它類型,剩下的就由閣下進行資料轉換處理了,我就偷懶了^_^
68.
return
-3;
//傳入的資料類型不被支援
69.
}
70.
71.
len = send(OnlySock, buffer, gDataLength, 0);
//發送資料
72.
delete
[] buffer;
73.
buffer = NULL;
74.
75.
if
(len>24)&0xff;
76.
buffer[1] = (lData>>16)&0xff;
77.
buffer[2] = (lData>>8)&0xff;
78.
buffer[3] = lData&0xff;
79.
80.
//4個char組成一個long
81.
lData_2 = ( (buffer[0] &0xff ) < < 24) +
82.
(( buffer[1] &0xff ) < < 16) +
83.
(( buffer[2] &0xff ) < < 8) +
84.
( buffer[3] &0xff );
四、現在來看看GetData()的處理,具體實作,請看如下代碼:
01.
// TODO: Add your dispatch handler code here
02.
if
(!OnlySock)
03.
return
-1;
//網絡尚未開始建立連接配接
04.
05.
int
gDataType = VariantToLong(DataType);
06.
long
gDataMaxLength = VariantToLong(DataMaxLength);
07.
int
gTimeOut = VariantToLong(TimeOut);
08.
if
(gDataType < 0)
09.
return
-2;
10.
if
(gDataMaxLength bstrVal = _com_util::ConvertStringToBSTR(buffer);
11.
break
;
12.
case
VT_BYREF|VT_UI1:
//按BYTE*形式接收
13.
memcpy
(Data->pbVal,buffer,gDataMaxLength);
14.
break
;
15.
case
VT_BYREF|VT_I1:
//按 char * 形式接收
16.
memcpy
(Data->pcVal,buffer,gDataMaxLength);
17.
break
;
18.
case
VT_BYREF|VT_I4:
//以長整型指針接收
19.
buffer[gDataMaxLength]=
'\0'
;
20.
for
(n=0; n< gDataMaxLength; n++)
21.
{
22.
Data->plVal[n] = buffer[n];
23.
}
24.
break
;
25.
case
VT_ARRAY|VT_I4:
//以長整型數組接收
26.
gData.vt = VT_I4;
27.
if
(gDataType != 0)
28.
{
29.
for
(m=0,n=0; n < gDataMaxLength;n++)
30.
{
31.
gData.lVal = ( ( buffer[m]&0xff ) < < 24) +
32.
( ( buffer[m+1]&0xff ) < < 16) +
33.
( ( buffer[m+2]&0xff ) < < 8) +
34.
( buffer[m+3]&0xff );
35.
36.
SafeArrayPutElement( Data->parray,&n,&gData.lVal );
37.
m = m+4;
38.
}
39.
}
40.
else
41.
{
42.
for
(n = 0; n< gDataMaxLength; n++)
43.
{
44.
gData.lVal = (
long
)buffer[n];
45.
SafeArrayPutElement( Data->parray,&n,&gData.lVal );
46.
}
47.
}
48.
break
;
49.
case
VT_ARRAY|VT_INT:
//以整型數組接收
50.
gData.vt = VT_INT;
51.
if
(gDataType != 0)
52.
{
53.
for
(m=0,n=0; n< gDataMaxLength;n++)
54.
{
55.
gData.intVal = ( ( buffer[m]&0xff)parray);
56.
delete
data;
57.
58.
}
59.
60.
void
CTestMFCWinSockDlg::OnCloseWinsockMfcwinsockctrl1()
61.
{
62.
// TODO: Add your control notification handler code here
63.
m_sock.DisConnect();
//調用斷開連接配接接口
64.
AfxMessageBox(
"伺服器斷開了該次連接配接,請檢查!"
);
65.
}
66.
67.
void
CTestMFCWinSockDlg::OnConnect()
68.
{
69.
// TODO: Add your control notification handler code here
70.
UpdateData(TRUE);
71.
if
(!m_sock.Connect(COleVariant(m_ip),COleVariant(m_port)))
72.
AfxMessageBox(
"與伺服器建立連接配接失敗,請确認伺服器是否存在!"
);
73.
}
VB調用控件方式:
VB時面調用要友善很多,這得益于VB的很多自動化功能,請看下圖:
圖三 VB調用控件方法
同樣,輕按兩下我們的控件,然後添加控件事件,如下圖:
圖四 VB響應控件事件
然後,添加相關代碼如下:
01.
Private Sub Command1_Click()
02.
MFCWinSock1.Connect CStr(ip), CLng(port)
03.
End Sub
04.
05.
Private Sub Command2_Click()
06.
MFCWinSock1.SendData
"SendData: 歡迎使用!"
, 0, 50, 3
07.
End Sub
08.
09.
Private Sub MFCWinSock1_CloseWinsock()
10.
MFCWinSock1.DisConnect
11.
MsgBox
"伺服器斷開了連接配接,請檢查!"
12.
13.
End Sub
14.
15.
Private Sub MFCWinSock1_RecvSockEvent()
16.
Dim data As Variant
17.
Dim data2(100) As Long
18.
Dim data3 As String
19.
Dim l As Long
20.
data = data2 '在VB裡當把一個Variant變量data等于另一個确定變量data2時,data将被初始化為與data2相同的類型變量
21.
'data = data3 '
如果讓data等于data3,那麼data将變成字元串型的變量參數
22.
l = MFCWinSock1.GetData(data, 0, 100, 3) '這時data裡面已存放了接收到的資料
23.
data3 = data(0) '這裡隻顯示接收到的首字元編碼
24.
MsgBox data3
25.
End Sub
大家可以看到,對于SAFEARRAY類型的資料進行相關處理也并不可怕,由于在源碼裡給出了具體代碼和詳細注解,在這裡我就不再贅述了,
至于BSTR和char *類型的資料,相信不用我多說,大家也已經知道如何使用了。
結束語:
全文至此暫告一段落,本文向大家展示了MFC ActiveX控件的魅力,以及所用的VARIANT類型參數,還詳細給出了WinSock的開發代碼,以用在VC,VB的調用方法,由于這段時間忙于一些新項目的開發,是以沒辦法花太多時間進行詳細解釋,是以很多地方都直接給出源代碼再加上注解,而沒有進行通俗的講解,還請各位讀者仔細檢視源代碼。
本控件目前隻能作為用戶端,閣下還可以繼續進行完善,比如進行端口的監聽,實作伺服器的相關處理等等,但這已經不是本文的目的,授人以魚,不如授人如漁,剩下的功能,就由各位讀者去實作了,也歡迎與我進行交流,謝謝!
另外:本文的示例,需要一個伺服器程式,大家可以在網上随便下載下傳一下進行測試,我就不提供了。