This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
RE: Problem in Win32CORE when building PAR-Packer-0.975 with bleadperl on Win32
[perl5.git] / win32 / win32.c
index a829b17..55ab70e 100644 (file)
@@ -19,7 +19,7 @@
 #  define HWND_MESSAGE     ((HWND)-3)
 #endif
 #ifndef WC_NO_BEST_FIT_CHARS
-#  define WC_NO_BEST_FIT_CHARS 0x00000400
+#  define WC_NO_BEST_FIT_CHARS 0x00000400 /* requires Windows 2000 or later */
 #endif
 #include <winnt.h>
 #include <tlhelp32.h>
@@ -60,13 +60,6 @@ typedef struct {
 #include "EXTERN.h"
 #include "perl.h"
 
-/* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
-#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
-#  include <shellapi.h>
-#else
-EXTERN_C LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
-#endif
-
 #define NO_XSLOCKS
 #define PERL_NO_GET_CONTEXT
 #include "XSUB.h"
@@ -164,7 +157,22 @@ _matherr(struct _exception *a)
 }
 #endif
 
-#if _MSC_VER >= 1400
+/* VS2005 (MSC version 14) provides a mechanism to set an invalid
+ * parameter handler.  This functionality is not available in the
+ * 64-bit compiler from the Platform SDK, which unfortunately also
+ * believes itself to be MSC version 14.
+ *
+ * There is no #define related to _set_invalid_parameter_handler(),
+ * but we can check for one of the constants defined for
+ * _set_abort_behavior(), which was introduced into stdlib.h at
+ * the same time.
+ */
+
+#if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
+#  define SET_INVALID_PARAMETER_HANDLER
+#endif
+
+#ifdef SET_INVALID_PARAMETER_HANDLER
 void my_invalid_parameter_handler(const wchar_t* expression,
     const wchar_t* function, 
     const wchar_t* file, 
@@ -191,6 +199,12 @@ IsWinNT(void)
     return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
 }
 
+int
+IsWin2000(void)
+{
+    return (g_osver.dwMajorVersion > 4);
+}
+
 EXTERN_C void
 set_w32_module_name(void)
 {
@@ -204,7 +218,7 @@ set_w32_module_name(void)
     osver.dwOSVersionInfoSize = sizeof(osver);
     GetVersionEx(&osver);
 
-    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    if (osver.dwMajorVersion > 4) {
         WCHAR modulename[MAX_PATH];
         WCHAR fullname[MAX_PATH];
         char *ansi;
@@ -843,7 +857,7 @@ win32_opendir(const char *filename)
     scanname[len] = '\0';
 
     /* do the FindFirstFile call */
-    if (IsWinNT()) {
+    if (IsWin2000()) {
         WCHAR wscanname[sizeof(scanname)];
         MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
        dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
@@ -934,7 +948,7 @@ win32_readdir(DIR *dirp)
            /* finding the next file that matches the wildcard
             * (which should be all of them in this directory!).
             */
-           if (IsWinNT()) {
+           if (IsWin2000()) {
                 WIN32_FIND_DATAW wFindData;
                res = FindNextFileW(dirp->handle, &wFindData);
                if (res) {
@@ -1203,7 +1217,7 @@ kill_process_tree_toolhelp(DWORD pid, int sig)
     int killed = 0;
 
     process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
-    if (process_handle == INVALID_HANDLE_VALUE)
+    if (process_handle == NULL)
         return 0;
 
     killed += terminate_process(pid, process_handle, sig);
@@ -1238,7 +1252,7 @@ kill_process_tree_sysinfo(SYSTEM_PROCESSES *process_info, DWORD pid, int sig)
     int killed = 0;
 
     process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
-    if (process_handle == INVALID_HANDLE_VALUE)
+    if (process_handle == NULL)
         return 0;
 
     killed += terminate_process(pid, process_handle, sig);
@@ -1293,7 +1307,8 @@ my_kill(int pid, int sig)
         return killpg(pid, -sig);
 
     process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
-    if (process_handle != INVALID_HANDLE_VALUE) {
+    /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
+    if (process_handle != NULL) {
         retval = terminate_process(pid, process_handle, sig);
         CloseHandle(process_handle);
     }
@@ -1332,6 +1347,7 @@ win32_kill(int pid, int sig)
                     /* Yield and wait for the other thread to send us its message_hwnd */
                     Sleep(0);
                     win32_async_check(aTHX);
+                   hwnd = w32_pseudo_child_message_hwnds[child];
                     ++count;
                 }
                 if (hwnd != INVALID_HANDLE_VALUE) {
@@ -2143,7 +2159,7 @@ win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD result
        timeout += ticks;
     }
     while (1) {
-       DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
+       DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_POSTMESSAGE|QS_TIMER);
        if (resultp)
           *resultp = result;
        if (result == WAIT_TIMEOUT) {
@@ -4561,73 +4577,23 @@ XS(w32_SetChildShowWindow)
     XSRETURN(1);
 }
 
-static void
-forward(pTHX_ const char *function)
-{
-    dXSARGS;
-    Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvn("Win32",5), newSVnv(0.27));
-    SPAGAIN;
-    PUSHMARK(SP-items);
-    call_pv(function, GIMME_V);
-}
-
-#define FORWARD(function) XS(w32_##function){ forward(aTHX_ "Win32::"#function); }
-FORWARD(GetCwd)
-FORWARD(SetCwd)
-FORWARD(GetNextAvailDrive)
-FORWARD(GetLastError)
-FORWARD(SetLastError)
-FORWARD(LoginName)
-FORWARD(NodeName)
-FORWARD(DomainName)
-FORWARD(FsType)
-FORWARD(GetOSVersion)
-FORWARD(IsWinNT)
-FORWARD(IsWin95)
-FORWARD(FormatMessage)
-FORWARD(Spawn)
-FORWARD(GetTickCount)
-FORWARD(GetShortPathName)
-FORWARD(GetFullPathName)
-FORWARD(GetLongPathName)
-FORWARD(CopyFile)
-FORWARD(Sleep)
-
-/* Don't forward Win32::SetChildShowWindow().  It accesses the internal variable
- * w32_showwindow in thread_intern and is therefore not implemented in Win32.xs.
- */
-/* FORWARD(SetChildShowWindow) */
-
-#undef FORWARD
-
 void
 Perl_init_os_extras(void)
 {
     dTHX;
     char *file = __FILE__;
-    dXSUB_SYS;
-
-    /* these names are Activeware compatible */
-    newXS("Win32::GetCwd", w32_GetCwd, file);
-    newXS("Win32::SetCwd", w32_SetCwd, file);
-    newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
-    newXS("Win32::GetLastError", w32_GetLastError, file);
-    newXS("Win32::SetLastError", w32_SetLastError, file);
-    newXS("Win32::LoginName", w32_LoginName, file);
-    newXS("Win32::NodeName", w32_NodeName, file);
-    newXS("Win32::DomainName", w32_DomainName, file);
-    newXS("Win32::FsType", w32_FsType, file);
-    newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
-    newXS("Win32::IsWinNT", w32_IsWinNT, file);
-    newXS("Win32::IsWin95", w32_IsWin95, file);
-    newXS("Win32::FormatMessage", w32_FormatMessage, file);
-    newXS("Win32::Spawn", w32_Spawn, file);
-    newXS("Win32::GetTickCount", w32_GetTickCount, file);
-    newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
-    newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
-    newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
-    newXS("Win32::CopyFile", w32_CopyFile, file);
-    newXS("Win32::Sleep", w32_Sleep, file);
+
+    /* Initialize Win32CORE if it has been statically linked. */
+    void (*pfn_init)(pTHX);
+#if defined(__BORLANDC__)
+    /* makedef.pl seems to have given up on fixing this issue in the .def file */
+    pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "_init_Win32CORE");
+#else
+    pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "init_Win32CORE");
+#endif
+    if (pfn_init)
+        pfn_init(aTHX);
+
     newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
 }
 
@@ -4700,7 +4666,7 @@ win32_ctrlhandler(DWORD dwCtrlType)
 }
 
 
-#if _MSC_VER >= 1400
+#ifdef SET_INVALID_PARAMETER_HANDLER
 #  include <crtdbg.h>
 #endif
 
@@ -4712,8 +4678,8 @@ ansify_path(void)
     WCHAR *wide_path;
     WCHAR *wide_dir;
 
-    /* there is no Unicode environment on Windows 9X */
-    if (IsWin95())
+    /* win32_ansipath() requires Windows 2000 or later */
+    if (!IsWin2000())
         return;
 
     /* fetch Unicode version of PATH */
@@ -4807,7 +4773,7 @@ Perl_win32_init(int *argcp, char ***argvp)
 {
     HMODULE module;
 
-#if _MSC_VER >= 1400
+#ifdef SET_INVALID_PARAMETER_HANDLER
     _invalid_parameter_handler oldHandler, newHandler;
     newHandler = my_invalid_parameter_handler;
     oldHandler = _set_invalid_parameter_handler(newHandler);
@@ -4880,19 +4846,6 @@ win32_signal(int sig, Sighandler_t subcode)
     }
 }
 
-
-#ifdef HAVE_INTERP_INTERN
-
-static void
-win32_csighandler(int sig)
-{
-#if 0
-    dTHXa(PERL_GET_SIG_CONTEXT);
-    Perl_warn(aTHX_ "Got signal %d",sig);
-#endif
-    /* Does nothing */
-}
-
 HWND
 win32_create_message_window()
 {
@@ -4904,12 +4857,24 @@ win32_create_message_window()
      * "right" place with DispatchMessage() anymore, as there is no WindowProc
      * if there is no window handle.
      */
-    if (g_osver.dwMajorVersion < 5)
+    if (!IsWin2000())
         return NULL;
 
     return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
 }
 
+#ifdef HAVE_INTERP_INTERN
+
+static void
+win32_csighandler(int sig)
+{
+#if 0
+    dTHXa(PERL_GET_SIG_CONTEXT);
+    Perl_warn(aTHX_ "Got signal %d",sig);
+#endif
+    /* Does nothing */
+}
+
 #if defined(__MINGW32__) && defined(__cplusplus)
 #define CAST_HWND__(x) (HWND__*)(x)
 #else
@@ -4938,7 +4903,7 @@ Perl_sys_intern_init(pTHX)
     for (i=0; i < SIG_SIZE; i++) {
        w32_sighandler[i] = SIG_DFL;
     }
-#  ifdef MULTIPLICTY
+#  ifdef MULTIPLICITY
     if (my_perl == PL_curinterp) {
 #  else
     {
@@ -4946,6 +4911,16 @@ Perl_sys_intern_init(pTHX)
        /* Force C runtime signal stuff to set its console handler */
        signal(SIGINT,win32_csighandler);
        signal(SIGBREAK,win32_csighandler);
+
+        /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
+         * flag.  This has the side-effect of disabling Ctrl-C events in all
+         * processes in this group.  At least on Windows NT and later we
+         * can re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
+         * with a NULL handler.  This is not valid on Windows 9X.
+         */
+        if (IsWinNT())
+            SetConsoleCtrlHandler(NULL,FALSE);
+
        /* Push our handler on top */
        SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
     }
@@ -4995,32 +4970,3 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
 }
 #  endif /* USE_ITHREADS */
 #endif /* HAVE_INTERP_INTERN */
-
-static void
-win32_free_argvw(pTHX_ void *ptr)
-{
-    char** argv = (char**)ptr;
-    while(*argv) {
-       Safefree(*argv);
-       *argv++ = Nullch;
-    }
-}
-
-void
-win32_argv2utf8(int argc, char** argv)
-{
-    dTHX;
-    char* psz;
-    int length, wargc;
-    LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
-    if (lpwStr && argc) {
-       while (argc--) {
-           length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
-           Newxz(psz, length, char);
-           WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
-           argv[argc] = psz;
-       }
-       call_atexit(win32_free_argvw, argv);
-    }
-    GlobalFree((HGLOBAL)lpwStr);
-}