eliu
| 1
gtk win32 & Named Pipe server |
0
0 | 2011-02-05 | quote | | |
If we use ReadFile in another thread other than the gtk_main(), update to widget is not executed until there is a GTK widget event (focus, key mouse); this is not acceptable.
Thus we need a way to inform gtk_main when to execute update from the request buffer. On the Linux, this can be done with
static gboolean cb_new_gcin_client(GIOChannel *source, GIOCondition condition, gpointer data) { }
g_io_add_watch(g_io_channel_unix_new(im_tcp_sockfd), G_IO_IN, cb_new_gcin_client, GINT_TO_POINTER(Connection_type_tcp)); |
On Windows win32, It seems we can use g_io_channel_win32_new_fd, but it is useless
In order to meaningfully use this function your code should use the same C runtime as GLib uses, which is msvcrt.dll. Note that in current Microsoft compilers it is near impossible to convince it to build code that would use msvcrt.dll. The last Microsoft compiler version that supported using msvcrt.dll as the C runtime was version 6. The GNU compiler and toolchain for Windows, also known as Mingw, fully supports msvcrt.dll. |
Ulike Linux select() which can accept any file descriptor(socket, pipe, ...), On win32, only socket io event WSAEventSelect() can be integrate into wndProc. The problem is not serious for win32 non-gtk applications because the request is not buffered. We can create multihread server to handle the NamedPipe request.
Fortunately for a NamedPipe client, we can use SendMessage/PostMessage to notify gtk_main() to execute the request buffer.
PostMessage(serverWnd, GCIN_CLIENT_MESSAGE_REQ, handle->server_idx, NULL); WritFile(...); ReadFile(handle, …); |
If you don't want to return LRESULT in wndProc, you simply use gdk_window_add_filter
Otherwise It is possible to create a window & wndproc to handle our own window message.
client request is handled by GCIN_CLIENT_MESSAGE_REQ,
LRESULT wndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_CREATE: break; case GCIN_PORT_MESSAGE: dbg("GCIN_PORT_MESSAGE %d\n", gcin_pipe_svr_no); return gcin_pipe_svr_no; case GCIN_CLIENT_MESSAGE_REQ: int idx; idx = wp; if (idx>=gcin_clientsN) p_err("bad idx %d", idx); HANDLE fd; fd = gcin_clients[idx].fd; if (!fd) p_err("bad fd idx:%d\n", idx); ReadFile(fd...) ... WriteFile(fd...)..
return TRUE; default: return DefWindowProc(hwnd, msg, wp, lp); } return 0; } HWND hwnd_message_srv; void ErrorExit(LPTSTR lpszFunction); void create_win32_svr_hwnd() { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = (WNDPROC)wndProc; .........
if( !RegisterClassEx( (LPWNDCLASSEX)&wc ) ) return; hwnd_message_srv = CreateWindowExA(0, GCIN_WIN_NAME, NULL, 0, 0, 0, 0, 0, HWND_DESKTOP, NULL, wc.hInstance, NULL); if (!hwnd_message_srv) ErrorExit("CreateWindowEx"); // dbg("svr_hwnd %x\n", hwnd); }
|
Below is the code of NamedPipe server. This server doesn't create a new thread for each client because ReadFile()/WriteFile() is done in wndProc()
#define BUFSIZE 65536 int gcin_pipe_svr_no; DWORD WINAPI pipe_svr_thread(LPVOID lpvParam) { BOOL fConnected = FALSE; HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL; for (;;) { for(gcin_pipe_svr_no=0; gcin_pipe_svr_no <MAX_GCIN_PIPE_SERVER;gcin_pipe_svr_no++) { char pipe_path[128]; sprintf(pipe_path, GCIN_PIPE_PATH, gcin_pipe_svr_no); dbg("Pipe Server: Try %s\n", pipe_path); hPipe = CreateNamedPipe( pipe_path, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_BYTE | // message type pipe PIPE_READMODE_BYTE | // message-read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances BUFSIZE, // output buffer size BUFSIZE, // input buffer size 0, // client time-out NULL); // default security attribute if (hPipe != INVALID_HANDLE_VALUE) { break; } } if (gcin_pipe_svr_no>=MAX_GCIN_PIPE_SERVER) p_err("something is wrong cannot create %s\n", GCIN_PIPE_PATH); fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (fConnected) { int idx = add_im_client(hPipe); DWORD wn; WriteFile(hPipe, &idx, sizeof(idx), &wn, NULL); } else // The client could not connect, so close the pipe. CloseHandle(hPipe); } } void start_pipe_svr() { DWORD dwThreadId = 0; HANDLE dlThread = CreateThread( NULL, // no security attribute 0, // default stack size pipe_svr_thread, // thread proc (LPVOID) NULL, // thread parameter 0, // not suspended &dwThreadId); // returns thread ID if (dlThread == NULL) { dbg("CreateThread failed, %d\n", GetLastError()); return; } }
|
edited: 8
|