Standard MFC Winsock ActiveX Control Development Instance (ii) Advanced

Source: Internet
Author: User

This article mainly uses the variant type as a parameter for network data transmission and receiving, as well as detailed usage of safearray and BSTR.
In addition, the call method and related data processing of the control in VC and VB are also provided.
Keywords: ActiveX, socket, variant, safearray, BSTR.

Review:In the previous articleArticleIn the Standard MFC Winsock ActiveX control development instance, we detail the control development process and interface and event
Add and response methods. Now we will continue the development of the previously unfinished controls and improve the functions that should be available as a Winsock Control.

2. Based on the Knowledge mentioned in the previous article, we now add two new interfaces: senddata () and getdata (). They look as follows:

 
// Send network data, send the data within the specified timeout period, and return the actual number of sent bytes. Otherwise, return the negative number long cmfcwinsockctrl: senddata (const variant far & data, const variant far & datatype, const variant far & datalength, const variant far & timeout) {// todo: add your dispatch handler code herereturn 0 ;}// get data, specify the time-out time for data retrieval, and return the actual length of the obtained data. Otherwise, return the negative number long cmfcwinsockctrl: getdata (variant far * data, const variant far & datatype, const variant far & datamaxlength, const variant far & timeout) {// todo: add your dispatch handler code herereturn 0 ;}

The parameters of the two interfaces are similar except the first parameter. Senddata () is used to send data without bringing back the data, so variant is used directly, while getdata () requires bringing back the data to the caller, so it is defined as the variant * type, the second parameter datatype is the type of data transmitted or received. The third parameter is the length of data transmitted or received. The length here is Char, if the input type is int, the length is 4. If the input type is string, a Chinese character occupies 2 characters. The last parameter is the timeout time when the network sends or reads data.

3. Add a connection () InterfaceSource code, Looks as follows:

// Send network data, send the data within the specified timeout period, and return the actual number of sent bytes. Otherwise, return the negative number long cmfcwinsockctrl: senddata (const variant far & data, const variant far & datatype, const variant far & datalength, const variant far & timeout) {// todo: add your dispatch handler code hereif (! Onlysock) Return-1; // The network has not started to establish a connection int gdatatype = varianttolong (datatype); long gdatalength = varianttolong (datalength); int gtimeout = varianttolong (timeout ); if (gdatatype <0) Return-2; If (gdatalength <= 0) Return-2; If (gtimeout <0) Return-2; Switch (gdatatype) {Case 0: // The default format. If data is an integer array, no conversion is performed, and an int is directly transmitted to a char (data may overflow range). Case 1: // when this value is set to 1, when date is a long integer array, a long is converted to four char and transferred to Case 2: // when this value is set to 2, when date is an integer Array Converts an int to four char and transmits Case 3: // when this value is set to 3, when date is an unsigned short integer array, convert an unsigned short to two char and transmit case 4: // when this value is specified as 4, when date is a byte array, convert a byte to a char and transmit case 5: // when this value is set to 5, when date is a short integer array, convert a short to two char and transmit case 6: // when this value is set to 6, when date is a floating point array, convert a float to four char and send case 7: // when this value is set to 7, when date is a double-precision array, convert a double to eight char and send the break; default: // if it is not in the preceding value range, the break will be transmitted according to the corresponding data type;} timeval TV; fd_set fdwrite; int Len = 0; long m = 0; long n = 0; L Ong changetype = 0; // convert the float data type before transmitting variant gdata; variantinit (& gdata); // send the information to the server fd_zero (& fdwrite); TV. TV _sec = gtimeout; // return TV after the specified time. TV _usec = 0; fd_set (onlysock, & fdwrite); // whether data can be sent select (0, null, & fdwrite, null, & TV); char * buffer = NULL; if (fd_isset (onlysock, & fdwrite) {Switch (data. vt) {Case vt_bstr: // send buffer = _ com_util: convertbstrtostring (data. bstrval); break; Case vt_byref | vt_ui1: // send B in byte * Format Uffer = new char [gdatalength]; memcpy (buffer, Data. pbval, gdatalength); break; Case vt_byref | vt_i1: // send buffer = new char [gdatalength] by char *; memcpy (buffer, Data. pcval, gdatalength); break; Case vt_array | vt_i4: // send gdata in a long integer array. vt = vt_i4; If (gdatatype! = 0) // long = char * 4 {// sizeof (long), here the length of a long integer is 4 charbuffer = new char [gdatalength]; for (m = 0, n = 0; n <gdatalength/4; n ++) {safearraygetelement (data. parray, & N, & gdata. lval); buffer [M ++] = (gdata. lval> 24) & 0xff; buffer [M ++] = (gdata. lval> 16) & 0xff; buffer [M ++] = (gdata. lval> 8) & 0xff; buffer [M ++] = gdata. lval & 0xff ;}} else // long = char * 1 // data may overflow {buffer = new char [gdatalength]; for (m = 0, n = 0; n <gdatalength; n ++) {SAF Earraygetelement (data. parray, & N, & gdata. lval); buffer [N] = (char) gdata. lval ;}} break; Case vt_array | vt_int: // send gdata in an integer array. vt = vt_int; If (gdatatype! = 0) {// an int is equal to four charbuffer = new char [gdatalength]; for (m = 0, n = 0; n <gdatalength/4; n ++) {safearraygetelement (data. parray, & N, & gdata. intval); buffer [M ++] = (gdata. intval> 24) & 0xff; buffer [M ++] = (gdata. intval> 16) & 0xff; buffer [M ++] = (gdata. intval> 8) & 0xff; buffer [M ++] = gdata. intval & 0xff ;}} else {buffer = new char [gdatalength]; for (n = 0; n <gdatalength; n ++) {safearraygetelement (data. parray, & N, & gdata. intval); buffer [N] = (char) gdata. intval ;}} break; Case vt_array | vt_ui1: // send gdata in byte array. vt = vt_ui1; // a char equals a byte and does not need to be converted to buffer = new char [gdatalength]; for (n = 0; n <gdatalength; n ++) {safearraygetelement (data. parray, & N, & gdata. bval); buffer [N] = gdata. bval;} break; default: // other types are not listed here. The rest will be converted by you, and I will be lazy. ^_^ return-3; // The input data type is not supported} Len = Send (onlysock, buffer, gdatalength, 0); // send data Delete [] buffer; buffer = NULL; if (LEN <= 0) // = socket_error) {return-101; // unable to send data, the other party may be disconnected} else {return 0; // network timeout} variantclear (& gdata); Return Len ;}

Here, we use _ com_util: convertbstrtostring () to convert BSTR to the char * type. It can automatically convert Chinese characters and solve the conversion using some methods, the bug that Chinese characters are garbled. The premise is that when using this method, you must first # include "comutil. H", and then add "comsupp. Lib kernel32.lib" to the Project Settings-link-Object/library modules"
Similarly, to convert char * to the BSTR type, use _ com_util: convertstringtobstr. In VC, we can see that the length of int and long is 4, and the length of char is 1. Therefore, if the input is a long integer or an integer array, I convert it to four char and then send it out. The conversion method can be processed by shift, as shown below:

 
// Convert long to four charchar buffer [4]; long ldata_1 = 12345678; long ldata_2 = 0; buffer [0] = (ldata> 24) & 0xff; buffer [1] = (ldata> 16) & 0xff; buffer [2] = (ldata> 8) & 0xff; buffer [3] = ldata & 0xff; // four char form a longldata_2 = (buffer [0] & 0xff) <24) + (buffer [1] & 0xff) <16) + (buffer [2] & 0xff) <8) + (buffer [3] & 0xff );

4. Now let's take a look at the processing of getdata (). The specific implementation is as follows:Code:

// Todo: add your dispatch handler code hereif (! Onlysock) Return-1; // The network has not started to establish a connection int gdatatype = varianttolong (datatype); long gdatamaxlength = varianttolong (datamaxlength); int gtimeout = varianttolong (timeout ); if (gdatatype <0) Return-2; If (gdatamaxlength <= 0) Return-2; If (gtimeout <0) Return-2; Switch (gdatatype) {Case 0: // The default format. If data is an integer array, no conversion is performed, and an int is directly transmitted to a char (data may overflow range). Case 1: // when this value is set to 1, when date is a long integer array, a long is converted to four char and transferred to Case 2: // when this value is set to 2, when d When ate is an integer array, an int is converted into four char and sent to case 3: // when this value is set to 3, when date is an unsigned short integer array, convert an unsigned short to two char and transmit case 4: // when this value is specified as 4, when date is a byte array, convert a byte to a char and transmit case 5: // when this value is set to 5, when date is a short integer array, convert a short to two char and transmit case 6: // when this value is set to 6, when date is a floating point array, convert a float to four char and send case 7: // when this value is set to 7, when date is a double-precision array, convert a double to eight char and send the break; default: // if it is not in the preceding value range, the break will be transmitted according to the corresponding data type;} timeval TV; fd_set fdread; int Len =-3; // if the connection cannot be found, return -3 long n = 0; long m = 0; long changetype = 0; variant gdata; variantinit (& gdata); char * buffer = NULL; buffer = new char [gdatamaxlength + 1]; memset (buffer, 0, gdatamaxlength + 1); fd_zero (& fdread); TV. TV _sec = gtimeout; // return TV after the specified time is exceeded. TV _usec = 0; fd_set (onlysock, & fdread); // whether data can be read select (0, & fdread, null, null, & TV); If (fd_isset (onlysock, & fdread) {Len = Recv (onlysock, buffer, gdatamaxlength, 0); If (LEN <= 0) {Delete [] Buffer; Return-102; // The data cannot be read, and the other party may be disconnected.} If (LEN <gdatamaxlength) // if the length of the data to be read is less than the input length, change the input length to the actual length gdatamaxlength = Len; Switch (data-> VT) {Case vt_bstr: // receives buffer [gdatamaxlength] = '\ 0' in string format '; data-> bstrval = _ com_util: convertstringtobstr (buffer); break; Case vt_byref | vt_ui1: // receives memcpy (data-> pbval, buffer, gdatamaxlength) in byte * format ); break; Case vt_byref | vt_i1: // receives memcpy (data-> pcval, buffer, gdatamaxlength in char * Format ); Break; Case vt_byref | vt_i4: // receives the buffer [gdatamaxlength] = '\ 0' with a long integer pointer; For (n = 0; n <gdatamaxlength; n ++) {data-> plval [N] = buffer [N];} break; Case vt_array | vt_i4: // receives gdata in a long integer array. vt = vt_i4; If (gdatatype! = 0) {for (m = 0, n = 0; n <gdatamaxlength; n ++) {gdata. lval = (buffer [m] & 0xff) <24) + (buffer [M + 1] & 0xff) <16) + (buffer [M + 2] & 0xff) <8) + (buffer [M + 3] & 0xff); safearrayputelement (data-> parray, & N, & gdata. lval); M = m + 4 ;}} else {for (n = 0; n <gdatamaxlength; n ++) {gdata. lval = (long) buffer [N]; safearrayputelement (data-> parray, & N, & gdata. lval) ;}} break; Case vt_array | vt_int: // receives gdata in an integer array. vt = vt_int; If (gdatatype! = 0) {for (m = 0, n = 0; n <gdatamaxlength; n ++) {gdata. intval = (buffer [m] & 0xff) <24) + (buffer [M + 1] & 0xff) <16) + (buffer [M + 2] & 0xff) <8) + (buffer [M + 3] & 0xff); safearrayputelement (data-> parray, & N, & gdata. intval); M = m + 4 ;}} else {for (n = 0; n <gdatamaxlength; n ++) {gdata. intval = (INT) buffer [N]; safearrayputelement (data-> parray, & N, & gdata. intval) ;}} break; Case vt_array | vt_ui1: // receives gdata in byte array. vt = vt_ui1; For (n = 0; n <gdatamaxlength; n ++) {gdata. bval = buffer [N] & 0xff; safearrayputelement (data-> parray, & N, & gdata. bval);} break; default: // other types. Please refer to the official website for processing. delete Delete [] buffer; Return-3; // The input data type cannot be identified} else {Delete [] buffer; return 0; // network data read timeout} variantclear (& gdata); Delete [] buffer; return Len;

5. Next, let's take a look at how VC and VB call the control:

  1. VC call control method: Create a dialog box project and add the control to the project. The settings are as follows:

    Figure 1 create a dialog box project and add the control

    Respond to the network disconnection and data arrival events of the control. The settings are as follows:

    Figure 2 responding to two events of the control

    Add the Code as follows:

    Void ctestmfcwinsockdlg: onrecvsockeventmfcwinsockctrl1 () {// todo: add your control notification handler code heresafearraybound bound [1]; // One-dimensional array bound [0]. llbound = 0; bound [0]. celements = 100; // This one-dimensional array can receive a maximum of 100 elements, variant * data; data = new variant; variantinit (data); data-> VT = vt_array | vt_i4; // specify as a long integer array data-> parray = safearraycreate (vt_i4, 1, bound); // create a safearray structure long l = m_sock.getdata (data, colevariant (long) 0), Colevariant (long) 100), colevariant (long) 3); If (L <= 0) {; // identify the error information here and handle it accordingly, I am just lazy .} char pdata [100] = {0}; // The result is long change = 0 in the character array. For (long n = 0; n <L; n ++) {safearraygetelement (data-> parray, & N, & Change); pdata [N] = (char) Change ;} cstring mess; mess. format ("% s", pdata); afxmessagebox (MESS); safearraydestroy (data-> parray); delete data;} void ctestmfcwinsockdlg: encrypt () {// todo: add you R control notification handler code herem_sock.disconnect (); // call the disconnection interface afxmessagebox ("the server has disconnected this connection. Please check! ");} Void ctestmfcwinsockdlg: onconnect () {// todo: add your control notification handler code hereupdatedata (true); If (! M_sock.connect (colevariant (m_ip), colevariant (m_port) afxmessagebox ("An error occurred while establishing a connection with the server. Check whether the server exists! ");}
  2. VB call control method: VB calls are much more convenient, thanks to many automated functions of VB. See:

    Figure 3 VB Call Control Method

    Similarly, double-click our controls and add control events, such:

    Figure 4 VB responds to control events

    Then, add the relevant Code as follows:

    Private sub commandrentclick () mfcwinsock1.connect CSTR (IP), clng (port) end subprivate sub command2_click () mfcwinsock1.senddata "senddata: Welcome! ", 0, 50, 3end subprivate sub mfcwinsock1_closewinsock () mfcwinsock1.disconnectmsgbox" the server is disconnected. Check the connection! "End subprivate sub mfcwinsock1_recvsockevent () dim data as variantdim data2 (100) as longdim data3 as stringdim L as longdata = data2 'in VB, when a variant variable data is equal to another identified variable data2, data will be initialized to the same type variable 'data = data3 'As data2. If we make data equal to data3, data will become a string-Type Variable Parameter L = mfcwinsock1.getdata (data, 0,100, 3) 'Data contains the received data data3 = data (0) '. Only the received first character code msgbox data3end sub is displayed.

    As you can see, it is not terrible to process safearray-type data. Because the specific code and detailed annotations are provided in the source code, I will not go into details here,
    As for the data of the BSTR and char * types, I believe you don't need to talk about it. You know how to use it.

Conclusion:

the full text has come to an end. This article shows you the charm of the MFC ActiveX control, the variant type parameters used, and the Winsock development code in detail,
it is used in the call methods of VC and VB. Due to the busy development of some new projects during this time, it is impossible to spend too much time explaining in detail, therefore, the source code is directly provided in many places
with annotations, without a general explanation. Please carefully check the source code.
currently, this control can only be used as a client. You can continue to improve it, such as listening to ports and implementing server-related processing. However, this is not the purpose of this Article,
it is better to teach people to fish than to teach them to fish. The rest of the functions will be implemented by readers. You are also welcome to communicate with me. Thank you!
In addition: For the example in this article, you need a server Program . You can download it online for testing, I will not provide it.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.