# include #define W32ASSERT(TEST, WHERE) if (!TEST) DebPrint (("%s: %s\n", WHERE, w32_strerror(0))) /* Trace functions. These functions make it possible to output trace messages to the console even if you want to trace functions in the W32 GUI. To enable trace define MYTRACE. To trace functions in the W32 GUI you must still be using emacsclient.exe and also define MYTRACEW32GUI. */ //#define MYTRACE //#define MYTRACEW32GUI int w32_window_app () { static int window_app = -1; char szTitle[MAX_PATH]; #ifdef MYTRACEW32GUI InitCommonControls(); return 1; #endif if (window_app < 0) { /* Checking for STDOUT does not work; it's a valid handle also in nonconsole apps. Testing for the console title seems to work. */ window_app = (GetConsoleTitleA (szTitle, MAX_PATH) == 0); if (window_app) InitCommonControls(); } return window_app; } void trace (char *message, ...) { char buf[2048]; char *msg = buf; va_list args; va_start (args, message); strcpy (buf, "TRACE: "); msg = strchr (buf, '\0'); vsprintf (msg, message, args); va_end (args); #ifdef MYTRACE strcat (msg, "\n"); fprintf (stdout, buf); fflush (stdout); if ( w32_window_app () ) MessageBox (NULL, buf, "EmacsClient trace", MB_ICONINFORMATION); #endif } /* Errors etc */ int w32_get_error_text(DWORD dwError, char* buf, int buflen) { LPVOID lpMsgBuf; LPVOID lpDisplayBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); int msglen = strlen(lpMsgBuf); if (msglen < buflen) { strcpy(buf, lpMsgBuf); LocalFree(lpMsgBuf); //strcat(buf, "\n"); // fix-me return msglen; } else { LocalFree(lpMsgBuf); return -msglen; } } void w32_sys_fatal2(DWORD dwError, char* lpszFunction) { char err[2048]; w32_get_error_text(dwError, err, 2048); char buf[2048]; sprintf(buf, "%s failed with w32 error %d: %s", lpszFunction, dwError, err); trace(buf); fatal(buf); } void w32_sys_fatal1(LPTSTR lpszFunction) { DWORD dw = GetLastError(); w32_sys_fatal2(dw, lpszFunction); } /* Other */ int get_emacs_bin_dir( char * pBuf, int len) { char *emacs_dir = NULL; char emacs_exe_dir[MAX_PATH]; pBuf[0] = 0; #ifdef WINDOWSNT #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */ /* Treat emacs_dir specially: Just return false if it appears that we are running from the bin subdir of a standard installation. */ { char *p; char emacs_exe[MAX_PATH]; if (GetModuleFileName (NULL, emacs_exe_dir, MAX_PATH)) { if (!((p = strrchr (emacs_exe_dir, '\\')) == NULL)) { *p = 0; if ((p = strrchr (emacs_exe_dir, '\\')) && stricmp (p, "\\bin") == 0) { char buf[SET_ENV_BUF_SIZE]; *p = 0; strcpy( emacs_exe, emacs_exe_dir); for (p = emacs_exe; *p; p++) if (*p == '\\') *p = '/'; strcat( emacs_exe, "/emacs.exe" ); if (access (emacs_exe, X_OK) == 0) return 0; else emacs_dir = emacs_exe_dir; } } } else w32_sys_fatal1("GetModuleFileName"); } #else // TODO #endif if (!emacs_dir) emacs_dir = egetenv("emacs_dir"); if (!emacs_dir) return 0; strcpy (pBuf, emacs_dir); strcat(pBuf, "\\bin\\"); return 1; } /* Windowing */ #define EMACSCLIENT_WNDCLS "EmacsClientWindowClass" #define WM_EMACSCLIENT_DONE (WM_USER + 1) #define WM_EMACSCLIENT_CW (WM_USER + 2) #define WM_EMACSCLIENT_QUIT (WM_USER + 3) struct { CRITICAL_SECTION cs; int owned; } g_cs; /* Avoid using W32_SYNC_ENTER / W32_SYNC_LEAVE in the code! Use instead W32_SYNC_DO or the getters/setters that can be created by W32_MK_SYNC_GETSET! */ void W32_SYNC_ENTER() { if (TryEnterCriticalSection(&g_cs.cs)) { LeaveCriticalSection(&g_cs.cs); } else { } EnterCriticalSection(&g_cs.cs); g_cs.owned++; } void W32_SYNC_LEAVE() { if (0 == --g_cs.owned) LeaveCriticalSection(&g_cs.cs); if (0 > g_cs.owned) fatal("g_cs.owned < 0"); } #define W32_SYNC_DO(CODE) { W32_SYNC_ENTER(); CODE; W32_SYNC_LEAVE(); } #define W32_MK_SYNC_GETSET(VAR, TYPE) \ void W32_SYNC_set_##VAR(TYPE value) { W32_SYNC_ENTER(); VAR = value; W32_SYNC_LEAVE(); } \ TYPE W32_SYNC_get_##VAR() { /* trace("a"); */ /* if (TryEnterCriticalSection(&g_cs.cs)) trace("Y"); else trace("N"); */ W32_SYNC_ENTER(); TYPE locval = VAR; W32_SYNC_LEAVE(); return locval; } /* Variables used in several threads */ static int g_exit_value = EXIT_SUCCESS; W32_MK_SYNC_GETSET(g_exit_value, int) static HWND g_hWndTxt = 0; W32_MK_SYNC_GETSET(g_hWndTxt, HWND) static HWND g_hWndBtn = 0; W32_MK_SYNC_GETSET(g_hWndBtn, HWND) static HWND g_hWndMsg = 0; W32_MK_SYNC_GETSET(g_hWndMsg, HWND) static BOOL g_bExitRequested = FALSE; W32_MK_SYNC_GETSET(g_bExitRequested, BOOL) static HANDLE g_hGUIThread = NULL; W32_MK_SYNC_GETSET(g_hGUIThread, HANDLE) static int g_w32_did_setup_window = 0; W32_MK_SYNC_GETSET(g_w32_did_setup_window, int) static HANDLE g_hMainThread = NULL; static DWORD g_dwGUIThreadId = 0; W32_MK_SYNC_GETSET(g_dwGUIThreadId, DWORD) static DWORD g_dwMainThreadId = 0; W32_MK_SYNC_GETSET(g_dwMainThreadId, DWORD) static int g_iButtonState = 0; /* states: 0 = cancel 1 = close */ W32_MK_SYNC_GETSET(g_iButtonState, int) #define W32_CHECK_THREADS #ifdef W32_CHECK_THREADS void W32_CHECK_IS_GUITHREAD(char* WHERE) { if(!(GetCurrentThreadId() == W32_SYNC_get_g_dwGUIThreadId() )) fatal("Not GUIThread: %s", WHERE); } void W32_CHECK_IS_MAINTHREAD(char* WHERE) { if(!(GetCurrentThreadId() == W32_SYNC_get_g_dwMainThreadId() )) fatal("Not MainThread: %s", WHERE); } #else #define W32_CHECK_IS_GUITHREAD(WHERE) #define W32_CHECK_IS_MAINTHREAD(WHERE) #endif void W32_SYNC_SetWindowText(HWND hWnd, char* sTxt) { W32_SYNC_DO( if (!SetWindowText(hWnd, sTxt)) w32_sys_fatal1("SetWindowText"); if (!UpdateWindow(hWnd)) w32_sys_fatal1("UpdateWindow"); ); } BOOL W32_SYNC_IsWindow(HWND hWnd) { BOOL res = FALSE; W32_SYNC_DO( res = IsWindow(hWnd); ); return res; } void w32_add_to_wait_message (char *add); BOOL g_bGUIExitRequested = FALSE; void w32_set_button_state(int iState) { //W32_CHECK_IS_GUITHREAD("w32_set_button_state"); if (W32_SYNC_IsWindow(g_hWndBtn)) { W32_SYNC_set_g_iButtonState(iState); switch (iState) { case 0: W32_SYNC_SetWindowText(g_hWndBtn, "Cancel"); break; case 1: W32_SYNC_SetWindowText(g_hWndBtn, "Close"); break; default: fatal("Invalid button state in w32_set_button_state: %d", iState); } } } void w32_button_clicked() { //trace("enter w32_button_clicked"); /* Fix-me: I get a hang if I try to sync here. Why??? */ //W32_CHECK_IS_GUITHREAD("w32_button_clicked"); int iState = g_iButtonState; switch (iState) { case 0: //trace("case 0"); w32_add_to_wait_message("\n- CANCELED by user!"); //trace("case 0 B"); w32_set_button_state(1); //trace("case 0 C"); //W32_SYNC_set_g_bExitRequested(TRUE); g_bGUIExitRequested = TRUE; break; case 1: //trace("case 1"); //W32_SYNC_DO( //trace("before post WM_CLOSE"); PostMessage(g_hWndMsg, WM_CLOSE, 0, 0); //trace("afterpost WM_CLOSE"); //); break; default: fatal("Invalid button state in w32_button_clicked: %d", iState); } trace("exit w32_button_clicked"); } static LRESULT CALLBACK MsgWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //trace("e-r=%d, uMsg=%d, wP=%d, lP=%d", g_bGUIExitRequested, uMsg, wParam, lParam); switch (uMsg) { case WM_COMMAND: if (lParam == (LPARAM)g_hWndBtn) { w32_button_clicked(); } break; case WM_CHAR: if (wParam == VK_RETURN || wParam == VK_SPACE) { w32_button_clicked(); return 0; } break; case WM_DESTROY: trace("WM_DESTROY"); if (g_bGUIExitRequested) { trace("g_bGUIExitRequested, PostQuitMessage(1)"); PostQuitMessage(1); } break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } void w32_create_message_window() { W32_CHECK_IS_GUITHREAD("create_message_window"); int iHouter = 200; int iWouter = 300; int iBorder = 13; HINSTANCE hInstance; DWORD dwStyle = WS_CAPTION | WS_BORDER | WS_CAPTION | WS_SYSMENU //| WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_VISIBLE; hInstance = GetModuleHandle(NULL); if (!(g_hWndMsg = CreateWindow(EMACSCLIENT_WNDCLS, "Emacs Client", dwStyle, 50, //CW_USEDEFAULT, 50, //CW_USEDEFAULT, iWouter, iHouter, NULL, NULL, hInstance, NULL))) w32_sys_fatal1("Could not create message window, CreateWindow"); if (!SetWindowPos(g_hWndMsg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED)) w32_sys_fatal1("HWND_TOPMOST, SetWindowPos"); RECT clr; if (!GetClientRect(g_hWndMsg, &clr)) w32_sys_fatal1("Could not client area, GetClientRect"); int iW = clr.right - clr.left; int iH = clr.bottom - clr.top; //trace("CreateWindow(WC_STATIC=%d", WC_STATIC); if (!(g_hWndTxt = CreateWindow(WC_STATIC, "", WS_CHILD | WS_VISIBLE | SS_LEFT, iBorder, iBorder, iW - 2*iBorder, iH - 4*iBorder - 24, g_hWndMsg, NULL, hInstance, NULL))) w32_sys_fatal1("WC_STATIC, CreateWindow"); HFONT hfFont = GetStockObject(DEFAULT_GUI_FONT); SendMessage(g_hWndTxt, WM_SETFONT, (WPARAM) hfFont, TRUE); int iBtnW = 70; int iBtnH = 24; if (!(g_hWndBtn = CreateWindow(WC_BUTTON, "&Cancel", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | BS_TEXT, (iW - iBtnW) / 2, iH - iBtnH - iBorder, iBtnW, iBtnH, g_hWndMsg, NULL, hInstance, NULL))) w32_sys_fatal1("WC_BUTTON, CreateWindow"); SendMessage(g_hWndBtn, WM_SETFONT, (WPARAM) hfFont, TRUE); } BOOL w32_init_class () { W32_CHECK_IS_GUITHREAD("w32_init_class"); HINSTANCE hInstance; WNDCLASS wc; if (!(hInstance = GetModuleHandle(NULL))) w32_sys_fatal1("GetModuleHandle"); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) MsgWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; if (!(wc.hIcon = LoadIcon (hInstance, "Emacs"))) w32_sys_fatal1("LoadIcon"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) COLOR_WINDOW; wc.lpszMenuName = NULL; wc.lpszClassName = EMACSCLIENT_WNDCLS; if (!RegisterClass (&wc)) w32_sys_fatal1("RegisterClass"); } DWORD WINAPI w32_msg_dispatcher(LPVOID lpParam) { W32_CHECK_IS_GUITHREAD("w32_msg_dispatcher"); MSG msg; BOOL bRet; w32_init_class (); //IsGUIThread(TRUE); if (!PostThreadMessage (g_dwMainThreadId, WM_EMACSCLIENT_DONE, 0, 0)) w32_sys_fatal1("PostThreadMessage(, WM_EMACSCLIENT_DONE, 0, 0)"); while ( (bRet = GetMessage (&msg, NULL, 0, 0)) != 0) { if (-1 == bRet) { char buf[2048]; w32_get_error_text(GetLastError(), buf, 2048); trace("w32_msg_dispatcher, GetMessage returned -1: %s", buf); } else { if (msg.hwnd == NULL) { switch (msg.message) { case WM_EMACSCLIENT_CW: w32_create_message_window(); DWORD dwMainThreadId = W32_SYNC_get_g_dwMainThreadId(); if (!PostThreadMessage (dwMainThreadId, WM_EMACSCLIENT_DONE, 0, 0)) w32_sys_fatal1("PostThreadMessage(, WM_EMACSCLIENT_DONE, 0, 0)"); trace("after w32_create_message_window 1"); break; case WM_EMACSCLIENT_QUIT: trace("rec WM_EMACSCLIENT_QUIT"); g_bGUIExitRequested = TRUE; //PostMessage(g_hWndMsg, WM_CLOSE, 0, 0); break; case WM_QUIT: trace("WM_QUIT -> ExitThread"); ExitThread(1); } } else { TranslateMessage(&msg); DispatchMessage (&msg); } } } trace("w32_msg_dispatcher exits"); } void w32_start_gui_thread() { MSG wmsg; W32_CHECK_IS_MAINTHREAD("w32_start_gui_thread"); if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &g_hMainThread, 0, TRUE, DUPLICATE_SAME_ACCESS)) w32_sys_fatal1("DuplicateHandle"); PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE); if (!(g_hGUIThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) w32_msg_dispatcher, NULL, 0, &g_dwGUIThreadId))) w32_sys_fatal1("CreateThread"); GetMessage (&wmsg, NULL, WM_EMACSCLIENT_DONE, WM_EMACSCLIENT_DONE); } void w32_check_not_synced() { W32_SYNC_DO( if (g_cs.owned > 1) fatal("g_cs.owned is not 0 (+1 here): %d", g_cs.owned); ); } void w32_wait_threads_fin(int connected) { W32_SYNC_set_g_bExitRequested(TRUE); HANDLE hGUIThread = W32_SYNC_get_g_hGUIThread(); if (hGUIThread) { W32_CHECK_IS_MAINTHREAD("w32_wait_threads_fin"); trace("posting WM_EMACSCLIENT_QUIT, g_dwGUIThreadId=%d", W32_SYNC_get_g_dwGUIThreadId()); W32_SYNC_DO( if (!PostThreadMessage (g_dwGUIThreadId, WM_EMACSCLIENT_QUIT, 0, 0)) { if (ERROR_INVALID_THREAD_ID != GetLastError()) w32_sys_fatal1("PostThreadMessage(, WM_EMACSCLIENT_QUIT, 0, 0)"); } ); trace("waiting for threads to finish, hGUIThread=%d", hGUIThread); if (connected) { //trace ("W32_SYNC_DO(if (g_bGUIExitRequested) PostMessage(g_hWndMsg, WM_CLOSE, 0, 0));"); //W32_SYNC_DO(if (g_bGUIExitRequested) PostMessage(g_hWndMsg, WM_CLOSE, 0, 0)); WaitForSingleObject(hGUIThread, 2000); } else WaitForSingleObject(hGUIThread, INFINITE); trace("after waiting for threads to finish"); } } void w32_setup_window() { if (! g_w32_did_setup_window) { g_w32_did_setup_window = 1; InitializeCriticalSection(&g_cs.cs); g_cs.owned = 0; if (w32_window_app ()) { g_dwMainThreadId = GetCurrentThreadId (); w32_start_gui_thread(); } } } void w32_remove_wait_message(); //void w32_add_to_wait_message(char *add); void w32_wait_after_message(int milliseconds); int w32_finish_messages (int connected) { int ret; //int did_setup = W32_SYNC_get_g_w32_did_setup_window(); int did_setup = g_w32_did_setup_window; trace ("w32 finish_messages, did=%d", did_setup); if (did_setup && w32_window_app ()) { w32_remove_wait_message(); trace ("w32_finish_messages after remove wait"); w32_wait_after_message(2000); w32_check_not_synced(); trace ("w32_finish_messages before fin"); w32_wait_threads_fin(connected); trace ("w32_finish_messages after fin"); ret = W32_SYNC_get_g_exit_value(); trace ("w32_finish_messages after ret"); DeleteCriticalSection(&g_cs.cs); g_w32_did_setup_window = 0; return ret; } else { fprintf (stdout, "\n"); fflush (stdout); ret = g_exit_value; } return ret; } /* Message functions. */ void w32_add_to_wait_message(char *add) { if (g_w32_did_setup_window && w32_window_app ()) { trace("w32_add_to_wait_message 1"); //W32_CHECK_IS_MAINTHREAD("w32_add_towait_message"); W32_SYNC_DO( if (IsWindow(g_hWndTxt)) { DWORD old_len = SendMessage(g_hWndTxt, WM_GETTEXTLENGTH, 0, 0); DWORD alloclen = 2*(old_len+strlen(add)+1); LPTSTR msg = alloca(alloclen); //trace("w32_add_to_wait_message before GETTEXT"); SendMessage(g_hWndTxt, WM_GETTEXT, (WPARAM) alloclen, (LPARAM) msg); //trace("w32_add_to_wait_message after GETTEXT"); lstrcat(msg, add); //trace("w32_add_to_wait_message before SETTEXT"); if (!SetWindowText(g_hWndTxt, msg)) w32_sys_fatal1("w32_add_to_wait_message, SetWindowText"); if (!UpdateWindow(g_hWndTxt)) w32_sys_fatal1("w32_add_to_wait_message, UpdateWindow"); } ); trace("w32_add_to_wait_message 2"); } else { trace ("w32_add_to_wait_message using stdout"); fprintf (stdout, add); fflush (stdout); } trace ("w32_add_to_wait_message exit"); } void w32_add_wait_dot() { if (w32_window_app ()) { w32_add_to_wait_message(" ."); } else w32_add_to_wait_message("."); } void w32_wait_after_message(int milliseconds) { if (g_w32_did_setup_window && w32_window_app ()) { DWORD dw; W32_SYNC_DO(dw = WaitForSingleObject(g_hGUIThread, milliseconds)); switch(dw) { case WAIT_TIMEOUT: break; case WAIT_OBJECT_0: W32_SYNC_set_g_bExitRequested(1); break; case WAIT_ABANDONED: fatal("Unexpected WAIT_ABANDONED in wait_after_message"); break; case WAIT_FAILED: w32_sys_fatal1("WAIT_FAILED - wait_after_message()"); break; } } else sleep(milliseconds/1000); } void w32_inform_1 (char *msg) { if (w32_window_app ()) { MessageBox (NULL, msg, "EmacsClient", MB_ICONINFORMATION); } else { fprintf (stdout, msg); fprintf (stdout, "\n"); fflush (stdout); } } void w32_error_1 (char *msg) { if (w32_window_app ()) { if (W32_SYNC_IsWindow(g_hWndMsg)) { w32_add_to_wait_message("\n"); if (1) //error { w32_add_to_wait_message("** ERROR ** "); w32_set_button_state(1); w32_add_to_wait_message(msg); W32_SYNC_set_g_bExitRequested(TRUE); } else w32_add_to_wait_message(msg); } else if (1) // error { MessageBox (NULL, msg, "EmacsClient ERROR", MB_ICONSTOP | MB_SYSTEMMODAL); } else MessageBox (NULL, msg, "Emacsclient", MB_ICONINFORMATION); } } void w32_fatal_1 (char *msg) { if (w32_window_app ()) MessageBox (NULL, msg, "EmacsClient FATAL ERROR", MB_ICONSTOP | MB_SYSTEMMODAL); else { fprintf (stderr, msg); fflush (stderr); } exit(EXIT_FAILURE); } void w32_message_1 (char *msg, int is_error) { if (w32_window_app ()) { if (W32_SYNC_IsWindow(g_hWndMsg)) { w32_add_to_wait_message("\n"); if (1) //error { w32_add_to_wait_message("** ERROR ** "); w32_set_button_state(1); w32_add_to_wait_message(msg); W32_SYNC_set_g_bExitRequested(TRUE); } else w32_add_to_wait_message(msg); } else if (is_error) MessageBox (NULL, msg, "Emacsclient ERROR", MB_ICONERROR); else MessageBox (NULL, msg, "Emacsclient", MB_ICONINFORMATION); } else { fprintf (stderr, msg); fprintf (stderr, "\n"); fflush (stderr); } } void w32_message_2 (char *msg) { if (w32_window_app ()) { MessageBox (NULL, msg, "EmacsClient", MB_ICONINFORMATION); } else { fprintf (stdout, msg); fprintf (stdout, "\n"); fflush (stdout); } } void w32_start_wait_message(char *sMessage) { if (w32_window_app ()) { w32_setup_window(); W32_CHECK_IS_MAINTHREAD("w32_start_wait_message"); if (!W32_SYNC_IsWindow(g_hWndMsg)) { DWORD dwGUIThreadId = W32_SYNC_get_g_dwGUIThreadId(); W32_SYNC_DO( trace("PostThreadMessage(g_dwGUIThreadId=%d, WM_EMACSCLIENT_CW, 0, 0)", g_dwGUIThreadId); if (!PostThreadMessage (g_dwGUIThreadId, WM_EMACSCLIENT_CW, 0, 0)) w32_sys_fatal1("PostThreadMessage(, WM_EMACSCLIENT_CW)"); ); MSG msg; W32_SYNC_DO( if (1 < g_cs.owned) { fatal("g_cs.owned was owned before w32_start_wait_message"); } ); GetMessage (&msg, NULL, WM_EMACSCLIENT_DONE, WM_EMACSCLIENT_DONE); } W32_SYNC_SetWindowText(g_hWndTxt, ""); w32_add_to_wait_message(sMessage); } else { fprintf (stdout, sMessage); fflush (stdout); } } void w32_close_message_window () { HWND hWnd; trace ("w32_close_message_window"); trace ("w32_close_message_window, did_setup=%d", g_w32_did_setup_window); if (g_w32_did_setup_window && w32_window_app ()) { hWnd = W32_SYNC_get_g_hWndMsg(); if (hWnd) { g_bGUIExitRequested = TRUE; PostMessage(hWnd, WM_CLOSE, 0, 0); } } } void w32_remove_wait_message() { W32_CHECK_IS_MAINTHREAD("w32_remove_wait_message"); W32_SYNC_DO( if (IsWindow(g_hWndMsg)) { w32_set_button_state(1); DestroyWindow(g_hWndMsg); } ); } /* Wrapper to make WSACleanup a cdecl, as required by atexit. */ void __cdecl close_winsock () { WSACleanup (); } void fatal_network_error(char* fmt); /* Initialize the WinSock2 library. */ void initialize_sockets () { WSADATA wsaData; if (WSAStartup (MAKEWORD (2, 0), &wsaData)) { fatal_network_error("error initializing WinSock2: %s"); } atexit (close_winsock); } FARPROC pfnAllowSetForegroundWindow; /* Pointer to AllowSetForegroundWindow. */ FARPROC pfnRealGetWindowClassA; /* Pointer to RealGetWindowClassA. */ BOOL found_emacs = FALSE; BOOL CALLBACK w32_find_emacs_process (hWnd, lParam) HWND hWnd; LPARAM lParam; { DWORD pid; char class[6]; /* Reject any window not of class "Emacs". */ if (! pfnRealGetWindowClassA (hWnd, class, sizeof (class)) || strcmp (class, "Emacs")) return TRUE; /* We only need the process id, not the thread id. */ (void) GetWindowThreadProcessId (hWnd, &pid); /* Not the one we're looking for. */ if (pid != (DWORD) emacs_pid) return TRUE; /* OK, let's raise it. */ if (!pfnAllowSetForegroundWindow (emacs_pid)) w32_sys_fatal1("AllowSetForegroundWindow"); found_emacs = TRUE; /* Stop enumeration. */ return FALSE; } /* * Search for a window of class "Emacs" and owned by a process with * process id = emacs_pid. If found, allow it to grab the focus. */ void w32_give_focus () { HMODULE hUser32; /* It shouldn't happen when dealing with TCP sockets. */ if (!emacs_pid) return; if (!(hUser32 = LoadLibrary ("user32.dll"))) return; /* Modern Windows restrict which processes can set the foreground window. emacsclient can allow Emacs to grab the focus by calling the function AllowSetForegroundWindow. Unfortunately, older Windows (W95, W98 and NT) lack this function, so we have to check its availability. */ if ((pfnAllowSetForegroundWindow = GetProcAddress (hUser32, "AllowSetForegroundWindow")) && (pfnRealGetWindowClassA = GetProcAddress (hUser32, "RealGetWindowClassA"))) EnumWindows (w32_find_emacs_process, (LPARAM) 0); FreeLibrary (hUser32); if (!found_emacs) w32_fatal_1 ("Could not find Emacs"); } #define REG_ROOT "SOFTWARE\\GNU\\Emacs" /* Retrieve an environment variable from the Emacs subkeys of the registry. Return NULL if the variable was not found, or it was empty. This code is based on w32_get_resource (w32.c). */ char * w32_get_resource (predefined, key, type) HKEY predefined; char *key; LPDWORD type; { HKEY hrootkey = NULL; char *result = NULL; DWORD cbData; if (RegOpenKeyEx (predefined, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS) { if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS) { result = (char *) xmalloc (cbData); if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) || (*result == 0)) { free (result); result = NULL; } } RegCloseKey (hrootkey); } return result; } /* getenv wrapper for Windows This is needed to duplicate Emacs's behavior, which is to look for enviroment variables in the registry if they don't appear in the environment. */ char * w32_getenv (envvar) char *envvar; { char *value; DWORD dwType; if (value = getenv (envvar)) /* Found in the environment. */ return value; if (! (value = w32_get_resource (HKEY_CURRENT_USER, envvar, &dwType)) && ! (value = w32_get_resource (HKEY_LOCAL_MACHINE, envvar, &dwType))) /* Not found in the registry. */ return NULL; if (dwType == REG_SZ) /* Registry; no need to expand. */ return value; if (dwType == REG_EXPAND_SZ) { DWORD size; if (size = ExpandEnvironmentStrings (value, NULL, 0)) { char *buffer = (char *) xmalloc (size); if (ExpandEnvironmentStrings (value, buffer, size)) { /* Found and expanded. */ free (value); return buffer; } /* Error expanding. */ free (buffer); } } /* Not the right type, or not correctly expanded. */ free (value); return NULL; } /* execvp wrapper for Windows. Quotes arguments with embedded spaces. This is necessary due to the broken implementation of exec* routines in the Microsoft libraries: they concatenate the arguments together without quoting special characters, and pass the result to CreateProcess, with predictably bad results. By contrast, Posix execvp passes the arguments directly into the argv array of the child process. */ int w32_execvp (path, argv) char *path; char **argv; { int i; /* Required to allow a .BAT script as alternate editor. */ argv[0] = (char *) alternate_editor; for (i = 0; argv[i]; i++) if (strchr (argv[i], ' ')) { char *quoted = alloca (strlen (argv[i]) + 3); sprintf (quoted, "\"%s\"", argv[i]); argv[i] = quoted; } return execvp (path, argv); } #undef execvp #define execvp w32_execvp /* Emulation of ttyname for Windows. */ char * ttyname (int fd) { return "CONOUT$"; }