Hi, I have implemented a different aproach about copying clipboard contents between XFree86 and Windows based on the original xwinclip. It's less automatic but allows the user to control when to copy. There is a windows trayicon with a menu to copy from Windows or from X11. As it is possible to have several Xfree running connected to different XClients (machines) there is submenu to select which client you want to use.
But i have a problem when copying from windows to X11 (only tested with Kde 2.2.1) the new selection added to the Klipper is not "activated" (so no paste with mouse middle button ) and if i do a message loop for "selectionrequest" events, it receives an infinite number of those events: --- XLoop new event xevent.xselectionrequest.property _QT_SELECTION target type TARGETS 334 XLoop new event xevent.xselectionrequest.property _QT_SELECTION target type XA_STRING 31 ... --- The function that performs this is "CopyFromWindows" Below is the code: // Standard library headers #include <assert.h> #include <stdio.h> #include <stdlib.h> // #include <dirent.h> // X headers */ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> #include <X11/Xatom.h> #include <X11/keysym.h> //------------------------------------------------------------------ // Fixups to prevent collisions between Windows and X headers #undef MINSHORT #undef MAXSHORT // Flags for Windows header options #define NONAMELESSUNION #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif // Windows headers #include <w32api/windows.h> #include <w32api/windowsx.h> #include <w32api/shellapi.h> //----------------------------------------------- #define MYWM_NOTIFYICON (WM_APP+100) #define IDM_EXIT 1000 #define IDM_FROM 100 #define IDM_TO 200 #define ID_ICON_APP 1 #define ID_ICON_TRAY 4 #define MAX_DISPLAYS 9 //------------------------------------------------ #ifndef ARRAYSIZE #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif // Application constants #define WINDOW_CLASS "XWinClip" #define WINDOW_TITLE "xwinclip" // Global variables BOOL DisplayIds[MAX_DISPLAYS] = {FALSE, }; //-------------------------------------------------------------------------- ------- // MS-Windows Global Vars HINSTANCE ghInstance; HINSTANCE ghResInst; HMENU hPopupMnu; HMENU hmToWin; HMENU hmToX11; HWND hAppWnd; // Function prototypes HWND CreateMessagingWindow(void); LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void DOStoUNIX (char *pszData, int iLength); void UNIXtoDOS (unsigned char **ppszData, int iLength); //--------- //-------------------------------------------------------------------------- ------- //-------------------------------------------------------------------------- ------- BOOL DoCopyFromX11(Display *pDisplay, Window iMyWindow, unsigned char **ppszReturnData) { Atom atomReturnType; Atom atomLocalProperty; Atom atomUTF8String; int iReturnFormat; unsigned long ulReturnItems, ulReturnBytesLeft; int iReturn; BOOL GotIt; // Local property to hold pasted data atomLocalProperty = XInternAtom (pDisplay, "CYGX_CUT_BUFFER", False); if (atomLocalProperty == None) { MessageBox(hAppWnd, "Could not create CYGX_CUT_BUFFER atom", "XWinClip", MB_OK); return FALSE; } iReturn = XConvertSelection (pDisplay, XA_PRIMARY, XA_STRING, atomLocalProperty, iMyWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow) { printf ("From X11 - XConvertSelection () failed\n"); return FALSE; } GotIt = FALSE; // Loop for X events while (!GotIt) { XEvent xevent; // Block until the next X event XNextEvent (pDisplay, &xevent); //printf("XLoop new event\n"); // Branch on the event type switch (xevent.type) { case SelectionNotify: GotIt = TRUE; //printf("Getting Size of property of Window %d\n", iMyWindow); // Retrieve the size of the stored data iReturn = XGetWindowProperty (pDisplay, iMyWindow, atomLocalProperty, 0, 0, // Don't get data, just get size */ False, AnyPropertyType, &atomReturnType, &iReturnFormat, &ulReturnItems, &ulReturnBytesLeft, ppszReturnData); if (iReturn != Success) { MessageBox(hAppWnd, "From X11 - XGetWindowProperty () failed", "XWinClip", MB_OK); return FALSE; } //printf("From X11 - returned data %d left %d\n", ulReturnItems, ulReturnBytesLeft); if (ulReturnBytesLeft <= 0) { MessageBox(hAppWnd, "XGetWindowProperty() returned 0 bytes", "XWinClip", MB_OK); return FALSE; } // Request the selection data iReturn = XGetWindowProperty (pDisplay, iMyWindow, atomLocalProperty, 0, ulReturnBytesLeft, False, AnyPropertyType, &atomReturnType, &iReturnFormat, &ulReturnItems, &ulReturnBytesLeft, ppszReturnData); if (iReturn != Success) { MessageBox(hAppWnd, "SelectionNotify - XGetWindowProperty () failed", "XWinClip", MB_OK); return FALSE; } break; default: // ++ if GotIt = TRUE (some kind of timeout); break; } } //printf("exiting XLoop\n"); //printf("From X11 - returned data %s, %d\n", *ppszReturnData, strlen(*ppszReturnData) ); return TRUE; } //-------------------------------------------------------------------------- ------- //-------------------------------------------------------------------------- ------- BOOL DoPasteToWindows(char *pszReturnData) { HGLOBAL hGlobal; char *pszGlobalData; BOOL result = TRUE; // Access the Windows clipboard if (!OpenClipboard (hAppWnd)) { printf ("OpenClipboard () failed\n"); return FALSE; } // Take ownership of the Window clipboard if (!EmptyClipboard ()) { MessageBox(hAppWnd, "EmptyClipboard () failed", "XWinClip", MB_OK); result = FALSE; } // Allocate global memory for the X clipboard data if (result) hGlobal = GlobalAlloc (GMEM_MOVEABLE, strlen(pszReturnData) + 1); result = !(hGlobal == NULL); // Obtain a pointer to the global memory if (result) pszGlobalData = GlobalLock(hGlobal); else MessageBox(hAppWnd, "Could not lock global memory for clipboard transfer", "XWinClip", MB_OK); result = !(pszGlobalData == NULL); if (result) { // Copy the returned string into the global memory strcpy(pszGlobalData, pszReturnData); // Release the pointer to the global memory GlobalUnlock(hGlobal); pszGlobalData = NULL; // Push the selection data to the Windows clipboard SetClipboardData(CF_TEXT, hGlobal); // NOTE: Do not try to free pszGlobalData, it is owned by // Windows after the call to SetClipboardData (). } // Release the clipboard if (!CloseClipboard ()) printf ("CloseClipboard () failed\n"); return(result); } //--------------------------------------------------------- //--------------------------------------------------------- void CopyFromX11(char * DisplayName) { Display *pDisplay; Window iMyWindow; unsigned char *pszReturnData = NULL; pDisplay = XOpenDisplay(DisplayName); if (pDisplay == NULL) { MessageBox(hAppWnd, "Could not open display", "XWinClip", MB_OK); return; } // Create a messaging window iMyWindow = XCreateSimpleWindow (pDisplay, RootWindow (pDisplay, 0), 1, 1, 500, 500, 0, BlackPixel (pDisplay, 0), BlackPixel (pDisplay, 0)); XFlush (pDisplay); if (iMyWindow == 0) { MessageBox(hAppWnd, "Could not create a X11 window", "XWinClip", MB_OK); } else { XSelectInput (pDisplay, iMyWindow, ExposureMask); if (DoCopyFromX11(pDisplay, iMyWindow, &pszReturnData) ) { // Convert the X clipboard string to DOS format UNIXtoDOS(&pszReturnData, strlen(pszReturnData)); DoPasteToWindows(pszReturnData); // Free the data returned from XGetWindowProperty XFree(pszReturnData); pszReturnData = NULL; } XDestroyWindow (pDisplay, iMyWindow); } // Close the connection to X11 XCloseDisplay(pDisplay); } //-------------------------------------------------------------------------- ---- //-------------------------------------------------------------------------- ---- char * GetDisplayMachine(int DisplayNum) { static char buf[250]; Display *pDisplay; Window iWindow; Window root_return, parent_return; Window *children_return; int nchildren_return; XTextProperty ClientMachine; int iReturn; sprintf(buf, ":%d.0", DisplayNum); pDisplay = XOpenDisplay(buf); if (pDisplay == NULL) { strncat(buf, " can't open display", sizeof(buf) -1 - 4); return(buf); } iWindow = XDefaultRootWindow(pDisplay); if ( (iWindow == BadWindow) || (iWindow == None) ) { strncpy(buf, "Could not get Root Window", sizeof(buf) -1); return(buf); } buf[0] = '\0'; XQueryTree(pDisplay, iWindow, &root_return, &parent_return, &children_return, &nchildren_return); if (nchildren_return > 0) { iWindow = children_return[0]; XFree(children_return); } else { return(buf); } iReturn = XGetWMClientMachine(pDisplay, iWindow, &ClientMachine); if (iReturn == 0) { //strncpy(buf, "Could not get WMClientMachine", sizeof(buf) -1); return(buf); } strncpy(buf, ClientMachine.value, sizeof(buf) -1); XFree(ClientMachine.value); XCloseDisplay(pDisplay); buf[255] = '\0'; return(buf); } //-------------------------------------------------------------------------- ---- void CopyFromWindows(char * DisplayName) { Display *pDisplay; Window iWindow; Window iMyWindow; XSelectionEvent eventSelection; int iReturn; char *pszGlobalData; HGLOBAL hGlobal; Atom TargetsAtom; //Atom atomClipboard; Atom atomUTF8String; BOOL XLoopDone = FALSE; XTextProperty ClientMachine; int i; char * tmpstr; BOOL IsSelectionRequest = FALSE; pDisplay = XOpenDisplay(DisplayName); if (pDisplay == NULL) { MessageBox(hAppWnd, "Could not open display", "XWinClip", MB_OK); return; } // Create a messaging window iMyWindow = XCreateSimpleWindow (pDisplay, RootWindow (pDisplay, 0), 1, 1, 500, 500, 0, BlackPixel (pDisplay, 0), BlackPixel (pDisplay, 0)); if (iMyWindow == 0) { MessageBox(hAppWnd, "Could not create a X11 window", "XWinClip", MB_OK); } XSelectInput (pDisplay, iMyWindow, StructureNotifyMask+ExposureMask); XFlush (pDisplay); atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False); if (atomUTF8String == None) { printf ("Could not create UTF8_STRING atom\n"); } TargetsAtom = XInternAtom(pDisplay, "TARGETS", False); if (TargetsAtom == None) { printf ("Could not create TARGETS atom\n"); // return; } iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, iMyWindow, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow) { printf ("Could not set XA_PRIMARY owner to Our window\n"); } while (!XLoopDone /*|| IsSelectionRequest*/ ) { XEvent xevent; XSelectionEvent eventSelection; // Block until the next X event XNextEvent(pDisplay, &xevent); printf("\nXLoop new event\n"); // Branch on the event type switch (xevent.type) { case SelectionRequest: IsSelectionRequest = TRUE; tmpstr = XGetAtomName(pDisplay, xevent.xselectionrequest.property); printf("xevent.xselectionrequest.property %s\n", tmpstr); XFree(tmpstr); tmpstr = NULL; if (xevent.xselectionrequest.target == TargetsAtom) { Atom atTargetArr[2] = {atomUTF8String, XA_STRING}; XLoopDone = FALSE; printf("target type TARGETS %d\n", xevent.xselectionrequest.target); iReturn = XChangeProperty (pDisplay, xevent.xselectionrequest.requestor, xevent.xselectionrequest.property, xevent.xselectionrequest.target, 8, PropModeReplace, (char *)(atTargetArr), sizeof(atTargetArr)); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { printf ("SelectionRequest - XChangeProperty failed: %d\n", iReturn); } // Setup selection notify xevent eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = xevent.xselectionrequest.requestor; eventSelection.selection = xevent.xselectionrequest.selection; eventSelection.target = xevent.xselectionrequest.target; eventSelection.property = xevent.xselectionrequest.property; eventSelection.time = xevent.xselectionrequest.time; // Notify the requesting window that the operation has completed iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { printf ("XSendEvent () failed\n"); } XFlush(pDisplay); } else if (xevent.xselectionrequest.target == XA_STRING) { printf("target type XA_STRING %d\n", xevent.xselectionrequest.target); XLoopDone = TRUE; // Access the clipboard if (!OpenClipboard (hAppWnd)) { printf ("OpenClipboard () failed\n"); return; } // Get a pointer to the clipboard text hGlobal = GetClipboardData (CF_TEXT); if (!hGlobal) { printf ("GetClipboardData () failed\n"); return; } pszGlobalData = (char *) GlobalLock (hGlobal); // Convert DOS string to UNIX string */ DOStoUNIX(pszGlobalData, strlen(pszGlobalData)); iReturn = XChangeProperty (pDisplay, xevent.xselectionrequest.requestor, xevent.xselectionrequest.property, xevent.xselectionrequest.target, 8, PropModeReplace, pszGlobalData, strlen(pszGlobalData) ); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { printf ("SelectionRequest - XChangeProperty failed: %d\n", iReturn); } // Release the clipboard data GlobalUnlock(hGlobal); pszGlobalData = NULL; CloseClipboard(); // Setup selection notify xevent eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = xevent.xselectionrequest.requestor; eventSelection.selection = xevent.xselectionrequest.selection; eventSelection.target = xevent.xselectionrequest.target; eventSelection.property = xevent.xselectionrequest.property; eventSelection.time = xevent.xselectionrequest.time; // Notify the requesting window that the operation has completed iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { printf ("XSendEvent () failed\n"); //return; } XFlush(pDisplay); } else { // Abort if invalid target type XLoopDone = TRUE; printf("invalid target type %d\n", xevent.xselectionrequest.target); // Setup selection notify xevent eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = xevent.xselectionrequest.requestor; eventSelection.selection = xevent.xselectionrequest.selection; eventSelection.target = xevent.xselectionrequest.target; eventSelection.property = None; eventSelection.time = xevent.xselectionrequest.time; // Notify the requesting window that the operation is complete iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { printf ("XSendEvent () failed\n"); //return; } XFlush(pDisplay); /****************** iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, eventSelection.requestor, CurrentTime); if (iReturn == BadAtom || iReturn == BadWindow) { printf ("Could not set XA_PRIMARY owner back to last window\n"); } XFlush(pDisplay); **********/ } break; case SelectionClear: IsSelectionRequest = FALSE; printf("SelectionClear message handler\n"); break; default: IsSelectionRequest = FALSE; printf("default message handler\n"); break; } // case } // while XDestroyWindow(pDisplay, iMyWindow); XCloseDisplay(pDisplay); } //--------------------------------------------------------- //--------------------------------------------- // * Change \n to \r\n. Reallocate string if necessary. // --------------------------------------------- void UNIXtoDOS (unsigned char **ppszData, int iLength) { int iNewlineCount = 0; unsigned char *pszSrc = *ppszData; unsigned char *pszEnd = pszSrc + iLength; unsigned char *pszDest = NULL, *pszDestBegin = NULL; #if 0 printf ("UNIXtoDOS () - Original data:\n%s\n", *ppszData); #endif // Count \n characters without leading \r */ while (pszSrc < pszEnd) { // Skip ahead two character if found set of \r\n */ if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') { pszSrc += 2; continue; } // Increment the count if found naked \n */ if (*pszSrc == '\n') { iNewlineCount++; } pszSrc++; } // Return if no naked \n's */ if (iNewlineCount == 0) return; // Allocate a new string */ pszDestBegin = pszDest = malloc (iLength + iNewlineCount + 1); // Set source pointer to beginning of data string */ pszSrc = *ppszData; // Loop through all characters in source string */ while (pszSrc < pszEnd) { // Copy line endings that are already valid */ if (*pszSrc == '\r' && pszSrc + 1 < pszEnd && *(pszSrc + 1) == '\n') { *pszDest = *pszSrc; *(pszDest + 1) = *(pszSrc + 1); pszDest += 2; pszSrc += 2; continue; } // Add \r to naked \n's */ if (*pszSrc == '\n') { *pszDest = '\r'; *(pszDest + 1) = *pszSrc; pszDest += 2; pszSrc += 1; continue; } // Copy normal characters */ *pszDest = *pszSrc; pszSrc++; pszDest++; } // Put terminating null at end of new string */ *pszDest = '\0'; // Swap string pointers */ free (*ppszData); *ppszData = pszDestBegin; #if 0 printf ("UNIXtoDOS () - Final string:\n%s\n", pszDestBegin); #endif } //-------------------------------------------------------------------------- -- // This was heavily inspired by, if not down right stolen from, Cygwin's // winsup/cygwin/fhandler.cc/fhandler_base::read () //-------------------------------------------------------------------------- -- void DOStoUNIX (char *pszSrc, int iLength) { char *pszDest = pszSrc; char *pszEnd = pszSrc + iLength; // Loop until the last character */ while (pszSrc < pszEnd) { // Copy the current source character to current destination character */ *pszDest = *pszSrc; // Advance to the next source character */ pszSrc++; // Don't advance the destination character if we need to drop an \r */ if (*pszDest != '\r' || *pszSrc != '\n') pszDest++; } // Move the terminating null */ *pszDest = '\0'; } // ------------------------------------------------------------------------- ----------------- int main (int argc, char *argv[]) { HWND hWnd; MSG msg; ghInstance = GetModuleHandle (NULL); ghResInst = LoadLibraryEx(/*C:\\cygwinDEV\\xwinclip\\*/"XWinclip.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE); printf("ghResInst = %d\n", ghResInst); // Create Windows messaging window hWnd = CreateMessagingWindow(); // Loop for Windows events // Acquire and dispatch messages until a WM_QUIT message is received. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } ////printf("Exiting xwinclip\n"); CreateTrayIcon(hWnd, NIM_DELETE, 0, NULL, NULL); FreeLibrary(ghResInst); UnregisterClass(WINDOW_CLASS, ghInstance); return 0; } //-------------------------------------------------------------------------- ---- // supported only local Displays from 0 to 9 //-------------------------------------------------------------------------- ---- int SelectDir(const struct dirent * current) { //(strlen(current->d_name) <= 2) && return ( (current->d_name[0] == 'X') && (current->d_name[1] >= '0') && (current->d_name[1] <= '9') && (current->d_name[2] == '\0') ); } //-------------------------------------------------------------------------- ---- // to find displays //--- /tpm/.X11-unix/X0 .. X4 .. Xn //-------------------------------------------------------------------------- ---- void RebuildTrayMenus(void) { char buf[260]; struct dirent **namelist; int i, n; for (i = 0; i < ARRAYSIZE(DisplayIds); i++) { if (DisplayIds[i]) { DeleteMenu(hmToWin, 0, MF_BYPOSITION); DeleteMenu(hmToX11, 0, MF_BYPOSITION); } } i = scandir("/tmp/.X11-unix/", &namelist, SelectDir, alphasort); if (i < 0) printf("error scandir\n"); else { bzero( (void *)DisplayIds, sizeof(DisplayIds)); while (i--) { int n = namelist[i]->d_name[1] - '0'; DisplayIds[n] = TRUE; /////////printf("%s\n", namelist[i]->d_name); free(namelist[i]); } free(namelist); } for (i = 0; i < ARRAYSIZE(DisplayIds); i++) { if (DisplayIds[i]) { char * MachineName = GetDisplayMachine(i); sprintf(buf, "From %d (%s)", i, MachineName); AppendMenu(hmToWin, MF_ENABLED | MF_STRING, IDM_FROM + i, buf); sprintf(buf, "To %d (%s)", i, MachineName); AppendMenu(hmToX11, MF_ENABLED | MF_STRING, IDM_TO + i, buf); } } } //-------------------------------------------------------------------------- ---- //-------------------------------------------------------------------------- ---- LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { static BOOL bShowing = TRUE; POINT Point; int CommandId; // cases for application messages switch (uMessage) { // command from application menu case WM_COMMAND: //use the GET_WM_COMMAND macro to unpack the commnad CommandId = GET_WM_COMMAND_ID(wParam, lParam); if ( (CommandId >= IDM_FROM) && (CommandId < IDM_FROM + MAX_DISPLAYS) ) { // Copy From X11 char dispName[8]; sprintf(dispName, ":%d.0", CommandId - IDM_FROM); CopyFromX11(dispName); //printf("Done Copy From X11 %d\n", CommandId); } else if ( (CommandId >= IDM_TO) && (CommandId < IDM_TO + MAX_DISPLAYS) ) { // Copy To X11 char dispName[8]; sprintf(dispName, ":%d.0", CommandId - IDM_TO); CopyFromWindows(dispName); //printf("Done Copy To X11 %d\n", CommandId); } else if (CommandId == IDM_EXIT) { DestroyWindow(hWnd); } else { return DefWindowProc(hWnd, uMessage, wParam, lParam); } break; case MYWM_NOTIFYICON: switch (lParam) { case WM_LBUTTONDBLCLK: if (bShowing) { ShowWindow(hWnd, SW_HIDE); } else { ShowWindow(hWnd, SW_SHOW); SetForegroundWindow(hWnd); // make us come to the front } bShowing = !bShowing; break; /*case WM_LBUTTONDOWN: switch (wParam) { } break; */ case WM_RBUTTONDOWN: RebuildTrayMenus(); DrawMenuBar(hWnd); break; case WM_RBUTTONUP: GetCursorPos(&Point); if ( !TrackPopupMenuEx(hPopupMnu, /*TPM_RIGHTBUTTON |*/ TPM_RIGHTALIGN, // screen-position and mouse-button flags Point.x, Point.y, hWnd, NULL) // points to RECT that specifies no-dismissal area ) printf("popup menu failed at X:%d, Y:%d\n", Point.x, Point.y); break; default: break; } break; case WM_DESTROY: // message: window being destroyed PostQuitMessage(0); break; default: // Passes it on if unproccessed return DefWindowProc(hWnd, uMessage, wParam, lParam); } return 0; } //-------------------------------------------------------------------------- ---------------- //-------------------------------------------------------------------------- - BOOL CreateTrayIcon(HWND hWnd, DWORD dwMessage, UINT uID, HICON hIcon, PSTR pszTip) { BOOL res; NOTIFYICONDATA tnd; tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = hWnd; tnd.uID = uID; tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; tnd.uCallbackMessage = MYWM_NOTIFYICON; tnd.hIcon = hIcon; if (pszTip) { lstrcpyn(tnd.szTip, pszTip, sizeof(tnd.szTip)); } else { tnd.szTip[0] = '\0'; } res = Shell_NotifyIcon(dwMessage, &tnd); return res; } //-------------------------------------------------------------------------- --- void CreateTrayMenu(void) { hPopupMnu = CreatePopupMenu(); hmToWin = CreatePopupMenu(); hmToX11 = CreatePopupMenu(); AppendMenu(hPopupMnu, MF_ENABLED | MF_POPUP | MF_STRING, (UINT)hmToWin, "Copy TO Windows"); AppendMenu(hPopupMnu, MF_ENABLED | MF_POPUP | MF_STRING, (UINT)hmToX11, "Copy TO X11"); AppendMenu(hPopupMnu, MF_SEPARATOR, 0, NULL); AppendMenu(hPopupMnu, MF_ENABLED | MF_STRING, IDM_EXIT, "Exit (Alt+F4)"); } //-------------------------------------------------------------------------- --- HWND CreateMessagingWindow(void) { WNDCLASS wc; HICON hIconApp; HICON hIconTray; hIconApp = (HICON)LoadImage(ghResInst, MAKEINTRESOURCE(ID_ICON_APP), IMAGE_ICON, 16, 16, 0); hIconTray = (HICON)LoadImage(ghResInst, MAKEINTRESOURCE(ID_ICON_TRAY), IMAGE_ICON, 16, 16, 0); //printf("hIconApp = %d\n", hIconApp); //printf("hIconTray = %d\n", hIconTray); CreateTrayMenu(); //printf("hPopupMnu %d\n", hPopupMnu); // Setup our window class */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInstance; wc.hIcon = hIconApp; wc.hCursor = 0; wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = WINDOW_CLASS; RegisterClass (&wc); // Create the window hAppWnd = CreateWindowExA (0, // Extended styles WINDOW_CLASS, // Class name WINDOW_TITLE, // Window name WS_OVERLAPPED, // Not visible anyway CW_USEDEFAULT, // Horizontal position CW_USEDEFAULT, // Vertical position 50, // Right edge CW_USEDEFAULT 50, // Bottom edge CW_USEDEFAULT (HWND) NULL, // No parent or owner window (HMENU) NULL, // No menu ghInstance,// Instance handle NULL); // ScreenPrivates assert (hAppWnd != NULL); CreateTrayIcon(hAppWnd, NIM_ADD, 0, hIconTray, "XClipboard 2 Win"); return(hAppWnd); } Any advice ? Thanks.