Код (C): int send (SOCKET sock, const char FAR* buf, int bufsize, int flags); Пример передачи данных серверу: Код (C): char szBuf[80]; lstrcpy(szBuf, "Test string"); send (srv_socket, szBuf, lstrlen(szBuf), 0); Параметры функции recv, предназначенной для приема данных, аналогичны параметрам функции send: Код (C): int recv (SOCKET sock, char FAR * buf, int bufsize, int flags); Функции recv и send возвращают количество, принятых и переданных байт данных. Приложение, которое принимает данные, вызывает функцию recv в цикле до тех пор, пока не будут приняты все переданные данные. На один вызов send может приходиться несколько вызовов функции recv. В случае ошибки функции send и recv возвращают значение SOCKET_ERROR. Для анализа причин возникновения ошибки используют функцию WSAGetLastError. Список кодов ошибок, которые возникают при вызове команды send: Код ошибкиhexОписаниеWSANOTINITIALISED276DПеред использованием функции необходимо вызвать функцию WSAStartupWSAENETDOWN2742Сбой в сетиWSAEACCES271DУказанный адрес является широковещательным (broadcast), однако перед вызовом функции не был установлен соответствующий флагWSAEINTR2714Работа функции была отменена при помощи функции WSACancelBlockingCallWSAEINPROGRESS2734Выполняется блокирующая функция интерфейса Windows SocketsWSAEFAULT271EПараметр buf указан неправильно (он не указывает на адресное пространство, принадлежащее приложению)WSAENETRESET2744Необходимо сбросить соединениеWSAENOBUFS2747Возникла блокировка буфераWSAENOTCONN2749Сокет не подсоединенWSAENOTSOCK2736Указанный в параметре дескриптор не является сокетомWSAESHUTDOWN274AСокет был закрыт функцией shutdownWSAEWOULDBLOCK2733Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировкеWSAEMSGSIZE2738Был использован сокет типа SOCK_DGRAM (предназначенный для передачи датаграмм). При этом размер пакета данных превышает максимально допустимый для данной реализации интерфейса Windows SocketsWSAEINVAL2726Сокет не был подключен функцией bindWSAECONNABORTED2745Сбой из-за слишком большой задержки или по другой причинеWSAECONNRESET2746Сброс соединения удаленным узломПри выполнении функции recv могут возникать следующие ошибки: Код ошибкиhexОписаниеWSANOTINITIALISED276DПеред использованием функции необходимо вызвать функцию WSAStartupWSAENETDOWN2742Сбой в сетиWSAENOTCONN2749Сокет не подсоединенWSAEINTR2714Работа функции была отменена при помощи функции WSACancelBlockingCallWSAEINPROGRESS2734Выполняется блокирующая функция интерфейса Windows SocketsWSAENOTSOCK2736Указанный в параметре дескриптор не является сокетомWSAESHUTDOWN274AСокет был закрыт функцией shutdownWSAEWOULDBLOCK2733Сокет отмечен как неблокирующий, но запрошенная операция приведет к блокировкеWSAEMSGSIZE2738Размер пакета данных превышает размер буфера, в результате чего принятый пакет был обрезанWSAEINVAL2726Сокет не был подключен функцией bindWSAECONNABORTED2745Сбой из-за слишком большой задержки или по другой причинеWSAECONNRESET2746Сброс соединения удаленным узломПередача и прием данных в цикле может привести к блокировке работы приложения. Если это неприемлемо, следует воспользоваться асинхронным расширением интерфейса Windows Sockets. Приложение демонстрирует асинхронный прием данных. После установки канала связи оно вызывает функцию WSAAsyncSelect, указывая в качестве последнего параметра комбинацию констант FD_READ и FD_CLOSE. Функция главного окна приложения получает сообщение WSA_NETEVENT в тот момент времени, когда чтение данных не вызовет блокировки приложения: Код (C): #define WSA_NETEVENT (WM_USER + 2) rc = WSAAsyncSelect (srv_socket, hWnd, WSA_NETEVENT, FD_READ | FD_CLOSE); При необходимости выполнения асинхронной посылки данных нужно указать функцию WSAAsyncSelect и параметр FD_WRITE. Если функция WSAAsyncSelect выполнилась успешно ― возвращается нулевое значение, при ошибке ― значение SOCKET_ERROR. В зависимости от значения последнего параметра могут возникать разные коды ошибки, которые можно получить при помощи функции WSAGetLastError. Следующие ошибки могут возникнуть при любом значении параметра: Код ошибкиhexОписаниеWSANOTINITIALISED276DПеред использованием функции необходимо вызвать функцию WSAStartupWSAENETDOWN2742Сбой в сетиWSAEINVAL2726Сокет не был подключен функцией bindWSAEINPROGRESS2734Выполняется блокирующая функция интерфейса Windows SocketsДополнительный код ошибки можно получить из параметра lParam при помощи макрокоманды WSAGETSELECTERROR. При использовании параметра FD_CONNECT возможно появление следующих ошибок: Код ошибкиhexОписаниеWSAEADDRINUSE2740Указанный адрес уже используетсяWSAEADDRNOTAVAIL2741Указанный адрес не доступенWSAEAFNOSUPPORT273FДля данного сокета нельзя использовать указанное семейство адресовWSAECONNREFUSED274DПопытка установления канала связи была отвергнутаWSAEDESTADDRREQ2737Необходимо указать адрес получателя пакетаWSAEFAULT271EНеправильно указан параметр namelenWSAEINVAL2726Сокет уже подключен к адресуWSAEISCONN2748Сокет уже подсоединенWSAEMFILE2728Больше нет доступных дескрипторовWSAENETUNREACH2743Из данного узла и в данное время невозможно получить доступ к сетиWSAENOBUFS2747Нет места для размещения буфераWSAENOTCONN2749Сокет на подключенWSAENOTSOCK2736Указан дескриптор файла, а не сокетаWSAETIMEDOUT274CПри попытке установления канала связи возникла задержка во времениЕсли используется параметр FD_CLOSE, может возникнуть одна из следующих ошибок: Код ошибкиhexОписаниеWSAENETDOWN2742Сбой в сетиWSAECONNRESET2746Сброс соединения удаленным узломWSAECONNABORTED2745Сбой из-за слишком большой задержки или по другой причинеВ том случае, когда указаны параметры FD_READ, FD_WRITE, FD_OOB, или FD_ACCEPT, может возникнуть ошибка с кодом WSAENETDOWN. Обработчик сообщения WSA_NETEVENT должен выполнить анализ причины, по которой он был вызван, так как за один вызов функции WSAAsyncSelect можно задать несколько событий, вызывающих генерацию сообщения. Этот анализ проводится следующим образом: Код (C): void WndProc_OnWSANetEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { char szTemp[256]; int rc; // Если на сокете выполняется передача данных, // прием и отображение этих данных в виде текстовой строки if(WSAGETSELECTEVENT(lParam) == FD_READ ) { rc = recv ((SOCKET)wParam, szTemp, 256, 0); if(rc) { szTemp[rc] = '\0'; MessageBox(NULL, szTemp, "Reсeived data", MB_OK); } return; } // Если соединение завершено -- вывод сообщения else if(WSAGETSELECTEVENT(lParam) == FD_CLOSE ) { MessageBox(NULL, "Connection closed", "Server", MB_OK); } } Параметр wParam содержит дескриптор сокета, на котором выполняется передача данных, параметр lParam ― код события, которое произошло в сети. Текст приложения-сервера (12s.asm) Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 WINSOCK_VERSION equ 504 SD_RECEIVE equ 0 SD_SEND equ 1 SD_BOTH equ 2 WSADATA struct wVersion dw ?; wHighVersion dw ? szDescription db (WSADESCRIPTION_LEN + 1) dup(?) szSystemStatus db (WSASYS_STATUS_LEN + 1) dup(?) iMaxSockets dw ? iMaxUdpDg dw ? lpVendorInfo dq ? WSADATA ends S_UN_B STRUCT s_b1 BYTE ? s_b2 BYTE ? s_b3 BYTE ? s_b4 BYTE ? S_UN_B ENDS S_UN_W STRUCT s_w1 WORD ? s_w2 WORD ? S_UN_W ENDS ADDRESS_UNION UNION S_un_b S_UN_B <> S_un_w S_UN_W <> S_addr DWORD ? ADDRESS_UNION ENDS in_addr STRUCT S_un ADDRESS_UNION <> in_addr ENDS SOCKADDR_IN STRUCT sin_family dw ?;is the same as af parameter in socket call. You must use AF_INET here. sin_port dw ?;is the port that the socket will use to communicate with the remote socket. ;This value depends on the higher level protocol that you want to use. If you want to connect to ;the remote socket for HTTP, use port 80 (decimal). However, note that the port value MUST be in ;network byte order that is big Endian. So you cannot use the port value per se but you must call ;htons to convert the value to network byte order first. This is one of the most common error the ;newcomers to winsock programming encounter. sin_addr in_addr <>;is the IP address of the remote host. Again, you must convert the ;IP address to network byte order before using it sin_zero BYTE 8 dup(?);is reserved. Don't mess with it SOCKADDR_IN ends .code WinMain proc enter 30h,0 mov r9d,256;cx mov [rbp-10h],r9 mov qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rbp-10h],rax;30h-10h=+20h invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local hFile:qword local cbWritten:dword local hResource:qword local pResource:qword local wsa:WSADATA local port:qword local FSize:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_DESTROY je wmDESTROY xor eax,eax jmp exit0 wmDESTROY:invoke WSACleanup jmp wmBYE wmSEND_WAV:mov port,12345 mov type0,WM_USER+3 mov ecx,offset wav_file xor r9d,r9d mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,rax invoke GetFileSize,eax,0 mov FSize,rax invoke GlobalAlloc,GPTR,eax mov p,rax lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile jmp @f wmSEND_ICO:mov port,12344 mov type0,WM_USER+2 mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,rax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov p,rax and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,eax,FSize,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b jmp @f wmSEND_TXT:mov port,12343 mov type0,WM_USER+1 invoke GlobalAlloc,GPTR,256 mov p,rax invoke GetDlgItemText,hWnddlg,ID_TXT,eax,256 inc eax mov FSize,rax @@: mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю invoke PostMessage,eax,type0,hWnddlg,FSize invoke SendData,p,FSize,port jmp wmBYE wmINITDIALOG:invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam ; активировать библиотеку сокетов lea edx,wsa invoke WSAStartup,WINSOCK_VERSION ;An error occured if eax != null, because there's no return value for this api, if there's return, ;there's an error jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp SendData proc buf:qword,len:qword,port:qword local sock:QWORD local saddr:SOCKADDR_IN;sizeof(saddr)) =10h local bytesSent:dword mov buf,rcx mov len,rdx mov port,r8 ; создать сокет invoke socket,AF_INET, SOCK_STREAM, IPPROTO_TCP mov sock,rax cmp eax,INVALID_SOCKET jz exit0;if (sock != INVALID_SOCKET) mov saddr.sin_family,AF_INET invoke htonl,INADDR_LOOPBACK mov saddr.sin_addr.S_un.S_addr,eax invoke htons,port;12345 mov saddr.sin_port,ax ;After the socket is created, you have two choices: wait for an incoming connection or connect ;to a remote socket. If you want to wait for incoming connection, you must call listen to listen ;for an incoming connection and call accept to establish connection with the remote socket. If you ;want to connect to a remote socket, you must call connect mov r8d,sizeof saddr;the size of SOCKADDR_IN structure lea edx,saddr;a pointer to a SOCKADDR_IN structure invoke connect,sock;socket descriptor of the local socket. You can pass the socket ;descriptor returned by socket call as this parameter or eax,eax jnz @0;if (connect (sock,(struct sockaddr*)&saddr,sizeof (saddr)) == 0) @@: cmp len,0 ; while (size) jz @0 ;use send to send data on a stream socket and sendto to send data on a datagram socket. I'll ;examine send here since many popular protocols such as HTTP and FTP use stream sockets. ; запрос пришел - посылаем информацию invoke send,sock,buf,len, 0 ;Parameters ; #1 socket == socket descriptor ; #2 buffer == address of the data that you want to send. The data need not be NULL-terminated ;since its size is specified in len parameter. ; #3 len == the size of data to send ; #4 flags == flags specifying the behavior of the function. There are two flags you can use: ; MSG_DONTROUTE : specifies that the data should not be subject to routing. Notice ;the word "should". Some windows socket implementation may ignore this flag. ; MSG_OOB : specifies that the data is out-of-band data. ;Normally we don't use any of these two flags, flags parameter should be 0 in this case. ;If the call is unsuccessful, the value SOCKET_ERROR is returned in eax. ;If it's successful, the actual number of bytes sent is returned in eax. Note that this number ;may not be equal to len parameter. or eax,eax jz @0;if (bytesSent <= 0) break; sub len,rax; size -= (uint32_t)bytesSent; add buf,rax; data = (uint8_t*)data + bytesSent; jmp @b ; закрыть связь @0: invoke shutdown,sock,SD_BOTH ; закрыть сокет invoke closesocket,sock exit0: leave ret SendData endp ;--------------------------------------- .data szWin db 'Socket Reciever',0 wav_file db '..\Images\03.wav',0 p dq ? p1 dd 1 type0 dq ? end rc-файл (12s.rc) Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_IMG1 104 #define IDC_DIALOG 200 #define IDC_ICON1 500 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Socket Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW | WS_VISIBLE | SS_ICON,5,23,128,128 CONTROL "Write something and click 'Send Text'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Send Text",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Send ICO", ID_SEND_ICO,149,45,60,15 PUSHBUTTON "Send WAV", ID_SEND_WAV,149,65,60,15 PUSHBUTTON "Exit", IDCANCEL, 149,85,60,15 END Текст приложения-клиента (12r.asm) Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 IDC_OUTPUT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 WINSOCK_VERSION equ 504 SD_RECEIVE equ 0 SD_SEND equ 1 SD_BOTH equ 2 WSADATA struct wVersion dw ?; wHighVersion dw ? szDescription db (WSADESCRIPTION_LEN + 1) dup(?) szSystemStatus db (WSASYS_STATUS_LEN + 1) dup(?) iMaxSockets dw ? iMaxUdpDg dw ? lpVendorInfo dq ? WSADATA ends S_UN_B STRUCT s_b1 BYTE ? s_b2 BYTE ? s_b3 BYTE ? s_b4 BYTE ? S_UN_B ENDS S_UN_W STRUCT s_w1 WORD ? s_w2 WORD ? S_UN_W ENDS ADDRESS_UNION UNION S_un_b S_UN_B <> S_un_w S_UN_W <> S_addr DWORD ? ADDRESS_UNION ENDS in_addr STRUCT S_un ADDRESS_UNION <> in_addr ENDS SOCKADDR_IN STRUCT sin_family WORD ? sin_port WORD ? sin_addr in_addr <> sin_zero BYTE 8 dup (?) SOCKADDR_IN ends .code WinMain proc enter 30h,0 mov r9d,offset DialogProc and qword ptr[rbp-10h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local wsa:WSADATA local clientSocket:qword local saddr:SOCKADDR_IN;sizeof(saddr)=10h local addrSize:dword local buffer[1024]:byte local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_DESTROY je wmDESTROY cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_USER+2 je wmUSER_2 cmp edx,WM_USER+3 je wmUSER_3 xor eax,eax jmp exit0 wmDESTROY:cmp serverSocket,INVALID_SOCKET jz wmBYE invoke shutdown,serverSocket,SD_BOTH invoke closesocket,serverSocket or serverSocket,INVALID_SOCKET jmp wmBYE wmUSER_1:cmp serverSocket,INVALID_SOCKET jz @f invoke shutdown,serverSocket,SD_BOTH invoke closesocket,serverSocket ; Create a stream socket for internet use ; создать сокет @@: invoke socket,AF_INET,SOCK_STREAM,IPPROTO_TCP mov serverSocket,rax cmp eax,INVALID_SOCKET jz break ; подключить сокет mov saddr.sin_family,AF_INET invoke htonl,INADDR_LOOPBACK mov saddr.sin_addr.S_un.S_addr,eax invoke htons,12343; convert port number into network byte order first mov saddr.sin_port,ax; адрес порта mov r8d,sizeof saddr lea edx,saddr invoke bind,serverSocket or eax,eax;if (bind (serverSocket, (struct sockaddr*)&saddr, sizeof(saddr)) == 0) jnz break ; перевести сокет в состояние "слушать" invoke listen,serverSocket,256 or eax,eax jnz break;if (listen (serverSocket, 256) == 0) ; ждем запроса от клиента mov addrSize,sizeof saddr lea edx,saddr lea r8d,addrSize invoke accept,serverSocket mov clientSocket,rax cmp eax,INVALID_SOCKET jz break;if (clientSocket == INVALID_SOCKET) break; ; запрос пришел - посылаем информацию @@: lea edx,buffer invoke recv,clientSocket,,1024,0 ;recv is for use with a stream socket ;Parameters: ; #1 socket == socket descriptor ; #2 buffer == address of the memory block to store the incoming data. ; #3 len == the size of the memory block ; #4 flags == flags specifying the behavior of the function. There are two flags you can use: ; MSG_PEEK Peek at the incoming data. The data is copied into the buffer but is not ;removed from the input queue. ; MSG_OOB Process out-of-band data. This flag is usually used when FD_OOB notification ;is received. If the call is successful, it returns the number of bytes read from the socket. If it ;is unsuccessful, the value SOCKET_ERROR is returned. If the return value is 0, the remote socket ;has been closed or eax,eax jnz @b;if (len <= 0) break ; выводим строку символов lea r8d,buffer invoke SetDlgItemText,hWnddlg,IDC_OUTPUT jmp @0 wmUSER_2:;mov rax,lParam mov FSize,r9;ax cmp serverSocket,INVALID_SOCKET jz @f invoke shutdown,serverSocket,SD_BOTH invoke closesocket,serverSocket @@: invoke socket,AF_INET,SOCK_STREAM,IPPROTO_TCP; Create a stream socket for internet use mov serverSocket,rax cmp serverSocket,INVALID_SOCKET jz break mov saddr.sin_family,AF_INET invoke htonl,INADDR_LOOPBACK mov saddr.sin_addr.S_un.S_addr,eax invoke htons,12344; convert port number into network byte order first mov saddr.sin_port,ax mov r8d,sizeof saddr lea edx,saddr invoke bind,serverSocket or eax,eax;if (bind (serverSocket, (struct sockaddr*)&saddr, sizeof(saddr)) == 0) jnz break invoke listen,serverSocket,256 or eax,eax jnz break;if (listen (serverSocket, 256) == 0) mov addrSize,sizeof saddr lea edx,saddr lea r8d,addrSize invoke accept,serverSocket mov clientSocket,rax cmp eax,INVALID_SOCKET jz break;if (clientSocket == INVALID_SOCKET) break; invoke GlobalAlloc,GPTR,FSize mov p,rax mov edi,eax @@: lea edx,buffer invoke recv,clientSocket,,1024,0 or eax,eax jz @f lea esi,buffer mov ecx,eax;1024 rep movsb jmp @b;if (len <= 0) break; @@: invoke CreateIconFromResourceEx,p,FSize,TRUE,30000h,256,256,LR_DEFAULTCOLOR invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON,eax jmp @1 wmUSER_3:;mov rax,lParam mov FSize,r9;ax cmp serverSocket,INVALID_SOCKET jz @f invoke shutdown,serverSocket,SD_BOTH invoke closesocket,serverSocket @@: invoke socket,AF_INET,SOCK_STREAM,IPPROTO_TCP; Create a stream socket for internet use mov serverSocket,rax cmp eax,INVALID_SOCKET jz break mov saddr.sin_family,AF_INET invoke htonl,INADDR_LOOPBACK mov saddr.sin_addr.S_un.S_addr,eax invoke htons,12345; convert port number into network byte order first mov saddr.sin_port,ax mov r8d,sizeof saddr lea edx,saddr invoke bind,serverSocket or eax,eax;if (bind (serverSocket, (struct sockaddr*)&saddr, sizeof(saddr)) == 0) jnz break invoke listen,serverSocket,256 or eax,eax jnz break;if (listen (serverSocket, 256) == 0) mov addrSize,sizeof saddr lea edx,saddr lea r8d,addrSize invoke accept,serverSocket mov clientSocket,rax cmp eax,INVALID_SOCKET jz break;if (clientSocket == INVALID_SOCKET) break; invoke GlobalAlloc,GPTR,FSize mov p,rax mov edi,eax @@: lea edx,buffer invoke recv,clientSocket,,1024,0 or eax,eax jz @f lea esi,buffer mov ecx,eax;1024 rep movsb jmp @b;if (len <= 0) break; @@: mov r8,p ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data) = 14h add r8d,14h invoke waveOutOpen,&hWaveOut,WAVE_MAPPER,,0,0,WAVE_ALLOWSYNC ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,p ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data)+\ ;(Type of format)+(Number of Channels)+(Sample Rate)+(Sample Rate*BitsPerSample*Channels/8)+\ ;(BitsPerSample*Channels/8)+(Bits per sample)+(“data” chunk header)+(Size of the data section)=2Ch add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov rax,FSize sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока invoke waveOutWrite,hWaveOut,&lpwiocb,sizeof WAVEHDR @@: test lpwiocb.dwFlags,WHDR_DONE jz @b invoke waveOutUnprepareHeader,hWaveOut,&lpwiocb,sizeof WAVEHDR invoke waveOutClose,hWaveOut ;---------------------------------------------------------- @1: invoke GlobalFree,p ; закрыть связь @0: invoke shutdown,clientSocket,SD_BOTH ; закрыть сокет invoke closesocket,clientSocket ;This function closes a socket. Every resource of the socket will be released break: cmp serverSocket,INVALID_SOCKET;if (serverSocket != INVALID_SOCKET) jz wmBYE invoke shutdown,serverSocket,SD_BOTH invoke closesocket,serverSocket mov serverSocket,INVALID_SOCKET jmp wmBYE wmINITDIALOG:;mov hWnd,rcx ; Найти окно отправителя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jnz wmBYE mov edx,offset Error1 mov r8d,offset szAppName invoke MessageBox,hWnddlg,,,MB_ICONEXCLAMATION or MB_YESNO cmp eax,IDNO jz wmBYE mov ecx,offset szService invoke WinExec,,SW_SHOW ;активировать библиотеку сокетов lea edx,wsa invoke WSAStartup,WINSOCK_VERSION jmp wmBYE ;-------------------------------------------------- wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;----------------------------------------------------------------------- .data szWin db "Socket Sender",0 Error1 db "The server is not running.",10,"Run?",0 szAppName db "Socket Reciever",0 szService db "12s",0 serverSocket dq INVALID_SOCKET ;threadHandleTxt dq ? ;threadHandleIco dq ? ;threadHandleWav dq ? ;threadId dd ? ;hWnd dq ? FSize dq ? p dq ? end rc-файл (08r.rc) Код (C): #include "resource.h" #define IDC_DIALOG 200 #define IDC_OUTPUT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Socket Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_OUTPUT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Exit",IDCANCEL,149,27,60,15 CONTROL 1,ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END в аттаче ASM-/RC-/EXE-файлы Благодарности Огромное спасибо rmn за подсказки, замечания и предоставленную программу
09. Mutexes. Блин #2. Более удачный, хотя и не последний вариант Пока только текст, но выводится без ошибок, вариант с передачей картинок и WAV-файлов будет позже (хотя есть вероятность, что механизм мьютексов не предназначен для такого интенсивного обмена сообщениями, но буду пробовать )...
09. Mutexes. Блин #3. Передача картинок (неудачная реализация)Для эксперимента были созданы иконки размером 16×16, 32×32, 64×64, 128×128, 256×256 Результат передачи текстовой строки и иконки 16×16 Результат передачи иконки 32×32 Результат передачи иконки 64×64 Результат передачи иконки 128×128 Результат передачи иконки 256×256Передача идет полубайтами+задержки для синхронизации. Картинка передана без искажений. Передача иконки 256×256 заняла примерно 42 минуты (2513036/60000 = 41,88393(3)). Видно, что нужно менять алгоритм и увеличивать скорость передачи. Size of Resource (bytes)mSecBytes/mSecтекстовая строка377020,05270655иконка 16×161128206390,05465381иконка 32×324264817760,05214244иконка 64×64169363235460,05234495иконка 128×128676245438820,12433579иконка 256×25627037625130360,10758939в аттаче ASM-/RC-/ICO-/EXE-файлы
14. Удаленный вызов процедур (Remote Procedure Call, RPC) Огромное спасибо HoShiMin и f13nd за помощь оказанную при написании программы! RPC технологии ― достаточно старые технологии. Наиболее яркие представители технологий RPC, это ― CORBA и DCOM. Главная идея RPC в том, чтобы сделать вызов удаленных систем похожим на вызов функций внутри программы. Вся механика удаленных вызовов прячется от программиста. Обычные вызовы функций внутри процессов обрабатывались на вызывающей стороне в Proxy, а на стороне системы, выполняющей функцию, в Dispatcher. Наблюдается своеобразный ренессанс RPC, наиболее яркие представители которого: Google ProtoBuf, Thrift, Avro. Теперь программист явным образом создает сервис (Service) или клиента (Client), вызывающего сервис. Сервис ― набор операций (Operation), каждая из которых на входе принимает запрос (Request) и выдает ответ (Response). Клиент явным образом посылает (Sent) запрос, сервис явным образом получает (Receive) его и отвечает (Sent), высылая ответ. Клиент получает (Receive) ответ и на этом вызов завершался. В процессе RPC выполняются следующие шаги: Клиент, заглушка клиента и один экземпляр времени выполнения RPC выполняются на клиентском компьютере. Клиент запускает процесс-заглушку клиента, передавая параметры обычным способом. Клиентская заглушка хранится в собственном адресном пространстве клиента. Он также просит локальную среду выполнения RPC отправить обратно на заглушку сервера. На этом этапе RPC доступен для пользователя путем выполнения обычной локальной процедурной калибровки. RPC Runtime управляет передачей сообщений между сетью через клиент и сервер. Он также выполняет работу по повторной передаче, подтверждению, маршрутизации и шифрованию. После завершения серверной процедуры он возвращается к заглушке сервера, которая упаковывает (маршаллы) возвращаемые значения в сообщение. Затем заглушка сервера отправляет сообщение обратно на транспортный уровень. На этом этапе транспортный уровень отправляет сообщение с результатом клиентскому транспортному уровню, который возвращает сообщение клиентской заглушке. На этом этапе клиентская заглушка демаршаллизирует (распаковывает) возвращаемые параметры в результирующем пакете, и процесс выполнения возвращается вызывающей стороне. Характеристики RPC Вызываемая процедура находится в другом процессе, который находится на другом компьютере. Процессы не разделяют адресное пространство. Параметры передаются только по значениям. RPC выполняется в среде серверного процесса. Он не предлагает доступ к среде вызывающей процедуры. RpcStringBindingCompose Функция RpcStringBindingCompose создает дескриптор привязки строки. Код (C): RPC_STATUS RpcStringBindingCompose( RPC_CSTR ObjUuid, RPC_CSTR ProtSeq, RPC_CSTR NetworkAddr, RPC_CSTR Endpoint, RPC_CSTR Options, RPC_CSTR *StringBinding ); Параметры ObjUuid ― Указатель на строковое представление UUID объекта, заканчивающееся нулем. ProtSeq ― Указатель на строковое представление последовательности протокола, заканчивающееся нулем. NetworkAddr ― Указатель на строковое представление сетевого адреса, заканчивающееся нулем. Формат сетевого адреса связан с последовательностью протокола. endpoint ― Указатель на строковое представление endpoint, заканчивающееся нулем. Формат и содержимое endpoint связаны с последовательностью протокола. Например, endpoint, связан с последовательностью протокола ncacn_np, представляет собой имя канала в формате \pipe\pipename. Options ― Указатель на строковое представление параметров сети, заканчивающееся нулем. Строка параметра связана с последовательностью протокола. StringBinding — возвращает указатель на строковое представление дескриптора привязки, заканчивающееся нулем. Укажите значение NULL, чтобы RpcStringBindingCompose не возвращал параметр StringBinding. В этом случае приложение не вызывает RpcStringFree. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функцииRPC_S_INVALID_STRING_UUID6A9недопустимое строковое представление UUIDRpcBindingFromStringBinding Функция RpcBindingFromStringBinding возвращает дескриптор привязки из строкового представления дескриптора привязки. Код (C): RPC_STATUS RpcBindingFromStringBinding( RPC_CSTR StringBinding, RPC_BINDING_HANDLE *Binding ); Параметры StringBinding ― Указатель на строковое представление дескриптора привязки. Binding ― возвращает указатель на дескриптор привязки сервера. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функцииRPC_S_INVALID_ARG57Аргумент недействителенRPC_S_INVALID_STRING_BINDING6A4Привязка строки недействительнаRPC_S_PROTSEQ_NOT_SUPPORTED6A7Последовательность протоколов не поддерживается на этом хостеRPC_S_INVALID_RPC_PROTSEQ6A8Последовательность протокола недействительна.RPC_S_INVALID_ENDPOINT_FORMAT6AAНедопустимый формат endpoint.RPC_S_INVALID_NET_ADDR6ABНедействительный сетевой адрес.RPC_S_STRING_TOO_LONG6CFСлишком длинная строка.RPC_S_INVALID_NAF_ID6E3Недопустимый идентификатор семейства сетевых адресов.Функция RpcStringFree освобождает строку символов, выделенную библиотекой времени выполнения RPC. Код (C): RPC_STATUS RpcStringFree( RPC_CSTR *String ); Параметры String ― Указатель на указатель на строку символов, которую нужно освободить. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функции.Примечание Приложение отвечает за однократный вызов RpcStringFree для каждой строки символов, выделенной и возвращенной вызовами других процедур библиотеки времени выполнения RPC. NdrClientCall2 Функция NdrClientCall2 точка входа на стороне клиента для заглушки режима /Oicf. Код (C): CLIENT_CALL_RETURN RPC_VAR_ENTRY NdrClientCall2( [in] PMIDL_STUB_DESC pStubDescriptor, [in] PFORMAT_STRING pFormat, ... ); Параметры [in] pStubDescriptor ― Указатель на сгенерированную MIDL структуру MIDL_STUB_DESC, которая содержит информацию об описании удаленного интерфейса. [in] pFormat ― Указатель на строку формата процедуры, сгенерированную MIDL, которая описывает метод и параметры. ... Указатель на стек вызовов на стороне клиента. Возвращаемые значения Возвращаемое значение удаленного вызова. Максимальный размер возвращаемого значения эквивалентен размеру регистра системы. MIDL переключается на заглушку режима /Os, если размер возвращаемого значения больше размера регистра. В зависимости от определения метода эта функция может вызвать исключение в случае сбоя сети или сервера. Примечания Функция NdrClientCall2 используется всеми клиентскими заглушками режима /Oicf. Функция NdrClientCall2 передает все [in] данные на удаленный сервер и после получения ответного пакета возвращает значение [out] клиентскому приложению. NdrServerCall2 Функция NdrServerCall2 не предназначена для непосредственного вызова из приложения. Код (C): void NdrServerCall2( PRPC_MESSAGE pRpcMsg ); Параметры pRpcMsg ― зарезервировано. RpcServerUseProtseqEp Функция RpcServerUseProtseqEp указывает библиотеке времени выполнения RPC использовать указанную последовательность протоколов в сочетании с указанной конечной точкой для получения удаленных вызовов процедур. Код (C): RPC_STATUS RpcServerUseProtseqEp( RPC_CSTR Protseq, unsigned int MaxCalls, RPC_CSTR Endpoint, void *SecurityDescriptor ); Параметры Protseq ― указатель на строковый идентификатор последовательности протокола для регистрации в библиотеке времени выполнения RPC. MaxCalls ― длина очереди очереди для последовательности протокола ncacn_ip_tcp. Все другие последовательности протоколов игнорируют этот параметр. Используйте RPC_C_PROTSEQ_MAX_REQS_DEFAULT, чтобы указать значение по умолчанию. Endpoint ― указатель на информацию об адресе конечной точки, используемую при создании привязки для последовательности протоколов, указанной в параметре Protseq. SecurityDescriptor ― указатель на необязательный параметр, предоставленный для подсистемы безопасности. Используется только для последовательностей протоколов ncacn_np и ncalrpc. Все другие последовательности протоколов игнорируют этот параметр. Использование дескриптора безопасности на конечной точке для обеспечения безопасности сервера не рекомендуется. Этот параметр отсутствует в спецификации DCE для этого API. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функцииRPC_S_PROTSEQ_NOT_SUPPORTED6A7Последовательность протоколов не поддерживается на этом хостеRPC_S_INVALID_RPC_PROTSEQ6A8Последовательность протокола недействительна.RPC_S_INVALID_ENDPOINT_FORMAT6AAНедопустимый формат endpoint.RPC_S_OUT_OF_MEMORYC0000017Системе не хватает памяти.RPC_S_DUPLICATE_ENDPOINT6CCendpoint является дубликатомRPC_S_INVALID_SECURITY_DESC53AНедопустимый дескриптор безопасности.Примечания Серверное приложение вызывает RpcServerUseProtseqEp для регистрации одной последовательности протокола в библиотеке времени выполнения RPC. При каждой регистрации последовательности протоколов RpcServerUseProtseqEp включает указанную информацию об адресе конечной точки. Чтобы получать запросы на удаленный вызов процедур, сервер должен зарегистрировать хотя бы одну последовательность протоколов в библиотеке времени выполнения RPC. Серверное приложение может вызывать эту процедуру несколько раз, чтобы зарегистрировать дополнительные последовательности протоколов и конечные точки. Для каждой последовательности протокола, зарегистрированной сервером, библиотека времени выполнения RPC создает одну или несколько конечных точек, через которые сервер получает запросы удаленного вызова процедур. Библиотека времени выполнения RPC создает разные конечные точки для каждой последовательности протоколов. Однако каждый интерфейс в процессе доступен через любую конечную точку. Для MaxCalls значение, предоставляемое приложением, является лишь подсказкой. Это значение может быть переопределено средой выполнения RPC или поставщиком сокетов Windows. Например, в Windows XP или Windows 2000 Professional значение ограничено 5. Значения больше 5 игнорируются и вместо них используется 5. В Windows Server 2003 и Windows 2000 Server это значение будет учитываться. Приложения должны быть осторожны, чтобы передавать разумные значения в MaxCalls. Большие значения для Server, Advanced Server или Datacenter Server могут привести к использованию большого объема памяти невыгружаемого пула. Использование слишком малого значения также нежелательно, так как это может привести к тому, что пакеты TCP SYN будут встречены протоколом TCP RST с сервера, если очередь ожидания будет исчерпана. Разработчик приложения должен сбалансировать объем памяти и требования к масштабируемости при определении правильного значения для MaxCalls. Если компьютер настроен на использование выборочной привязки, успешный возврат не гарантирует, что сервер создал конечные точки для всех сетевых интерфейсов, присутствующих на компьютере. Среда выполнения RPC может не прослушивать некоторые сетевые интерфейсы в зависимости от настроек выборочной привязки. Кроме того, если интерфейс еще не получил IP-адрес с помощью DHCP, сервер RPC не прослушивает сетевой интерфейс, пока ему не будет назначен DHCP-адрес. Успешный возврат означает, что сервер прослушивает по крайней мере один сетевой интерфейс; полный список дескрипторов привязки, через которые могут быть получены удаленные вызовы процедур, можно получить с помощью вызова функции RpcServerInqBindings. RpcServerRegisterIf Функция RpcServerRegisterIf регистрирует интерфейс в библиотеке времени выполнения RPC. Код (C): RPC_STATUS RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID *MgrTypeUuid, RPC_MGR_EPV *MgrEpv ); Параметры IfSpec ― генерируемая MIDL структура, указывающая интерфейс для регистрации. MgrTypeUuid ― Указатель на UUID типа для связи с параметром MgrEpv. Указание нулевого значения параметра (или нулевого UUID) регистрирует IfSpec с нулевым UUID. MgrEpv ― Вектор точек входа (EPV) подпрограмм менеджера. Чтобы использовать EPV по умолчанию, сгенерированный MIDL, укажите нулевое значение. Возвращаемое значение Возвращает RPC_S_OK в случае успеха. Примечания Сервер может зарегистрировать неограниченное количество интерфейсов в библиотеке времени выполнения RPC. Регистрация делает интерфейс доступным для клиентов, используя дескриптор привязки к серверу. Чтобы зарегистрировать интерфейс, код серверного приложения вызывает RpcServerRegisterIf. Для каждой реализации интерфейса, которую предлагает сервер, он должен зарегистрировать отдельный EPV менеджера. При вызове RpcServerRegisterIf сервер предоставляет следующую информацию: Спецификация интерфейса. Спецификация интерфейса — это структура данных, которую генерирует компилятор MIDL. Сервер указывает интерфейс с помощью параметра IfSpec. UUID типа менеджера и EPV менеджера ― UUID типа менеджера и EPV менеджера определяют, какая подпрограмма менеджера выполняется, когда сервер получает запрос удаленного вызова процедуры от клиента. Сервер указывает UUID и EPV типа менеджера, используя параметры MgrTypeUuid и MgrEpv. Обратите внимание, что при указании UUID типа менеджера, отличного от nil, сервер должен также вызывать функцию RpcObjectSetType для регистрации объектов этого отличного от nil типа. Если вашему серверному приложению необходимо зарегистрировать интерфейс автоматического прослушивания или использовать функцию обратного вызова для аутентификации, используйте RpcServerRegisterIfEx. RpcServerListen Функция RpcServerListen сигнализирует библиотеке времени выполнения RPC прослушивать удаленные вызовы процедур. Эта функция не повлияет на интерфейсы автоматического прослушивания; используйте RpcServerRegisterIfEx , если вам нужна эта функциональность. Код (C): RPC_STATUS RpcServerListen( unsigned int MinimumCallThreads, unsigned int MaxCalls, unsigned int DontWait ); Параметры MinimumCallThreads ― подсказка для среды выполнения RPC, указывающая минимальное количество потоков вызовов, которые должны быть созданы и поддерживаться на данном сервере. Это значение является лишь подсказкой и интерпретируется по-разному в разных версиях Windows. В Windows XP это значение представляет собой количество ранее созданных потоков в каждом пуле потоков, которые создает среда выполнения RPC. Приложение должно указать один для этого параметра и отложить принятие решений о создании потока во время выполнения RPC. MaxCalls ― рекомендуемое максимальное количество одновременных удаленных вызовов процедур, которые может выполнить сервер. Чтобы обеспечить эффективную производительность, библиотеки времени выполнения RPC интерпретируют параметр MaxCalls как предлагаемый предел, а не как абсолютную верхнюю границу. Используйте RPC_C_LISTEN_MAX_CALLS_DEFAULT , чтобы указать значение по умолчанию. DontWait ― флаг, управляющий возвратом от RpcServerListen. Ненулевое значение указывает, что RpcServerListen должен вернуться сразу после завершения обработки функции. Нулевое значение указывает, что RpcServerListen не должен возвращаться до тех пор, пока не будет вызвана функция RpcMgmtStopServerListening и не будут завершены все удаленные вызовы. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функцииRPC_S_ALREADY_LISTENING6B1Сервер уже в режиме прослушивания.RPC_S_NO_PROTSEQS_REGISTERED6B2Протокольные последовательности не зарегистрированы.RPC_S_MAX_CALLS_TOO_SMALL6CEМаксимальное значение вызовов слишком мало.RpcServerUnregisterIf Функция RpcServerUnregisterIf удаляет интерфейс из реестра библиотеки времени выполнения RPC. Код (C): RPC_STATUS RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID *MgrTypeUuid, unsigned int WaitForCallsToComplete ); Параметры IfSpec ― Интерфейс для удаления из реестра. Укажите нулевое значение, чтобы удалить все интерфейсы, ранее зарегистрированные со значением UUID типа, указанным в параметре MgrTypeUuid. MgrTypeUuid ― указатель на тип UUID вектора точки входа менеджера (EPV), который необходимо удалить из реестра. Значение MgrTypeUuid должно быть тем же значением, которое было предоставлено при вызове функции RpcServerRegisterIf, RpcServerRegisterIf2 или функции RpcServerRegisterIfEx. Укажите нулевое значение, чтобы удалить интерфейс, указанный в параметре IfSpec, для всех ранее зарегистрированных UUID типов из реестра. Укажите нулевой UUID, чтобы удалить EPV менеджера по умолчанию, сгенерированный MIDL, из реестра. В этом случае все EPV менеджера, зарегистрированные с UUID отличного от nil типа, остаются зарегистрированными. WaitForCallsToComplete ― флаг, указывающий, следует ли немедленно удалить интерфейс из реестра или дождаться завершения всех текущих вызовов. Укажите нулевое значение, чтобы игнорировать текущие вызовы и немедленно удалить интерфейс из реестра. Укажите любое ненулевое значение для ожидания завершения всех активных вызовов. Возвращаемые значения ЗначениеhexОписаниеRPC_S_OK0Успешный вызов функцииRPC_S_UNKNOWN_MGR_TYPE6B4Тип менеджера неизвестен.RPC_S_UNKNOWN_IF6B5Интерфейс неизвестен.
Атрибут ncalrpcКлючевое слово ncalrpc определяет локальную межпроцессную связь как семейство протоколов для endpoint. Это ключевое слово является одним из допустимых имен семейств протоколов, которые должны использоваться с атрибутом endpoint. Код (C): endpoint("ncalrpc:[port-name]") Параметрыport-name Символьная строка, задающая порт связи (приложение, служба или экземпляр службы), который клиент использует для выполнения межпроцессных вызовов к серверу. Строка может содержать до 53 символов и не должна содержать символы обратной косой черты (\). Имя компьютера не должно использоваться с ключевым словом ncalrpc . Синтаксис строки локального межпроцессного порта, как и все строки портов, определяется реализацией транспорта и не зависит от спецификации IDL. Компилятор MIDL выполняет ограниченную проверку синтаксиса, но не гарантирует правильность спецификации endpoint. Некоторые классы ошибок могут сообщаться во время выполнения, а не во время компиляции.Атрибут endpointАтрибут [endpoint] указывает известный порт или порты (endpoint связи), на которых серверы интерфейса прослушивают вызовы. Код (C): endpoint("protocol-sequence:[endpoint-port]" [ , ...] ) Параметрыпоследовательность протоколов Задает символьную строку, представляющую допустимое сочетание протокола RPC (например, ncacn), транспортного протокола (например, tcp) и сетевого протокола (например, ip). Список допустимых последовательностей протоколовMicrosoft RPC поддерживает следующие последовательности протоколов. КонстантаЗначениеОписаниеncacn_nb_tcpПротокол TCP, ориентированный на подключение NetBIOSТолько клиент: MS-DOS, клиент Windows 3.x и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NTncacn_nb_ipxОриентированные на подключение NetBIOS через интернет-пакет Exchange (IPX)Только клиент: MS-DOS, клиент Windows 3.x и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NTncacn_nb_nbОриентированный на подключение пользовательский интерфейс NetBIOS (NetBEUI)Только клиент: MS-DOS, Windows 3.x Client and Server: Windows Server 2003, Windows XP, Windows 2000, Windows NT, Windows Me, Windows 98, Windows 95ncacn_ip_tcpПротокол TCP/IP, ориентированный на подключениеТолько клиент: MS-DOS, Windows 3.x и клиент и сервер Apple Macintosh: Windows Server 2003, Windows XP, Windows 2000, Windows NT, Windows Me, Windows 98, Windows 95ncacn_npИменованные каналы, ориентированные на подключениеТолько клиент: MS-DOS, Windows 3.x, Windows 95 Client and Server: Windows Server 2003, Windows XP, Windows 2000, Windows NTncacn_spxExchange пакетов, ориентированных на подключение (SPX)Только клиент: MS-DOS, Windows 3.x Client and Server: Windows Server 2003, Windows XP, Windows 2000, Windows NT, Windows Me, Windows 98, Windows 95ncacn_dnet_nspТранспорт DECnet, ориентированный на подключениеТолько клиент: MS-DOS, Windows 3.xncacn_at_dspПоставщик служб DSP AppleTalk, ориентированный на подключениеКлиент: Apple Macintosh Server: Windows Server 2003, Windows XP, Windows 2000, Windows NTncacn_vns_sppТранспорт масштабируемой параллельной обработки с ориентацией на подключение (SPP)Только клиент: MS-DOS, клиент Windows 3.x и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NTncadg_ip_udpDatagram (без подключения) User Datagram Protocol/Internet Protocol (UDP/IP)Только клиент: MS-DOS, клиент Windows 3.x и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NTncadg_ipxDatagram (без подключения) IPXТолько клиент: MS-DOS, клиент Windows 3.x и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NTncadg_mqДатаграмма (без подключения) через сервер очереди сообщений Майкрософт (MSMQ)Только клиент: Windows Me/98/95 Client and Server: Windows Server 2003, Windows XP, Windows 2000, Windows NT Server 4.0 с пакетом обновления 3 (SP3) и более поздних версийncacn_httpПротокол TCP/IP, ориентированный на подключение, с помощью Microsoft Internet Information Server в качестве прокси-сервера HTTPТолько клиент: Windows Me/98/95 Client and Server: Windows Server 2003, Windows XP, Windows 2000ncalrpcВызов локальной процедурыКлиент и сервер: Windows Server 2003, Windows XP, Windows 2000, Windows NT, Windows Me, Windows 98, Windows 95порт endpoint Указывает строку, представляющую назначение endpoint для указанного семейства протоколов. Синтаксис строки порта зависит от каждой последовательности протоколов. Атрибут [endpoint] указывает семейство транспорта, такое как протокол, ориентированный на подключение TCP/IP, протокол, ориентированный на подключение NetBIOS, или протокол, ориентированный на подключение с именованным каналом. Использование атрибута [endpoint] согласуется с другими методами добавления endpoint и не предоставляет дополнительные или специальные службы для endpoint; он просто предоставляет ярлык для вызова API. Передача текста, картинок и музыки между приложениями практически мгновенная! Текст приложения-сервера 14r.asm Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 IDC_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 RPC_S_OK equ 0 RPC_C_LISTEN_MAX_CALLS_DEFAULT equ 1234 RPC_VERSION struc MajorVersion dw ? MinorLinker dw ? RPC_VERSION ends RPC_SERVER_INTERFACE struct Len dd ? InterfaceId GUID <> a RPC_VERSION <> TransferSyntax GUID <> b RPC_VERSION <> dd ? DispatchTable dq ? RpcProtseqEndpointCount dd ?,? RpcProtseqEndpoint dq ? DefaultManagerEpv dq ? InterpreterInfo dq ? Flags dd ?,? RPC_SERVER_INTERFACE ends .code WinMain proc enter 30h,0 mov r9d,offset DialogProc and qword ptr[rbp-10h],0 invoke DialogBoxParamA,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_DESTROY je wmDESTROY xor eax,eax jmp exit0 wmDESTROY: jmp wmBYE wmINITDIALOG:mov hWnd,rcx invoke GetProcessHeap mov hHeap,rax ; Найти окно отправителя mov edx,offset szWin invoke FindWindowA,NULL or eax,eax jnz wmBYE mov edx,offset Error1 mov r8d,offset szAppName invoke MessageBoxA,hWnddlg,,,MB_ICONEXCLAMATION or MB_YESNO cmp eax,IDNO jz wmBYE mov ecx,offset szService invoke WinExec,,SW_SHOW ;start Rpc Server And Listen--------------------------------- mov r8d,offset endpoint mov ecx,offset protocol invoke RpcServerUseProtseqEpA,,RPC_C_LISTEN_MAX_CALLS_DEFAULT,,0 or eax,eax;cmp eax,RPC_S_OK jz @f mov edx,offset Format jmp @0 @@: mov ecx,offset RPC_SampleInterface_v1_0_s_ifspec invoke RpcServerRegisterIf,,0,0 or eax,eax;cmp eax,RPC_S_OK jz @f mov edx,offset aUnableToRegist jmp @0 ; Start to listen for remote procedure ; calls for all registered interfaces. ; This call will not return until ; RpcMgmtStopServerListening is called. @@: invoke RpcServerListen,1,\;Recommended minimum number of threads. RPC_C_LISTEN_MAX_CALLS_DEFAULT,\;Recommended maximum number of threads TRUE or eax,eax;cmp eax,RPC_S_OK jz wmBYE mov edx,offset aUnableToStartL mov r8d,offset szAppName invoke MessageBoxA,hWnddlg,,,MB_ICONEXCLAMATION or MB_OK mov ecx,offset RPC_SampleInterface_v1_0_s_ifspec invoke RpcServerUnregisterIf,,0,0 or eax,eax;cmp eax,RPC_S_OK jz wmBYE mov edx,offset aUnableToUnregi @0: mov r8d,offset szAppName invoke MessageBoxA,hWnddlg,,,MB_ICONEXCLAMATION or MB_OK jmp wmBYE ;-------------------------------------------------- wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp j_NdrServerCall2 proc jmp NdrServerCall2 j_NdrServerCall2 endp ; Memory allocation function for RPC. ; The runtime uses these two functions for allocating/deallocating ; enough memory to pass the string to the server. MIDL_user_allocate proc len:qword mov r8d,ecx invoke RtlAllocateHeap,hHeap,0 leave retn MIDL_user_allocate endp MIDL_user_free proc lpMem:qword mov r8d,ecx invoke HeapFree,hHeap,0 leave retn MIDL_user_free endp RPC_SampleInterface_sampleFunc proc handle_t:qword,size_:dword,buffer:qword local hWaveOut:qword local lpwiocb:WAVEHDR mov buffer,r8 mov size_,edx mov handle_t,rcx cmp byte ptr[r8],CF_TEXT jne @f and byte ptr[r8+rdx],0 inc r8 invoke SetDlgItemTextA,hWnd,IDC_TXT;,buffer jmp @0 ;------------------------------------------------------------------ @@: cmp byte ptr[r8],CF_BITMAP jne @f lea ecx,[r8+1] invoke CreateIconFromResourceEx,,,TRUE,30000h,256,256,LR_DEFAULTCOLOR invoke SendDlgItemMessageA,hWnd,ID_ICON,STM_SETIMAGE,IMAGE_ICON,eax jmp @0 ;------------------------------------------------------------------ @@: mov r8,buffer ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data) = 14h add r8d,14h invoke waveOutOpen,&hWaveOut,WAVE_MAPPER,,0,0,WAVE_ALLOWSYNC ; Подготавливаем заголовок для вывода lea edi,lpwiocb mov edx,edi xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,buffer ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data)+\ ;(Type of format)+(Number of Channels)+(Sample Rate)+(Sample Rate*BitsPerSample*Channels/8)+\ ;(BitsPerSample*Channels/8)+(Bits per sample)+(“data” chunk header)+(Size of the data section)=2Ch add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,size_ sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока invoke waveOutWrite,hWaveOut,&lpwiocb,sizeof WAVEHDR @@: test lpwiocb.dwFlags,WHDR_DONE jz @b invoke waveOutUnprepareHeader,hWaveOut,&lpwiocb,sizeof WAVEHDR invoke waveOutClose,hWaveOut @0: leave retn RPC_SampleInterface_sampleFunc endp ;----------------------------------------------------------------------- .data szWin db "Remote Procedure Call Sender",0 Error1 db "The server is not running.",10,"Run?",0 szAppName db "Remote Procedure Call Reciever",0 szService db "14s",0 protocol db "ncalrpc",0 endpoint db "{46E785FC-BCCC-46B8-B161-D6C90D391670}",0; // Unique user-defined endpoint ID in a free form Format db "Unable to setup protocol sequence",0 aUnableToRegist db "Unable to register the interface",0 aUnableToStartL db "Unable to start listening",0 aUnableToUnregi db "Unable to unregister the interface",0 hWnd dq ? hHeap dq ? ; RPC_SampleInterface_v1_0_s_ifspec label RPC_SERVER_INTERFACE dd sizeof RPC_SERVER_INTERFACE;Length GUID <8A4A7813h,0ADAAh,49BCh,{99h,6Ah,4Dh,47h,71h,5Fh,0CAh,40h}> RPC_VERSION <1,0> ;RPC_VERSION MajorVersion: u16, MinorVersion: u16 +14 GUID <8A885D04h,1CEBh,11C9h,{9Fh,0E8h,8,0,2Bh,10h,48h,60h}> ;+20 RPC_VERSION <2,0> ;RPC_VERSION MajorVersion: u16, MinorVersion: u16 +28 dd 0 ;+2C dq RPC_SampleInterface_v1_0_DispatchTable;DispatchTable: *mut RPC_DISPATCH_TABLE +30 dd 0,0 ;RpcProtseqEndpointCount: u32 +38 dq 0 ;RpcProtseqEndpoint: *mut RPC_PROTSEQ_ENDPOINT +3C dq 0 ;DefaultManagerEpv: *mut c_void +44 dq RPC_SampleInterface_ServerInfo;InterpreterInfo: *const c_void +4C dd 4000000h ;Flags: u32 RPC_SampleInterface_v1_0_DispatchTable: dq 1 dq RPC_SampleInterface_table dq 0 RPC_SampleInterface_table: dq j_NdrServerCall2 dq 0 ;--------------------------------------------- RPC_SampleInterface_ServerInfo: dq RPC_SampleInterface_StubDesc dq RPC_SampleInterface_ServerRoutineTable dq RPC_SampleInterface__MIDL_ProcFormatString dq RPC_SampleInterface_FormatStringOffsetTable dq 0 dq 0 dq 0 dq 0 RPC_SampleInterface_StubDesc: dq RPC_SampleInterface_v1_0_s_ifspec dq MIDL_user_allocate dq MIDL_user_free dq 0 dq 0 dq 0 dq 0 dq 0 dq RPC_SampleInterface__MIDL_TypeFormatString dd 1 dd 50002h dq 0 dd 8010274h dq 0 dq 0 dq 0 dd 0 dq 1 dq 0 dq 0 dq 0 ;------------------------------------------ RPC_SampleInterface_ServerRoutineTable dq RPC_SampleInterface_sampleFunc RPC_SampleInterface__MIDL_ProcFormatString: db 0,48h dd 0 dw 0 dw 18h db 32h,0 dw 0 dw 8 dw 0 db 42h,2,0Ah,5 dw 0 dw 1 dw 0 dw 0 dw 48h dw 8 db 8,0 dw 10Bh dw 10h dw 6 db 0 RPC_SampleInterface_FormatStringOffsetTable: dd 0 RPC_SampleInterface__MIDL_TypeFormatString: dw 0 db 11h,0 dw 2 db 1Bh,0 dw 1 db 29h,0 dw 8 dw 1 db 2,5Bh,0 end ресурсы (14r.rc) Код (C): #include "resource.h" #define IDC_DIALOG 200 #define IDC_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Remote Procedure Call Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Exit",IDCANCEL,149,27,60,15 CONTROL 1,ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END Текст приложения-клиента (14s.asm) Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 RPC_S_OK equ 0 RPC_C_LISTEN_MAX_CALLS_DEFAULT equ 1234 RPC_VERSION struc MajorVersion dw ? MinorLinker dw ? RPC_VERSION ends RPC_CLIENT_INTERFACE struct Len dd ? InterfaceId GUID <> a RPC_VERSION <> TransferSyntax GUID <> b RPC_VERSION <> dd ? DispatchTable dq ? RpcProtseqEndpointCount dd ?,? RpcProtseqEndpoint dq ? DefaultManagerEpv dq ? InterpreterInfo dq ? Flags dd ?,? RPC_CLIENT_INTERFACE ends .code WinMain proc enter 30h,0 mov r9d,256;cx mov [rbp-10h],r9 mov qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImageA,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rbp-10h],rax;30h-10h=+20h invoke DialogBoxParamA,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local hResource:qword local pResource:qword local FSize:qword local hFile:dword local szReadWrite:qword ;number of bytes actually read or write local stringBinding:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_DESTROY je wmDESTROY xor eax,eax jmp exit0 wmDESTROY: jmp wmBYE wmSEND_WAV:mov ecx,offset wav_file invoke CreateFile,,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,\ FILE_ATTRIBUTE_ARCHIVE,0 mov hFile,eax invoke GetFileSize,eax,0 mov FSize,rax invoke GlobalAlloc,GPTR,eax mov p,rax lea r9d,szReadWrite and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile invoke RPC_SampleInterface_sampleFunc,bindingHandle,FSize,p jmp wmBYE wmSEND_ICO:mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,rax inc eax invoke GlobalAlloc,GPTR,eax mov p,rax mov edi,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov esi,eax mov byte ptr[rdi],CF_BITMAP inc edi mov rcx,FSize rep movsb mov rdx,FSize inc edx invoke RPC_SampleInterface_sampleFunc,bindingHandle,,p mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov [rsp+20h],rcx mov [rsp+28h],rcx mov rcx,p inc ecx invoke CreateIconFromResourceEx,,FSize,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessageA,hWnd,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,256 mov p,rax mov byte ptr[rax],CF_TEXT inc eax invoke GetDlgItemTextA,hWnddlg,ID_TXT,eax,256 inc eax invoke RPC_SampleInterface_sampleFunc,bindingHandle,eax,p jmp wmBYE wmINITDIALOG:mov hWnd,rcx invoke GetProcessHeap mov hHeap,rax invoke GetDlgItem,hWnddlg,IDC_IMG1 invoke SendMessageA,eax,STM_SETIMAGE,IMAGE_ICON,lParam ;setup Rpc----------------------------- lea ecx,stringBinding mov [rsp+28h],rcx movr qword ptr[rsp+20h],security mov r9d,offset endpoint mov edx,offset protocol invoke RpcStringBindingComposeA,0,,0 or eax,eax;eax=RPC_S_OK? jne wmBYE mov edx,offset bindingHandle invoke RpcBindingFromStringBindingA,stringBinding invoke RpcStringFreeW,&stringBinding or eax,eax;eax=RPC_S_OK? jne wmBYE ;---------------------------------------------------- cmp bindingHandle,0 jnz wmBYE mov r8d,offset szWin mov ecx,offset Error invoke MessageBoxA,hWnd,,,MB_OK jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 mov ecx,offset bindingHandle invoke RpcBindingFree wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp RPC_SampleInterface_sampleFunc proc bindingHandle:qword,bufferLength:dword,buffer:qword mov [rsp+20h],r8;buffer mov r9d,edx;bufferLength mov r8,rcx;bindingHandle lea rdx, RPC_SampleInterface__MIDL_ProcFormatString lea rcx,RPC_SampleInterface_StubDesc ; pStubDescriptor invoke NdrClientCall2 leave retn RPC_SampleInterface_sampleFunc endp MIDL_user_allocate proc len:qword mov r8d,ecx invoke RtlAllocateHeap,hHeap,0 leave ret MIDL_user_allocate endp MIDL_user_free proc lpMem:qword mov r8d,ecx invoke HeapFree,hHeap,0 leave ret MIDL_user_free endp ;--------------------------------------- .data szWin db 'Remote Procedure Call Reciever',0 Error db "Unable to setup an RPC connection, exiting...",0 bindingHandle dq ? hWnd dq ? protocol db "ncalrpc",0 endpoint db "{46E785FC-BCCC-46B8-B161-D6C90D391670}",0; // Unique user-defined endpoint ID in a free form security db "Security=impersonation static false",0 p dq ? p1 dd 1 RPC_SampleInterface__MIDL_ProcFormatString: db 0 db 48h ; H dd 0 dw 0 dw 18h db 32h, 0 dw 0 dw 8 dw 0 db 42h,2,10,5 dw 0 dw 1 dw 0 dw 0 dw 48h dw 8 db 8, 0 dw 10Bh dw 10h dw 6 db 0 RPC_SampleInterface_StubDesc: dq RPC_SampleInterface___RpcClientInterface; RpcInterfaceInformation dq MIDL_user_allocate; pfnAllocate dq MIDL_user_free; pfnFree dq RPC_SampleInterface__MIDL_AutoBindHandle; IMPLICIT_HANDLE_INFO.pAutoHandle dq 0 ; apfnNdrRundownRoutines dq 0 ; aGenericBindingRoutinePairs dq 0 ; apfnExprEval dq 0 ; aXmitQuintuple dq RPC_SampleInterface__MIDL_TypeFormatString; pFormatTypes dd 1 ; fCheckBounds dd 50002h ; Version dq 0 ; pMallocFreeStruct dd 8010274h ; MIDLVersion db 4 dup(0) dq 0 ; CommFaultOffsets dq 0 ; aUserMarshalQuadruple dq 0 ; NotifyRoutineTable dq 1 ; mFlags dq 0 ; CsRoutineTables dq 0 ; ProxyServerInfo dq 0 ; pExprInfo RPC_SampleInterface___RpcClientInterface label RPC_CLIENT_INTERFACE dd sizeof RPC_CLIENT_INTERFACE;Length struct;+0 GUID <8A4A7813h,0ADAAh,49BCh,{99h,6Ah,4Dh,47h,71h,5Fh,0CAh,40h}> RPC_VERSION <1,0> GUID <8A885D04h,1CEBh,11C9h,{9Fh,0E8h,8,0,2Bh,10h,48h,60h}> RPC_VERSION <2,0> dd 0;+2C dq 0; PRPC_DISPATCH_TABLE DispatchTable;+30h dd 0,0; unsigned int RpcProtseqEndpointCount;+38h dq 0; PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint;+40h dq 0; ULONG_PTR Reserved;+48h dq 0; void const *InterpreterInfo;+50h dq 0;+58h dd 0;unsigned int Flags;+5Ch RPC_SampleInterface__MIDL_AutoBindHandle dq 0,0 RPC_SampleInterface__MIDL_TypeFormatString: dw 0 db 11h,0 dw 2 db 1Bh,0 dw 1 db 29h,0 dw 8 dw 1 db 2,5Bh,0 ;------------------------------- hHeap dq ? wav_file db '..\Images\03.wav',0 end ресурсы (14s.rc) Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_IMG1 104 #define IDC_DIALOG 200 #define IDC_ICON1 500 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Remote Procedure Call Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW | WS_VISIBLE | SS_ICON,5,23,128,128 CONTROL "Write something and click 'Send Text'",ID_TXT,"EDIT",WS_BORDER|WS_TABSTOP|ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Send Text",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Send ICO", ID_SEND_ICO,149,45,60,15 PUSHBUTTON "Send WAV", ID_SEND_WAV,149,65,60,15 PUSHBUTTON "Exit", IDCANCEL, 149,85,60,15 END в аттаче ASM-/RC-/EXE-файлы
15. DLL Текст приложения-сервера (15s.asm) Код (ASM): ; GUI # include win64a.inc includelib IPC.lib ExeToDll PROTO :qword,:dword,:dword DllToExe PROTO :qword,:dword,:dword ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 .code WinMain proc ;dummy:qword enter 30h,0 mov r9d,256 mov [rbp-10h],r9 and qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImageA,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,0,0,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov [rbp-10h],rax invoke DialogBoxParamA,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local buffer:qword local cdata:COPYDATASTRUCT local FSize:dword local hFile:dword local p:qword local szReadWrite:qword ;number of bytes actually read or write local hResource:qword local pResource:qword local temp:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:invoke GetDlgItem,,IDC_IMG1 invoke SendMessageA,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,256 mov buffer,rax invoke GetDlgItemTextA,hWnddlg,ID_TXT,eax,256 or eax,eax jz wmBYE inc eax mov FSize,eax invoke ExeToDll,buffer,eax,CF_TEXT ; Найти окно получателя mov edx,offset szWin invoke FindWindowA,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov r9d,FSize shl r9,8 or r9,CF_TEXT mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],5000 and qword ptr[rsp+30h],0 invoke SendMessageTimeoutA,eax,WM_USER+1,hWnddlg jmp wmBYE wmSEND_ICO:mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov p,rax ;------------------------------------------------- mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov [rsp+20h],rcx mov [rsp+28h],rcx mov edx,FSize invoke CreateIconFromResourceEx,p,,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessageA,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b mov edx,FSize invoke ExeToDll,p,,CF_BITMAP ; Найти окно получателя mov edx,offset szWin invoke FindWindowA,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov r9d,FSize shl r9,8 or r9,CF_BITMAP mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],5000 and qword ptr[rsp+30h],0 invoke SendMessageTimeoutA,eax,WM_USER+1,hWnddlg jmp wmBYE wmSEND_WAV:mov ecx,offset wav_file invoke CreateFile,,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,\ FILE_ATTRIBUTE_ARCHIVE,0 mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax invoke GlobalAlloc,GPTR,eax mov p,rax lea r9d,szReadWrite and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile mov edx,FSize invoke ExeToDll,p,,CF_WAVE ; Найти окно получателя mov edx,offset szWin invoke FindWindowA,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov r9d,FSize shl r9,8 or r9,CF_WAVE mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],500 and qword ptr[rsp+30h],0 invoke SendMessageTimeoutA,eax,WM_USER+1,hWnddlg jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: xor eax,eax leave retn DialogProc endp ;--------------------------------------- .data szWin db 'DLL Reciever',0 wav_file db '..\Images\03.wav',0 p1 dd 1 end ресурсы (15s.rc) Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_IMG1 104 #define IDC_DIALOG 200 #define IDC_ICON1 500 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOGEX 200, 0, 212, 154 STYLE DS_MODALFRAME | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "DLL Sender" { CONTROL "",-1,BUTTON,BS_GROUPBOX | WS_CHILD | WS_VISIBLE,2,-1,207,24 CONTROL "",IDC_IMG1,STATIC,SS_ICON | WS_CHILD | WS_VISIBLE,3,40,128,128 CONTROL "Write something and click 'Send Text'",ID_TXT,EDIT,ES_LEFT | ES_AUTOHSCROLL|WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP,5,7,199,13 CONTROL "Send Text", ID_SEND_TXT, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 149, 27, 60, 15 CONTROL "Send ICO", ID_SEND_ICO, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 149, 45, 60, 15 CONTROL "Send WAV", ID_SEND_WAV, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 149, 65, 60, 15 CONTROL "Exit",IDCANCEL,BUTTON,BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 149, 85, 60, 15 } Текст приложения-клиента (15r.asm) Код (ASM): ; GUI # include win64a.inc includelib IPC.lib ExeToDll PROTO :qword,:dword,:dword DllToExe PROTO :qword,:dword,:dword IDC_DIALOG equ 200 ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 .code WinMain proc dummy:qword invoke DialogBoxParamA,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP,qword ptr(offset DialogProc),0 invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local p:qword local FSize:dword local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG jne wmBYE wmINITDIALOG:;mov rcx,hWnd ; Найти окно получателя invoke FindWindowA,0,&szWin or eax,eax jnz wmBYE invoke MessageBoxA,hWnddlg,&Error1,&szAppName,MB_ICONEXCLAMATION or MB_YESNO cmp eax,IDNO jz wmBYE invoke WinExec,&szService,SW_SHOW jmp wmBYE wmUSER_1:cmp r9b,CF_TEXT je COPY_TEXT cmp r9b,CF_BITMAP; Это нужный тип данных? je COPY_ICON cmp r9b,CF_WAVE jne wmBYE shr r9,8 mov FSize,r9d invoke DllToExe mov p,rax mov r8,p ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data) = 14h add r8d,14h invoke waveOutOpen,&hWaveOut,WAVE_MAPPER,,0,0,WAVE_ALLOWSYNC ; Подготавливаем заголовок для вывода lea edi,lpwiocb mov edx,edi xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,p ;"RIFF"+(File size)+(File Type Header)+(Format chunk marker)+(Length of format data)+\ ;(Type of format)+(Number of Channels)+(Sample Rate)+(Sample Rate*BitsPerSample*Channels/8)+\ ;(BitsPerSample*Channels/8)+(Bits per sample)+(“data” chunk header)+(Size of the data section)=2Ch add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,FSize sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока invoke waveOutWrite,hWaveOut,&lpwiocb,sizeof WAVEHDR @@: test lpwiocb.dwFlags,WHDR_DONE jz @b invoke waveOutUnprepareHeader,hWaveOut,&lpwiocb,sizeof WAVEHDR invoke waveOutClose,hWaveOut jmp wmBYE COPY_TEXT:invoke DllToExe invoke SetDlgItemTextA,hWnddlg,ID_TXT,eax jmp wmBYE COPY_ICON:shr r9,8 mov FSize,r9d invoke DllToExe ; Создать HICON напрямую из памяти invoke CreateIconFromResourceEx,eax,FSize,TRUE,30000h,256,256,LR_DEFAULTCOLOR invoke SendDlgItemMessageA,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON,eax jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: xor eax,eax leave retn DialogProc endp .data szWin db "DLL Sender",0 Error1 db "The server is not running.",10,"Run?",0 szAppName db "DLL Reciever",0 szService db "15s",0 ClassName db 'DLGCLASS',0 end ресурсы приложения-клиента (15r.rc) Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 #define ID_PROGRESS 106 #define ID_TXT1 107 IDC_DIALOG DIALOGEX 0,0,212,154 STYLE DS_MODALFRAME | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "DLL Reciever" { CONTROL "",-1,BUTTON,BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 2,-3,207,24 CONTROL "", ID_TXT, STATIC, SS_LEFT | SS_NOPREFIX | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 5, 5, 199, 13 CONTROL "Exit", IDCANCEL, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 149, 25, 60, 15 CONTROL "",ID_ICON, STATIC, SS_ICON | WS_CHILD | WS_VISIBLE,3,40,128,128 } Текст IPC.dll Код (ASM): ; DLL # include win64a.inc .code .code DllMain proc hInstDLL:QWORD, reason:QWORD, unused:QWORD mov eax,TRUE leave ret DllMain Endp DllToExe proc lea rax,bufferDLL ret DllToExe endp ExeToDll proc buffer:qword,FSize:dword,type0:dword mov buffer,rcx mov FSize,edx lea rdi,bufferDLL mov ecx,FSize mov rsi,buffer rep movsb leave ret ExeToDll endp .data? bufferDLL db 8000000 dup(?) end Текст IPC.def Код (Text): LIBRARY IPC EXPORTS ExeToDll EXPORTS DllToExe в аттаче ASM-/RC-/EXE-/DLL-/DEF-/LIB-файлыИспользованы материалы: CyberManiac IPC mort[MATRiX] Взаимодействие между процессами mort[MATRiX] Синхронизация manhunter Обмен данными между процессами с помощью WM_COPYDATA manhunter Как сделать ProgressBar с надписью Алекс Jenter IPC: основы межпроцессного взаимодействия (Обзор технологий) Александр Фролов, Григорий Фролов Операционная система MS Windows 3.1 для программиста. Дополнительные главы. Александр Фролов, Григорий Фролов Программирование для Windows NT. Часть 1 Александр Фролов, Григорий Фролов Программирование для Windows NT. Часть 2
Клиент серверное приложение для мгновенного обмена сообщениями Написал простое клиент-серверное приложение на winsock2, в репозитории client и server, server работает в консоли, может обслуживать сразу нескольких клиентов синхронно через select, client отправляет сообщение серверу, а сервер броадкастит его всем подключенным клиентам. В README есть туду лист, со временем буду дополнять https://github.com/babasuck/sendsock/ (ветка dev)
редко когда ее делаю, сейчас памяти так много, что об этом думать лишний раз не приходится, тем более выделяется мало --- Сообщение объединено, 21 окт 2023 --- Хотя там для строки выделяется произвольного размера, добавлю все таки, спасибо
Да. память счас дешевле некуда 32 Гигабайта 50$ жаль еще нету планок по 64/128 ГБ --- Сообщение объединено, 21 окт 2023 --- Хотя пишут на серверах уже есть планки по 512 ГБ !!?? и даже по ТЕРАБАЙТУ?? https://www.tomshardware.com/news/samsung-talks-1tb-ddr5-modules-ddr5-7200
Возникла такая проблема,не получается создать пайп-сервер,компилю код сервера и запускаю,а клиент запускаю под отладчиком,так вот после вызова функции CreateFileA сервер прекращает свою работу. код на FASM сервер: Код (ASM): format PE console include 'win32axp.inc' section '.text' code readable executable invoke CreateNamedPipeA,namedpip,PIPE_ACCESS_DUPLEX,PIPE_TYPE_BYTE OR PIPE_WAIT,PIPE_UNLIMITED_INSTANCES,512,512,0,0 mov [desc],eax invoke ConnectNamedPipe,eax,0 invoke ReadFile,desc,namedpip,10,info,0 invoke ExitProcess,0 section '.data' data readable writeable namedpip db '\\.\pipe\channel',0 desc rd 0 buffer rb 10 info rd 0 section '.idata' import data readable writeable library kernel32,'kernel32.dll',\ msvcrt,'msvcrt.dll',\ user32,'user32.dll' import kernel32,\ ReadConsoleA,'ReadConsoleA',\ WriteConsoleA,'WriteConsoleA',\ GetStdHandle,'GetStdHandle',\ ExitProcess,'ExitProcess',\ Sleep,'Sleep',\ CreateFileA,'CreateFileA',\ WriteFile,'WriteFile',\ ReadFile,'ReadFile',\ SetFilePointer,'SetFilePointer',\ CreateNamedPipeA,'CreateNamedPipeA',\ ConnectNamedPipe,'ConnectNamedPipe' import user32,\ MessageBoxA,'MessageBoxA' клиент Код (ASM): format PE console include 'win32axp.inc' section '.text' code readable executable invoke CreateFileA,namedpip,GENERIC_WRITE OR GENERIC_READ,0,0, OPEN_EXISTING,0,0 mov [desc],eax invoke SetNamedPipeHandleState,desc,addr state,0,0 invoke WriteFile,desc,namedpip,10,dat,0 invoke ExitProcess,0 section '.data' data readable writeable state rd PIPE_TYPE_BYTE desc rd 1 namedpip db '\\.\pipe\channel',0 dat dd 0 section '.idata' import data readable writeable library kernel32,'kernel32.dll',\ msvcrt,'msvcrt.dll',\ user32,'user32.dll' import kernel32,\ ReadConsoleA,'ReadConsoleA',\ WriteConsoleA,'WriteConsoleA',\ GetStdHandle,'GetStdHandle',\ ExitProcess,'ExitProcess',\ Sleep,'Sleep',\ CreateFileA,'CreateFileA',\ WriteFile,'WriteFile',\ SetFilePointer,'SetFilePointer',\ CreateNamedPipeA,'CreateNamedPipeA',\ ConnectNamedPipe,'ConnectNamedPipe',\ SetNamedPipeHandleState,'SetNamedPipeHandleState',\ WaitNamedPipeA,'WaitNamedPipeA' import user32,\ MessageBoxA,'MessageBoxA' сервер успешно создается,а данные прочесть не удаётся
Так у вас обе программы просто один раз пишут (клиент) и читают (сервер) в пайп. На сервере нету цикла для постоянного чтения данных из пайпа. Клиент просто записывает данные и умирает. В обоих программах даже нету корректного освобождения объектов. Запускайте обе в отладчике и смотрите результат. Как минимум один раз данные должны быть переданы.