cht電腦資訊LanguageC/C++
adm Find login register

gtk win32 & Named Pipe server

eliu

joined: 2007-08-09
posted: 11468
promoted: 617
bookmarked: 187
新竹, 台灣
1subject: gtk win32 & Named Pipe serverPromote 0 Bookmark 02011-02-05quote  

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

CC: Windows
cht電腦資訊LanguageC/C++
adm Find login register
views:5585