3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc.
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
16 # define Win32_Winsock
20 # define _WIN32_WINNT 0x0500 /* needed for CreateHardlink() etc. */
26 # define HWND_MESSAGE ((HWND)-3)
29 #ifndef PROCESSOR_ARCHITECTURE_AMD64
30 # define PROCESSOR_ARCHITECTURE_AMD64 9
33 #ifndef WC_NO_BEST_FIT_CHARS
34 # define WC_NO_BEST_FIT_CHARS 0x00000400
43 /* #include "config.h" */
45 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
54 #define PERL_NO_GET_CONTEXT
59 /* assert.h conflicts with #define of assert in perl.h */
68 #if defined(_MSC_VER) || defined(__MINGW32__)
69 # include <sys/utime.h>
75 /* Mingw32 defaults to globing command line
76 * So we turn it off like this:
81 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
82 /* Mingw32-1.1 is missing some prototypes */
84 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
85 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
86 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
92 #if defined(__BORLANDC__)
94 # define _utimbuf utimbuf
99 #define EXECF_SPAWN_NOWAIT 3
101 #if defined(PERL_IMPLICIT_SYS)
102 # undef win32_get_privlib
103 # define win32_get_privlib g_win32_get_privlib
104 # undef win32_get_sitelib
105 # define win32_get_sitelib g_win32_get_sitelib
106 # undef win32_get_vendorlib
107 # define win32_get_vendorlib g_win32_get_vendorlib
109 # define getlogin g_getlogin
112 static void get_shell(void);
113 static long tokenize(const char *str, char **dest, char ***destv);
114 static int do_spawn2(pTHX_ const char *cmd, int exectype);
115 static BOOL has_shell_metachars(const char *ptr);
116 static long filetime_to_clock(PFILETIME ft);
117 static BOOL filetime_from_time(PFILETIME ft, time_t t);
118 static char * get_emd_part(SV **leading, STRLEN *const len,
119 char *trailing, ...);
120 static void remove_dead_process(long deceased);
121 static long find_pid(int pid);
122 static char * qualified_path(const char *cmd);
123 static char * win32_get_xlib(const char *pl, const char *xlib,
124 const char *libname, STRLEN *const len);
125 static LRESULT win32_process_message(HWND hwnd, UINT msg,
126 WPARAM wParam, LPARAM lParam);
129 static void remove_dead_pseudo_process(long child);
130 static long find_pseudo_pid(int pid);
134 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
135 char w32_module_name[MAX_PATH+1];
138 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
141 /* Silence STDERR grumblings from Borland's math library. */
143 _matherr(struct _exception *a)
150 /* VS2005 (MSC version 14) provides a mechanism to set an invalid
151 * parameter handler. This functionality is not available in the
152 * 64-bit compiler from the Platform SDK, which unfortunately also
153 * believes itself to be MSC version 14.
155 * There is no #define related to _set_invalid_parameter_handler(),
156 * but we can check for one of the constants defined for
157 * _set_abort_behavior(), which was introduced into stdlib.h at
161 #if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
162 # define SET_INVALID_PARAMETER_HANDLER
165 #ifdef SET_INVALID_PARAMETER_HANDLER
166 void my_invalid_parameter_handler(const wchar_t* expression,
167 const wchar_t* function,
173 wprintf(L"Invalid parameter detected in function %s."
174 L" File: %s Line: %d\n", function, file, line);
175 wprintf(L"Expression: %s\n", expression);
181 set_w32_module_name(void)
183 /* this function may be called at DLL_PROCESS_ATTACH time */
185 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
186 ? GetModuleHandle(NULL)
187 : w32_perldll_handle);
189 OSVERSIONINFO osver; /* g_osver may not yet be initialized */
190 osver.dwOSVersionInfoSize = sizeof(osver);
191 GetVersionEx(&osver);
193 if (osver.dwMajorVersion > 4) {
194 WCHAR modulename[MAX_PATH];
195 WCHAR fullname[MAX_PATH];
198 DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
199 (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
200 GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
202 GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
204 /* Make sure we get an absolute pathname in case the module was loaded
205 * explicitly by LoadLibrary() with a relative path. */
206 GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
208 /* Make sure we start with the long path name of the module because we
209 * later scan for pathname components to match "5.xx" to locate
210 * compatible sitelib directories, and the short pathname might mangle
211 * this path segment (e.g. by removing the dot on NTFS to something
212 * like "5xx~1.yy") */
213 if (pfnGetLongPathNameW)
214 pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
216 /* remove \\?\ prefix */
217 if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
218 memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
220 ansi = win32_ansipath(fullname);
221 my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
225 GetModuleFileName(module, w32_module_name, sizeof(w32_module_name));
227 /* remove \\?\ prefix */
228 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
229 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
231 /* try to get full path to binary (which may be mangled when perl is
232 * run from a 16-bit app) */
233 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
234 win32_longpath(w32_module_name);
235 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
238 /* normalize to forward slashes */
239 ptr = w32_module_name;
247 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
249 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
251 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
254 const char *subkey = "Software\\Perl";
258 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
259 if (retval == ERROR_SUCCESS) {
261 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
262 if (retval == ERROR_SUCCESS
263 && (type == REG_SZ || type == REG_EXPAND_SZ))
267 *svp = sv_2mortal(newSVpvn("",0));
268 SvGROW(*svp, datalen);
269 retval = RegQueryValueEx(handle, valuename, 0, NULL,
270 (PBYTE)SvPVX(*svp), &datalen);
271 if (retval == ERROR_SUCCESS) {
273 SvCUR_set(*svp,datalen-1);
281 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
283 get_regstr(const char *valuename, SV **svp)
285 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
287 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
291 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
293 get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
297 char mod_name[MAX_PATH+1];
303 va_start(ap, trailing_path);
304 strip = va_arg(ap, char *);
306 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
307 baselen = strlen(base);
309 if (!*w32_module_name) {
310 set_w32_module_name();
312 strcpy(mod_name, w32_module_name);
313 ptr = strrchr(mod_name, '/');
314 while (ptr && strip) {
315 /* look for directories to skip back */
318 ptr = strrchr(mod_name, '/');
319 /* avoid stripping component if there is no slash,
320 * or it doesn't match ... */
321 if (!ptr || stricmp(ptr+1, strip) != 0) {
322 /* ... but not if component matches m|5\.$patchlevel.*| */
323 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
324 && strncmp(strip, base, baselen) == 0
325 && strncmp(ptr+1, base, baselen) == 0))
331 strip = va_arg(ap, char *);
339 strcpy(++ptr, trailing_path);
341 /* only add directory if it exists */
342 if (GetFileAttributes(mod_name) != (DWORD) -1) {
343 /* directory exists */
346 *prev_pathp = sv_2mortal(newSVpvn("",0));
347 else if (SvPVX(*prev_pathp))
348 sv_catpvn(*prev_pathp, ";", 1);
349 sv_catpv(*prev_pathp, mod_name);
351 *len = SvCUR(*prev_pathp);
352 return SvPVX(*prev_pathp);
359 win32_get_privlib(const char *pl, STRLEN *const len)
362 char *stdlib = "lib";
363 char buffer[MAX_PATH+1];
366 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
367 sprintf(buffer, "%s-%s", stdlib, pl);
368 if (!get_regstr(buffer, &sv))
369 (void)get_regstr(stdlib, &sv);
371 /* $stdlib .= ";$EMD/../../lib" */
372 return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
376 win32_get_xlib(const char *pl, const char *xlib, const char *libname,
381 char pathstr[MAX_PATH+1];
385 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
386 sprintf(regstr, "%s-%s", xlib, pl);
387 (void)get_regstr(regstr, &sv1);
390 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
391 sprintf(pathstr, "%s/%s/lib", libname, pl);
392 (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
394 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
395 (void)get_regstr(xlib, &sv2);
398 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
399 sprintf(pathstr, "%s/lib", libname);
400 (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
407 sv_catpvn(sv1, ";", 1);
417 win32_get_sitelib(const char *pl, STRLEN *const len)
419 return win32_get_xlib(pl, "sitelib", "site", len);
422 #ifndef PERL_VENDORLIB_NAME
423 # define PERL_VENDORLIB_NAME "vendor"
427 win32_get_vendorlib(const char *pl, STRLEN *const len)
429 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME, len);
433 has_shell_metachars(const char *ptr)
439 * Scan string looking for redirection (< or >) or pipe
440 * characters (|) that are not in a quoted string.
441 * Shell variable interpolation (%VAR%) can also happen inside strings.
473 #if !defined(PERL_IMPLICIT_SYS)
474 /* since the current process environment is being updated in util.c
475 * the library functions will get the correct environment
478 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
480 PERL_FLUSHALL_FOR_CHILD;
481 return win32_popen(cmd, mode);
485 Perl_my_pclose(pTHX_ PerlIO *fp)
487 return win32_pclose(fp);
491 DllExport unsigned long
494 return (unsigned long)g_osver.dwPlatformId;
503 return -((int)w32_pseudo_id);
508 /* Tokenize a string. Words are null-separated, and the list
509 * ends with a doubled null. Any character (except null and
510 * including backslash) may be escaped by preceding it with a
511 * backslash (the backslash will be stripped).
512 * Returns number of words in result buffer.
515 tokenize(const char *str, char **dest, char ***destv)
517 char *retstart = NULL;
518 char **retvstart = 0;
522 int slen = strlen(str);
524 register char **retv;
525 Newx(ret, slen+2, char);
526 Newx(retv, (slen+3)/2, char*);
534 if (*ret == '\\' && *str)
536 else if (*ret == ' ') {
552 retvstart[items] = NULL;
565 if (!w32_perlshell_tokens) {
566 /* we don't use COMSPEC here for two reasons:
567 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
568 * uncontrolled unportability of the ensuing scripts.
569 * 2. PERL5SHELL could be set to a shell that may not be fit for
570 * interactive use (which is what most programs look in COMSPEC
573 const char* defaultshell = "cmd.exe /x/d/c";
574 const char *usershell = PerlEnv_getenv("PERL5SHELL");
575 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
576 &w32_perlshell_tokens,
582 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
590 PERL_ARGS_ASSERT_DO_ASPAWN;
596 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
598 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
603 while (++mark <= sp) {
604 if (*mark && (str = SvPV_nolen(*mark)))
611 status = win32_spawnvp(flag,
612 (const char*)(really ? SvPV_nolen(really) : argv[0]),
613 (const char* const*)argv);
615 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
616 /* possible shell-builtin, invoke with shell */
618 sh_items = w32_perlshell_items;
620 argv[index+sh_items] = argv[index];
621 while (--sh_items >= 0)
622 argv[sh_items] = w32_perlshell_vec[sh_items];
624 status = win32_spawnvp(flag,
625 (const char*)(really ? SvPV_nolen(really) : argv[0]),
626 (const char* const*)argv);
629 if (flag == P_NOWAIT) {
630 PL_statusvalue = -1; /* >16bits hint for pp_system() */
634 if (ckWARN(WARN_EXEC))
635 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
640 PL_statusvalue = status;
646 /* returns pointer to the next unquoted space or the end of the string */
648 find_next_space(const char *s)
650 bool in_quotes = FALSE;
652 /* ignore doubled backslashes, or backslash+quote */
653 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
656 /* keep track of when we're within quotes */
657 else if (*s == '"') {
659 in_quotes = !in_quotes;
661 /* break it up only at spaces that aren't in quotes */
662 else if (!in_quotes && isSPACE(*s))
671 do_spawn2(pTHX_ const char *cmd, int exectype)
677 BOOL needToTry = TRUE;
680 /* Save an extra exec if possible. See if there are shell
681 * metacharacters in it */
682 if (!has_shell_metachars(cmd)) {
683 Newx(argv, strlen(cmd) / 2 + 2, char*);
684 Newx(cmd2, strlen(cmd) + 1, char);
687 for (s = cmd2; *s;) {
688 while (*s && isSPACE(*s))
692 s = find_next_space(s);
700 status = win32_spawnvp(P_WAIT, argv[0],
701 (const char* const*)argv);
703 case EXECF_SPAWN_NOWAIT:
704 status = win32_spawnvp(P_NOWAIT, argv[0],
705 (const char* const*)argv);
708 status = win32_execvp(argv[0], (const char* const*)argv);
711 if (status != -1 || errno == 0)
721 Newx(argv, w32_perlshell_items + 2, char*);
722 while (++i < w32_perlshell_items)
723 argv[i] = w32_perlshell_vec[i];
724 argv[i++] = (char *)cmd;
728 status = win32_spawnvp(P_WAIT, argv[0],
729 (const char* const*)argv);
731 case EXECF_SPAWN_NOWAIT:
732 status = win32_spawnvp(P_NOWAIT, argv[0],
733 (const char* const*)argv);
736 status = win32_execvp(argv[0], (const char* const*)argv);
742 if (exectype == EXECF_SPAWN_NOWAIT) {
743 PL_statusvalue = -1; /* >16bits hint for pp_system() */
747 if (ckWARN(WARN_EXEC))
748 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
749 (exectype == EXECF_EXEC ? "exec" : "spawn"),
750 cmd, strerror(errno));
755 PL_statusvalue = status;
761 Perl_do_spawn(pTHX_ char *cmd)
763 PERL_ARGS_ASSERT_DO_SPAWN;
765 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
769 Perl_do_spawn_nowait(pTHX_ char *cmd)
771 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
773 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
777 Perl_do_exec(pTHX_ const char *cmd)
779 PERL_ARGS_ASSERT_DO_EXEC;
781 do_spawn2(aTHX_ cmd, EXECF_EXEC);
785 /* The idea here is to read all the directory names into a string table
786 * (separated by nulls) and when one of the other dir functions is called
787 * return the pointer to the current file name.
790 win32_opendir(const char *filename)
796 char scanname[MAX_PATH+3];
797 WCHAR wscanname[sizeof(scanname)];
798 WIN32_FIND_DATAW wFindData;
799 char buffer[MAX_PATH*2];
802 len = strlen(filename);
807 if (len > MAX_PATH) {
808 errno = ENAMETOOLONG;
812 /* Get us a DIR structure */
815 /* Create the search pattern */
816 strcpy(scanname, filename);
818 /* bare drive name means look in cwd for drive */
819 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
820 scanname[len++] = '.';
821 scanname[len++] = '/';
823 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
824 scanname[len++] = '/';
826 scanname[len++] = '*';
827 scanname[len] = '\0';
829 /* do the FindFirstFile call */
830 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
831 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
833 if (dirp->handle == INVALID_HANDLE_VALUE) {
834 DWORD err = GetLastError();
835 /* FindFirstFile() fails on empty drives! */
837 case ERROR_FILE_NOT_FOUND:
839 case ERROR_NO_MORE_FILES:
840 case ERROR_PATH_NOT_FOUND:
843 case ERROR_NOT_ENOUGH_MEMORY:
855 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
856 wFindData.cFileName, -1,
857 buffer, sizeof(buffer), NULL, &use_default);
858 if (use_default && *wFindData.cAlternateFileName) {
859 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
860 wFindData.cAlternateFileName, -1,
861 buffer, sizeof(buffer), NULL, NULL);
864 /* now allocate the first part of the string table for
865 * the filenames that we find.
867 idx = strlen(buffer)+1;
872 Newx(dirp->start, dirp->size, char);
873 strcpy(dirp->start, buffer);
875 dirp->end = dirp->curr = dirp->start;
881 /* Readdir just returns the current string pointer and bumps the
882 * string pointer to the nDllExport entry.
884 DllExport struct direct *
885 win32_readdir(DIR *dirp)
890 /* first set up the structure to return */
891 len = strlen(dirp->curr);
892 strcpy(dirp->dirstr.d_name, dirp->curr);
893 dirp->dirstr.d_namlen = len;
896 dirp->dirstr.d_ino = dirp->curr - dirp->start;
898 /* Now set up for the next call to readdir */
899 dirp->curr += len + 1;
900 if (dirp->curr >= dirp->end) {
903 char buffer[MAX_PATH*2];
905 if (dirp->handle == INVALID_HANDLE_VALUE) {
908 /* finding the next file that matches the wildcard
909 * (which should be all of them in this directory!).
912 WIN32_FIND_DATAW wFindData;
913 res = FindNextFileW(dirp->handle, &wFindData);
915 BOOL use_default = FALSE;
916 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
917 wFindData.cFileName, -1,
918 buffer, sizeof(buffer), NULL, &use_default);
919 if (use_default && *wFindData.cAlternateFileName) {
920 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
921 wFindData.cAlternateFileName, -1,
922 buffer, sizeof(buffer), NULL, NULL);
927 long endpos = dirp->end - dirp->start;
928 long newsize = endpos + strlen(buffer) + 1;
929 /* bump the string table size by enough for the
930 * new name and its null terminator */
931 while (newsize > dirp->size) {
932 long curpos = dirp->curr - dirp->start;
934 Renew(dirp->start, dirp->size, char);
935 dirp->curr = dirp->start + curpos;
937 strcpy(dirp->start + endpos, buffer);
938 dirp->end = dirp->start + newsize;
943 if (dirp->handle != INVALID_HANDLE_VALUE) {
944 FindClose(dirp->handle);
945 dirp->handle = INVALID_HANDLE_VALUE;
949 return &(dirp->dirstr);
955 /* Telldir returns the current string pointer position */
957 win32_telldir(DIR *dirp)
959 return dirp->curr ? (dirp->curr - dirp->start) : -1;
963 /* Seekdir moves the string pointer to a previously saved position
964 * (returned by telldir).
967 win32_seekdir(DIR *dirp, long loc)
969 dirp->curr = loc == -1 ? NULL : dirp->start + loc;
972 /* Rewinddir resets the string pointer to the start */
974 win32_rewinddir(DIR *dirp)
976 dirp->curr = dirp->start;
979 /* free the memory allocated by opendir */
981 win32_closedir(DIR *dirp)
984 if (dirp->handle != INVALID_HANDLE_VALUE)
985 FindClose(dirp->handle);
986 Safefree(dirp->start);
991 /* duplicate a open DIR* for interpreter cloning */
993 win32_dirp_dup(DIR *const dirp, CLONE_PARAMS *const param)
996 PerlInterpreter *const from = param->proto_perl;
997 PerlInterpreter *const to = PERL_GET_THX;
1002 /* switch back to original interpreter because win32_readdir()
1003 * might Renew(dirp->start).
1009 /* mark current position; read all remaining entries into the
1010 * cache, and then restore to current position.
1012 pos = win32_telldir(dirp);
1013 while (win32_readdir(dirp)) {
1014 /* read all entries into cache */
1016 win32_seekdir(dirp, pos);
1018 /* switch back to new interpreter to allocate new DIR structure */
1024 memcpy(dup, dirp, sizeof(DIR));
1026 Newx(dup->start, dirp->size, char);
1027 memcpy(dup->start, dirp->start, dirp->size);
1029 dup->end = dup->start + (dirp->end - dirp->start);
1031 dup->curr = dup->start + (dirp->curr - dirp->start);
1043 * Just pretend that everyone is a superuser. NT will let us know if
1044 * we don\'t really have permission to do something.
1047 #define ROOT_UID ((uid_t)0)
1048 #define ROOT_GID ((gid_t)0)
1077 return (auid == ROOT_UID ? 0 : -1);
1083 return (agid == ROOT_GID ? 0 : -1);
1090 char *buf = w32_getlogin_buffer;
1091 DWORD size = sizeof(w32_getlogin_buffer);
1092 if (GetUserName(buf,&size))
1098 chown(const char *path, uid_t owner, gid_t group)
1105 * XXX this needs strengthening (for PerlIO)
1108 int mkstemp(const char *path)
1111 char buf[MAX_PATH+1];
1115 if (i++ > 10) { /* give up */
1119 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1123 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1133 long child = w32_num_children;
1134 while (--child >= 0) {
1135 if ((int)w32_child_pids[child] == pid)
1142 remove_dead_process(long child)
1146 CloseHandle(w32_child_handles[child]);
1147 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1148 (w32_num_children-child-1), HANDLE);
1149 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1150 (w32_num_children-child-1), DWORD);
1157 find_pseudo_pid(int pid)
1160 long child = w32_num_pseudo_children;
1161 while (--child >= 0) {
1162 if ((int)w32_pseudo_child_pids[child] == pid)
1169 remove_dead_pseudo_process(long child)
1173 CloseHandle(w32_pseudo_child_handles[child]);
1174 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1175 (w32_num_pseudo_children-child-1), HANDLE);
1176 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1177 (w32_num_pseudo_children-child-1), DWORD);
1178 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1179 (w32_num_pseudo_children-child-1), HWND);
1180 w32_num_pseudo_children--;
1186 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1190 /* "Does process exist?" use of kill */
1193 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1198 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1201 default: /* For now be backwards compatible with perl 5.6 */
1203 /* Note that we will only be able to kill processes owned by the
1204 * current process owner, even when we are running as an administrator.
1205 * To kill processes of other owners we would need to set the
1206 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1208 if (TerminateProcess(process_handle, sig))
1216 killpg(int pid, int sig)
1218 HANDLE process_handle;
1219 HANDLE snapshot_handle;
1222 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1223 if (process_handle == NULL)
1226 killed += terminate_process(pid, process_handle, sig);
1228 snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1229 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1230 PROCESSENTRY32 entry;
1232 entry.dwSize = sizeof(entry);
1233 if (Process32First(snapshot_handle, &entry)) {
1235 if (entry.th32ParentProcessID == (DWORD)pid)
1236 killed += killpg(entry.th32ProcessID, sig);
1237 entry.dwSize = sizeof(entry);
1239 while (Process32Next(snapshot_handle, &entry));
1241 CloseHandle(snapshot_handle);
1243 CloseHandle(process_handle);
1248 my_kill(int pid, int sig)
1251 HANDLE process_handle;
1254 return killpg(pid, -sig);
1256 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1257 /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1258 if (process_handle != NULL) {
1259 retval = terminate_process(pid, process_handle, sig);
1260 CloseHandle(process_handle);
1266 win32_kill(int pid, int sig)
1272 /* it is a pseudo-forked child */
1273 child = find_pseudo_pid(-pid);
1275 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1276 HANDLE hProcess = w32_pseudo_child_handles[child];
1279 /* "Does process exist?" use of kill */
1283 /* kill -9 style un-graceful exit */
1284 if (TerminateThread(hProcess, sig)) {
1285 remove_dead_pseudo_process(child);
1292 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1293 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1294 /* Yield and wait for the other thread to send us its message_hwnd */
1296 win32_async_check(aTHX);
1297 hwnd = w32_pseudo_child_message_hwnds[child];
1300 if (hwnd != INVALID_HANDLE_VALUE) {
1301 /* We fake signals to pseudo-processes using Win32
1302 * message queue. In Win9X the pids are negative already. */
1303 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1304 PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1306 /* It might be us ... */
1319 child = find_pid(pid);
1321 if (my_kill(pid, sig)) {
1323 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1324 exitcode != STILL_ACTIVE)
1326 remove_dead_process(child);
1332 if (my_kill(pid, sig))
1341 win32_stat(const char *path, Stat_t *sbuf)
1344 char buffer[MAX_PATH+1];
1345 int l = strlen(path);
1348 BOOL expect_dir = FALSE;
1350 GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
1351 GV_NOTQUAL, SVt_PV);
1352 BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
1355 switch(path[l - 1]) {
1356 /* FindFirstFile() and stat() are buggy with a trailing
1357 * slashes, except for the root directory of a drive */
1360 if (l > sizeof(buffer)) {
1361 errno = ENAMETOOLONG;
1365 strncpy(buffer, path, l);
1366 /* remove additional trailing slashes */
1367 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1369 /* add back slash if we otherwise end up with just a drive letter */
1370 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1377 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1379 if (l == 2 && isALPHA(path[0])) {
1380 buffer[0] = path[0];
1391 path = PerlDir_mapA(path);
1395 /* We must open & close the file once; otherwise file attribute changes */
1396 /* might not yet have propagated to "other" hard links of the same file. */
1397 /* This also gives us an opportunity to determine the number of links. */
1398 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1399 if (handle != INVALID_HANDLE_VALUE) {
1400 BY_HANDLE_FILE_INFORMATION bhi;
1401 if (GetFileInformationByHandle(handle, &bhi))
1402 nlink = bhi.nNumberOfLinks;
1403 CloseHandle(handle);
1407 /* path will be mapped correctly above */
1408 #if defined(WIN64) || defined(USE_LARGE_FILES)
1409 res = _stati64(path, sbuf);
1411 res = stat(path, sbuf);
1413 sbuf->st_nlink = nlink;
1416 /* CRT is buggy on sharenames, so make sure it really isn't.
1417 * XXX using GetFileAttributesEx() will enable us to set
1418 * sbuf->st_*time (but note that's not available on the
1419 * Windows of 1995) */
1420 DWORD r = GetFileAttributesA(path);
1421 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1422 /* sbuf may still contain old garbage since stat() failed */
1423 Zero(sbuf, 1, Stat_t);
1424 sbuf->st_mode = S_IFDIR | S_IREAD;
1426 if (!(r & FILE_ATTRIBUTE_READONLY))
1427 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1432 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1433 && (path[2] == '\\' || path[2] == '/'))
1435 /* The drive can be inaccessible, some _stat()s are buggy */
1436 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1441 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1445 if (S_ISDIR(sbuf->st_mode)) {
1446 /* Ensure the "write" bit is switched off in the mode for
1447 * directories with the read-only attribute set. Borland (at least)
1448 * switches it on for directories, which is technically correct
1449 * (directories are indeed always writable unless denied by DACLs),
1450 * but we want stat() and -w to reflect the state of the read-only
1451 * attribute for symmetry with chmod(). */
1452 DWORD r = GetFileAttributesA(path);
1453 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
1454 sbuf->st_mode &= ~S_IWRITE;
1458 if (S_ISDIR(sbuf->st_mode)) {
1459 sbuf->st_mode |= S_IEXEC;
1461 else if (S_ISREG(sbuf->st_mode)) {
1463 if (l >= 4 && path[l-4] == '.') {
1464 const char *e = path + l - 3;
1465 if (strnicmp(e,"exe",3)
1466 && strnicmp(e,"bat",3)
1467 && strnicmp(e,"com",3)
1468 && strnicmp(e,"cmd",3))
1469 sbuf->st_mode &= ~S_IEXEC;
1471 sbuf->st_mode |= S_IEXEC;
1474 sbuf->st_mode &= ~S_IEXEC;
1475 /* Propagate permissions to _group_ and _others_ */
1476 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1477 sbuf->st_mode |= (perms>>3) | (perms>>6);
1484 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1485 #define SKIP_SLASHES(s) \
1487 while (*(s) && isSLASH(*(s))) \
1490 #define COPY_NONSLASHES(d,s) \
1492 while (*(s) && !isSLASH(*(s))) \
1496 /* Find the longname of a given path. path is destructively modified.
1497 * It should have space for at least MAX_PATH characters. */
1499 win32_longpath(char *path)
1501 WIN32_FIND_DATA fdata;
1503 char tmpbuf[MAX_PATH+1];
1504 char *tmpstart = tmpbuf;
1511 if (isALPHA(path[0]) && path[1] == ':') {
1513 *tmpstart++ = path[0];
1517 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1519 *tmpstart++ = path[0];
1520 *tmpstart++ = path[1];
1521 SKIP_SLASHES(start);
1522 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1524 *tmpstart++ = *start++;
1525 SKIP_SLASHES(start);
1526 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1531 /* copy initial slash, if any */
1532 if (isSLASH(*start)) {
1533 *tmpstart++ = *start++;
1535 SKIP_SLASHES(start);
1538 /* FindFirstFile() expands "." and "..", so we need to pass
1539 * those through unmolested */
1541 && (!start[1] || isSLASH(start[1])
1542 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1544 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1549 /* if this is the end, bust outta here */
1553 /* now we're at a non-slash; walk up to next slash */
1554 while (*start && !isSLASH(*start))
1557 /* stop and find full name of component */
1560 fhand = FindFirstFile(path,&fdata);
1562 if (fhand != INVALID_HANDLE_VALUE) {
1563 STRLEN len = strlen(fdata.cFileName);
1564 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1565 strcpy(tmpstart, fdata.cFileName);
1576 /* failed a step, just return without side effects */
1577 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1582 strcpy(path,tmpbuf);
1591 /* Can't use PerlIO to write as it allocates memory */
1592 PerlLIO_write(PerlIO_fileno(Perl_error_log),
1593 PL_no_mem, strlen(PL_no_mem));
1599 /* The win32_ansipath() function takes a Unicode filename and converts it
1600 * into the current Windows codepage. If some characters cannot be mapped,
1601 * then it will convert the short name instead.
1603 * The buffer to the ansi pathname must be freed with win32_free() when it
1604 * it no longer needed.
1606 * The argument to win32_ansipath() must exist before this function is
1607 * called; otherwise there is no way to determine the short path name.
1609 * Ideas for future refinement:
1610 * - Only convert those segments of the path that are not in the current
1611 * codepage, but leave the other segments in their long form.
1612 * - If the resulting name is longer than MAX_PATH, start converting
1613 * additional path segments into short names until the full name
1614 * is shorter than MAX_PATH. Shorten the filename part last!
1617 win32_ansipath(const WCHAR *widename)
1620 BOOL use_default = FALSE;
1621 size_t widelen = wcslen(widename)+1;
1622 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1623 NULL, 0, NULL, NULL);
1624 name = win32_malloc(len);
1628 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1629 name, len, NULL, &use_default);
1631 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1633 WCHAR *shortname = win32_malloc(shortlen*sizeof(WCHAR));
1636 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1638 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1639 NULL, 0, NULL, NULL);
1640 name = win32_realloc(name, len);
1643 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1644 name, len, NULL, NULL);
1645 win32_free(shortname);
1652 win32_getenv(const char *name)
1658 needlen = GetEnvironmentVariableA(name,NULL,0);
1660 curitem = sv_2mortal(newSVpvn("", 0));
1662 SvGROW(curitem, needlen+1);
1663 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1665 } while (needlen >= SvLEN(curitem));
1666 SvCUR_set(curitem, needlen);
1669 /* allow any environment variables that begin with 'PERL'
1670 to be stored in the registry */
1671 if (strncmp(name, "PERL", 4) == 0)
1672 (void)get_regstr(name, &curitem);
1674 if (curitem && SvCUR(curitem))
1675 return SvPVX(curitem);
1681 win32_putenv(const char *name)
1689 Newx(curitem,strlen(name)+1,char);
1690 strcpy(curitem, name);
1691 val = strchr(curitem, '=');
1693 /* The sane way to deal with the environment.
1694 * Has these advantages over putenv() & co.:
1695 * * enables us to store a truly empty value in the
1696 * environment (like in UNIX).
1697 * * we don't have to deal with RTL globals, bugs and leaks
1698 * (specifically, see http://support.microsoft.com/kb/235601).
1700 * Why you may want to use the RTL environment handling
1701 * (previously enabled by USE_WIN32_RTL_ENV):
1702 * * environ[] and RTL functions will not reflect changes,
1703 * which might be an issue if extensions want to access
1704 * the env. via RTL. This cuts both ways, since RTL will
1705 * not see changes made by extensions that call the Win32
1706 * functions directly, either.
1710 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1719 filetime_to_clock(PFILETIME ft)
1721 __int64 qw = ft->dwHighDateTime;
1723 qw |= ft->dwLowDateTime;
1724 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1729 win32_times(struct tms *timebuf)
1734 clock_t process_time_so_far = clock();
1735 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1737 timebuf->tms_utime = filetime_to_clock(&user);
1738 timebuf->tms_stime = filetime_to_clock(&kernel);
1739 timebuf->tms_cutime = 0;
1740 timebuf->tms_cstime = 0;
1742 /* That failed - e.g. Win95 fallback to clock() */
1743 timebuf->tms_utime = process_time_so_far;
1744 timebuf->tms_stime = 0;
1745 timebuf->tms_cutime = 0;
1746 timebuf->tms_cstime = 0;
1748 return process_time_so_far;
1751 /* fix utime() so it works on directories in NT */
1753 filetime_from_time(PFILETIME pFileTime, time_t Time)
1755 struct tm *pTM = localtime(&Time);
1756 SYSTEMTIME SystemTime;
1762 SystemTime.wYear = pTM->tm_year + 1900;
1763 SystemTime.wMonth = pTM->tm_mon + 1;
1764 SystemTime.wDay = pTM->tm_mday;
1765 SystemTime.wHour = pTM->tm_hour;
1766 SystemTime.wMinute = pTM->tm_min;
1767 SystemTime.wSecond = pTM->tm_sec;
1768 SystemTime.wMilliseconds = 0;
1770 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1771 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1775 win32_unlink(const char *filename)
1781 filename = PerlDir_mapA(filename);
1782 attrs = GetFileAttributesA(filename);
1783 if (attrs == 0xFFFFFFFF) {
1787 if (attrs & FILE_ATTRIBUTE_READONLY) {
1788 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1789 ret = unlink(filename);
1791 (void)SetFileAttributesA(filename, attrs);
1794 ret = unlink(filename);
1799 win32_utime(const char *filename, struct utimbuf *times)
1806 struct utimbuf TimeBuffer;
1809 filename = PerlDir_mapA(filename);
1810 rc = utime(filename, times);
1812 /* EACCES: path specifies directory or readonly file */
1813 if (rc == 0 || errno != EACCES)
1816 if (times == NULL) {
1817 times = &TimeBuffer;
1818 time(×->actime);
1819 times->modtime = times->actime;
1822 /* This will (and should) still fail on readonly files */
1823 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1824 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1825 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1826 if (handle == INVALID_HANDLE_VALUE)
1829 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1830 filetime_from_time(&ftAccess, times->actime) &&
1831 filetime_from_time(&ftWrite, times->modtime) &&
1832 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1837 CloseHandle(handle);
1842 unsigned __int64 ft_i64;
1847 #define Const64(x) x##LL
1849 #define Const64(x) x##i64
1851 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1852 #define EPOCH_BIAS Const64(116444736000000000)
1854 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1855 * and appears to be unsupported even by glibc) */
1857 win32_gettimeofday(struct timeval *tp, void *not_used)
1861 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1862 GetSystemTimeAsFileTime(&ft.ft_val);
1864 /* seconds since epoch */
1865 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1867 /* microseconds remaining */
1868 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1874 win32_uname(struct utsname *name)
1876 struct hostent *hep;
1877 STRLEN nodemax = sizeof(name->nodename)-1;
1880 switch (g_osver.dwPlatformId) {
1881 case VER_PLATFORM_WIN32_WINDOWS:
1882 strcpy(name->sysname, "Windows");
1884 case VER_PLATFORM_WIN32_NT:
1885 strcpy(name->sysname, "Windows NT");
1887 case VER_PLATFORM_WIN32s:
1888 strcpy(name->sysname, "Win32s");
1891 strcpy(name->sysname, "Win32 Unknown");
1896 sprintf(name->release, "%d.%d",
1897 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1900 sprintf(name->version, "Build %d",
1901 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1902 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1903 if (g_osver.szCSDVersion[0]) {
1904 char *buf = name->version + strlen(name->version);
1905 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1909 hep = win32_gethostbyname("localhost");
1911 STRLEN len = strlen(hep->h_name);
1912 if (len <= nodemax) {
1913 strcpy(name->nodename, hep->h_name);
1916 strncpy(name->nodename, hep->h_name, nodemax);
1917 name->nodename[nodemax] = '\0';
1922 if (!GetComputerName(name->nodename, &sz))
1923 *name->nodename = '\0';
1926 /* machine (architecture) */
1931 GetSystemInfo(&info);
1933 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1934 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
1935 procarch = info.u.s.wProcessorArchitecture;
1937 procarch = info.wProcessorArchitecture;
1940 case PROCESSOR_ARCHITECTURE_INTEL:
1941 arch = "x86"; break;
1942 case PROCESSOR_ARCHITECTURE_IA64:
1943 arch = "ia64"; break;
1944 case PROCESSOR_ARCHITECTURE_AMD64:
1945 arch = "amd64"; break;
1946 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1947 arch = "unknown"; break;
1949 sprintf(name->machine, "unknown(0x%x)", procarch);
1950 arch = name->machine;
1953 if (name->machine != arch)
1954 strcpy(name->machine, arch);
1959 /* Timing related stuff */
1962 do_raise(pTHX_ int sig)
1964 if (sig < SIG_SIZE) {
1965 Sighandler_t handler = w32_sighandler[sig];
1966 if (handler == SIG_IGN) {
1969 else if (handler != SIG_DFL) {
1974 /* Choose correct default behaviour */
1990 /* Tell caller to exit thread/process as approriate */
1995 sig_terminate(pTHX_ int sig)
1997 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1998 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2005 win32_async_check(pTHX)
2008 HWND hwnd = w32_message_hwnd;
2010 /* Reset w32_poll_count before doing anything else, incase we dispatch
2011 * messages that end up calling back into perl */
2014 if (hwnd != INVALID_HANDLE_VALUE) {
2015 /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2016 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2021 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2022 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2024 /* re-post a WM_QUIT message (we'll mark it as read later) */
2025 if(msg.message == WM_QUIT) {
2026 PostQuitMessage((int)msg.wParam);
2030 if(!CallMsgFilter(&msg, MSGF_USER))
2032 TranslateMessage(&msg);
2033 DispatchMessage(&msg);
2038 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2039 * This is necessary when we are being called by win32_msgwait() to
2040 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2041 * message over and over. An example how this can happen is when
2042 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2043 * is generating messages before the process terminated.
2045 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2047 /* Above or other stuff may have set a signal flag */
2054 /* This function will not return until the timeout has elapsed, or until
2055 * one of the handles is ready. */
2057 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2059 /* We may need several goes at this - so compute when we stop */
2061 if (timeout != INFINITE) {
2062 ticks = GetTickCount();
2066 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
2069 if (result == WAIT_TIMEOUT) {
2070 /* Ran out of time - explicit return of zero to avoid -ve if we
2071 have scheduling issues
2075 if (timeout != INFINITE) {
2076 ticks = GetTickCount();
2078 if (result == WAIT_OBJECT_0 + count) {
2079 /* Message has arrived - check it */
2080 (void)win32_async_check(aTHX);
2083 /* Not timeout or message - one of handles is ready */
2087 /* compute time left to wait */
2088 ticks = timeout - ticks;
2089 /* If we are past the end say zero */
2090 return (ticks > 0) ? ticks : 0;
2094 win32_internal_wait(int *status, DWORD timeout)
2096 /* XXX this wait emulation only knows about processes
2097 * spawned via win32_spawnvp(P_NOWAIT, ...).
2101 DWORD exitcode, waitcode;
2104 if (w32_num_pseudo_children) {
2105 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2106 timeout, &waitcode);
2107 /* Time out here if there are no other children to wait for. */
2108 if (waitcode == WAIT_TIMEOUT) {
2109 if (!w32_num_children) {
2113 else if (waitcode != WAIT_FAILED) {
2114 if (waitcode >= WAIT_ABANDONED_0
2115 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2116 i = waitcode - WAIT_ABANDONED_0;
2118 i = waitcode - WAIT_OBJECT_0;
2119 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2120 *status = (int)((exitcode & 0xff) << 8);
2121 retval = (int)w32_pseudo_child_pids[i];
2122 remove_dead_pseudo_process(i);
2129 if (!w32_num_children) {
2134 /* if a child exists, wait for it to die */
2135 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2136 if (waitcode == WAIT_TIMEOUT) {
2139 if (waitcode != WAIT_FAILED) {
2140 if (waitcode >= WAIT_ABANDONED_0
2141 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2142 i = waitcode - WAIT_ABANDONED_0;
2144 i = waitcode - WAIT_OBJECT_0;
2145 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2146 *status = (int)((exitcode & 0xff) << 8);
2147 retval = (int)w32_child_pids[i];
2148 remove_dead_process(i);
2153 errno = GetLastError();
2158 win32_waitpid(int pid, int *status, int flags)
2161 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2164 if (pid == -1) /* XXX threadid == 1 ? */
2165 return win32_internal_wait(status, timeout);
2168 child = find_pseudo_pid(-pid);
2170 HANDLE hThread = w32_pseudo_child_handles[child];
2172 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2173 if (waitcode == WAIT_TIMEOUT) {
2176 else if (waitcode == WAIT_OBJECT_0) {
2177 if (GetExitCodeThread(hThread, &waitcode)) {
2178 *status = (int)((waitcode & 0xff) << 8);
2179 retval = (int)w32_pseudo_child_pids[child];
2180 remove_dead_pseudo_process(child);
2192 child = find_pid(pid);
2194 hProcess = w32_child_handles[child];
2195 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2196 if (waitcode == WAIT_TIMEOUT) {
2199 else if (waitcode == WAIT_OBJECT_0) {
2200 if (GetExitCodeProcess(hProcess, &waitcode)) {
2201 *status = (int)((waitcode & 0xff) << 8);
2202 retval = (int)w32_child_pids[child];
2203 remove_dead_process(child);
2211 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
2213 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2214 if (waitcode == WAIT_TIMEOUT) {
2215 CloseHandle(hProcess);
2218 else if (waitcode == WAIT_OBJECT_0) {
2219 if (GetExitCodeProcess(hProcess, &waitcode)) {
2220 *status = (int)((waitcode & 0xff) << 8);
2221 CloseHandle(hProcess);
2225 CloseHandle(hProcess);
2231 return retval >= 0 ? pid : retval;
2235 win32_wait(int *status)
2237 return win32_internal_wait(status, INFINITE);
2240 DllExport unsigned int
2241 win32_sleep(unsigned int t)
2244 /* Win32 times are in ms so *1000 in and /1000 out */
2245 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2248 DllExport unsigned int
2249 win32_alarm(unsigned int sec)
2252 * the 'obvious' implentation is SetTimer() with a callback
2253 * which does whatever receiving SIGALRM would do
2254 * we cannot use SIGALRM even via raise() as it is not
2255 * one of the supported codes in <signal.h>
2259 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2260 w32_message_hwnd = win32_create_message_window();
2263 if (w32_message_hwnd == NULL)
2264 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2267 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2272 KillTimer(w32_message_hwnd, w32_timerid);
2279 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2282 win32_crypt(const char *txt, const char *salt)
2285 return des_fcrypt(txt, salt, w32_crypt_buffer);
2288 /* simulate flock by locking a range on the file */
2290 #define LK_LEN 0xffff0000
2293 win32_flock(int fd, int oper)
2299 fh = (HANDLE)_get_osfhandle(fd);
2300 if (fh == (HANDLE)-1) /* _get_osfhandle() already sets errno to EBADF */
2303 memset(&o, 0, sizeof(o));
2306 case LOCK_SH: /* shared lock */
2307 if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2310 case LOCK_EX: /* exclusive lock */
2311 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2314 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2315 if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2318 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2319 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2323 case LOCK_UN: /* unlock lock */
2324 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2327 default: /* unknown */
2332 if (GetLastError() == ERROR_LOCK_VIOLATION)
2333 errno = WSAEWOULDBLOCK;
2343 * redirected io subsystem for all XS modules
2356 return (&(_environ));
2359 /* the rest are the remapped stdio routines */
2379 win32_ferror(FILE *fp)
2381 return (ferror(fp));
2386 win32_feof(FILE *fp)
2392 * Since the errors returned by the socket error function
2393 * WSAGetLastError() are not known by the library routine strerror
2394 * we have to roll our own.
2398 win32_strerror(int e)
2400 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2401 extern int sys_nerr;
2404 if (e < 0 || e > sys_nerr) {
2409 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2410 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2411 w32_strerror_buffer, sizeof(w32_strerror_buffer),
2414 strcpy(w32_strerror_buffer, "Unknown Error");
2416 return w32_strerror_buffer;
2420 #define strerror win32_strerror
2424 win32_str_os_error(void *sv, DWORD dwErr)
2428 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2429 |FORMAT_MESSAGE_IGNORE_INSERTS
2430 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2431 dwErr, 0, (char *)&sMsg, 1, NULL);
2432 /* strip trailing whitespace and period */
2435 --dwLen; /* dwLen doesn't include trailing null */
2436 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2437 if ('.' != sMsg[dwLen])
2442 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2444 dwLen = sprintf(sMsg,
2445 "Unknown error #0x%lX (lookup 0x%lX)",
2446 dwErr, GetLastError());
2450 sv_setpvn((SV*)sv, sMsg, dwLen);
2456 win32_fprintf(FILE *fp, const char *format, ...)
2459 va_start(marker, format); /* Initialize variable arguments. */
2461 return (vfprintf(fp, format, marker));
2465 win32_printf(const char *format, ...)
2468 va_start(marker, format); /* Initialize variable arguments. */
2470 return (vprintf(format, marker));
2474 win32_vfprintf(FILE *fp, const char *format, va_list args)
2476 return (vfprintf(fp, format, args));
2480 win32_vprintf(const char *format, va_list args)
2482 return (vprintf(format, args));
2486 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2488 return fread(buf, size, count, fp);
2492 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2494 return fwrite(buf, size, count, fp);
2497 #define MODE_SIZE 10
2500 win32_fopen(const char *filename, const char *mode)
2508 if (stricmp(filename, "/dev/null")==0)
2511 f = fopen(PerlDir_mapA(filename), mode);
2512 /* avoid buffering headaches for child processes */
2513 if (f && *mode == 'a')
2514 win32_fseek(f, 0, SEEK_END);
2518 #ifndef USE_SOCKETS_AS_HANDLES
2520 #define fdopen my_fdopen
2524 win32_fdopen(int handle, const char *mode)
2528 f = fdopen(handle, (char *) mode);
2529 /* avoid buffering headaches for child processes */
2530 if (f && *mode == 'a')
2531 win32_fseek(f, 0, SEEK_END);
2536 win32_freopen(const char *path, const char *mode, FILE *stream)
2539 if (stricmp(path, "/dev/null")==0)
2542 return freopen(PerlDir_mapA(path), mode, stream);
2546 win32_fclose(FILE *pf)
2548 return my_fclose(pf); /* defined in win32sck.c */
2552 win32_fputs(const char *s,FILE *pf)
2554 return fputs(s, pf);
2558 win32_fputc(int c,FILE *pf)
2564 win32_ungetc(int c,FILE *pf)
2566 return ungetc(c,pf);
2570 win32_getc(FILE *pf)
2576 win32_fileno(FILE *pf)
2582 win32_clearerr(FILE *pf)
2589 win32_fflush(FILE *pf)
2595 win32_ftell(FILE *pf)
2597 #if defined(WIN64) || defined(USE_LARGE_FILES)
2598 #if defined(__BORLANDC__) /* buk */
2599 return win32_tell( fileno( pf ) );
2602 if (fgetpos(pf, &pos))
2612 win32_fseek(FILE *pf, Off_t offset,int origin)
2614 #if defined(WIN64) || defined(USE_LARGE_FILES)
2615 #if defined(__BORLANDC__) /* buk */
2625 if (fgetpos(pf, &pos))
2630 fseek(pf, 0, SEEK_END);
2631 pos = _telli64(fileno(pf));
2640 return fsetpos(pf, &offset);
2643 return fseek(pf, (long)offset, origin);
2648 win32_fgetpos(FILE *pf,fpos_t *p)
2650 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2651 if( win32_tell(fileno(pf)) == -1L ) {
2657 return fgetpos(pf, p);
2662 win32_fsetpos(FILE *pf,const fpos_t *p)
2664 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2665 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2667 return fsetpos(pf, p);
2672 win32_rewind(FILE *pf)
2682 char prefix[MAX_PATH+1];
2683 char filename[MAX_PATH+1];
2684 DWORD len = GetTempPath(MAX_PATH, prefix);
2685 if (len && len < MAX_PATH) {
2686 if (GetTempFileName(prefix, "plx", 0, filename)) {
2687 HANDLE fh = CreateFile(filename,
2688 DELETE | GENERIC_READ | GENERIC_WRITE,
2692 FILE_ATTRIBUTE_NORMAL
2693 | FILE_FLAG_DELETE_ON_CLOSE,
2695 if (fh != INVALID_HANDLE_VALUE) {
2696 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2698 #if defined(__BORLANDC__)
2699 setmode(fd,O_BINARY);
2701 DEBUG_p(PerlIO_printf(Perl_debug_log,
2702 "Created tmpfile=%s\n",filename));
2714 int fd = win32_tmpfd();
2716 return win32_fdopen(fd, "w+b");
2728 win32_fstat(int fd, Stat_t *sbufptr)
2731 /* A file designated by filehandle is not shown as accessible
2732 * for write operations, probably because it is opened for reading.
2735 BY_HANDLE_FILE_INFORMATION bhfi;
2736 # if defined(WIN64) || defined(USE_LARGE_FILES)
2737 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2739 int rc = fstat(fd,&tmp);
2741 sbufptr->st_dev = tmp.st_dev;
2742 sbufptr->st_ino = tmp.st_ino;
2743 sbufptr->st_mode = tmp.st_mode;
2744 sbufptr->st_nlink = tmp.st_nlink;
2745 sbufptr->st_uid = tmp.st_uid;
2746 sbufptr->st_gid = tmp.st_gid;
2747 sbufptr->st_rdev = tmp.st_rdev;
2748 sbufptr->st_size = tmp.st_size;
2749 sbufptr->st_atime = tmp.st_atime;
2750 sbufptr->st_mtime = tmp.st_mtime;
2751 sbufptr->st_ctime = tmp.st_ctime;
2753 int rc = fstat(fd,sbufptr);
2756 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2757 # if defined(WIN64) || defined(USE_LARGE_FILES)
2758 sbufptr->st_size = ((__int64)bhfi.nFileSizeHigh << 32) | bhfi.nFileSizeLow ;
2760 sbufptr->st_mode &= 0xFE00;
2761 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2762 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2764 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2765 + ((S_IREAD|S_IWRITE) >> 6));
2769 # if defined(WIN64) || defined(USE_LARGE_FILES)
2770 return _fstati64(fd, sbufptr);
2772 return fstat(fd, sbufptr);
2778 win32_pipe(int *pfd, unsigned int size, int mode)
2780 return _pipe(pfd, size, mode);
2784 win32_popenlist(const char *mode, IV narg, SV **args)
2787 Perl_croak(aTHX_ "List form of pipe open not implemented");
2792 * a popen() clone that respects PERL5SHELL
2794 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2798 win32_popen(const char *command, const char *mode)
2800 #ifdef USE_RTL_POPEN
2801 return _popen(command, mode);
2813 /* establish which ends read and write */
2814 if (strchr(mode,'w')) {
2815 stdfd = 0; /* stdin */
2818 nhandle = STD_INPUT_HANDLE;
2820 else if (strchr(mode,'r')) {
2821 stdfd = 1; /* stdout */
2824 nhandle = STD_OUTPUT_HANDLE;
2829 /* set the correct mode */
2830 if (strchr(mode,'b'))
2832 else if (strchr(mode,'t'))
2835 ourmode = _fmode & (O_TEXT | O_BINARY);
2837 /* the child doesn't inherit handles */
2838 ourmode |= O_NOINHERIT;
2840 if (win32_pipe(p, 512, ourmode) == -1)
2843 /* save the old std handle (this needs to happen before the
2844 * dup2(), since that might call SetStdHandle() too) */
2847 old_h = GetStdHandle(nhandle);
2849 /* save current stdfd */
2850 if ((oldfd = win32_dup(stdfd)) == -1)
2853 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2854 /* stdfd will be inherited by the child */
2855 if (win32_dup2(p[child], stdfd) == -1)
2858 /* close the child end in parent */
2859 win32_close(p[child]);
2861 /* set the new std handle (in case dup2() above didn't) */
2862 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2864 /* start the child */
2867 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2870 /* revert stdfd to whatever it was before */
2871 if (win32_dup2(oldfd, stdfd) == -1)
2874 /* close saved handle */
2877 /* restore the old std handle (this needs to happen after the
2878 * dup2(), since that might call SetStdHandle() too */
2880 SetStdHandle(nhandle, old_h);
2885 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2887 /* set process id so that it can be returned by perl's open() */
2888 PL_forkprocess = childpid;
2891 /* we have an fd, return a file stream */
2892 return (PerlIO_fdopen(p[parent], (char *)mode));
2895 /* we don't need to check for errors here */
2899 win32_dup2(oldfd, stdfd);
2903 SetStdHandle(nhandle, old_h);
2909 #endif /* USE_RTL_POPEN */
2917 win32_pclose(PerlIO *pf)
2919 #ifdef USE_RTL_POPEN
2923 int childpid, status;
2926 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2929 childpid = SvIVX(sv);
2945 if (win32_waitpid(childpid, &status, 0) == -1)
2950 #endif /* USE_RTL_POPEN */
2954 win32_link(const char *oldname, const char *newname)
2957 WCHAR wOldName[MAX_PATH+1];
2958 WCHAR wNewName[MAX_PATH+1];
2960 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
2961 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
2962 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2963 CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2967 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2972 win32_rename(const char *oname, const char *newname)
2974 char szOldName[MAX_PATH+1];
2976 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
2979 if (stricmp(newname, oname))
2980 dwFlags |= MOVEFILE_REPLACE_EXISTING;
2981 strcpy(szOldName, PerlDir_mapA(oname));
2983 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
2985 DWORD err = GetLastError();
2987 case ERROR_BAD_NET_NAME:
2988 case ERROR_BAD_NETPATH:
2989 case ERROR_BAD_PATHNAME:
2990 case ERROR_FILE_NOT_FOUND:
2991 case ERROR_FILENAME_EXCED_RANGE:
2992 case ERROR_INVALID_DRIVE:
2993 case ERROR_NO_MORE_FILES:
2994 case ERROR_PATH_NOT_FOUND:
3007 win32_setmode(int fd, int mode)
3009 return setmode(fd, mode);
3013 win32_chsize(int fd, Off_t size)
3015 #if defined(WIN64) || defined(USE_LARGE_FILES)
3017 Off_t cur, end, extend;
3019 cur = win32_tell(fd);
3022 end = win32_lseek(fd, 0, SEEK_END);
3025 extend = size - end;
3029 else if (extend > 0) {
3030 /* must grow the file, padding with nulls */
3032 int oldmode = win32_setmode(fd, O_BINARY);
3034 memset(b, '\0', sizeof(b));
3036 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3037 count = win32_write(fd, b, count);
3038 if ((int)count < 0) {
3042 } while ((extend -= count) > 0);
3043 win32_setmode(fd, oldmode);
3046 /* shrink the file */
3047 win32_lseek(fd, size, SEEK_SET);
3048 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3054 win32_lseek(fd, cur, SEEK_SET);
3057 return chsize(fd, (long)size);
3062 win32_lseek(int fd, Off_t offset, int origin)
3064 #if defined(WIN64) || defined(USE_LARGE_FILES)
3065 #if defined(__BORLANDC__) /* buk */
3067 pos.QuadPart = offset;
3068 pos.LowPart = SetFilePointer(
3069 (HANDLE)_get_osfhandle(fd),
3074 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3078 return pos.QuadPart;
3080 return _lseeki64(fd, offset, origin);
3083 return lseek(fd, (long)offset, origin);
3090 #if defined(WIN64) || defined(USE_LARGE_FILES)
3091 #if defined(__BORLANDC__) /* buk */
3094 pos.LowPart = SetFilePointer(
3095 (HANDLE)_get_osfhandle(fd),
3100 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3104 return pos.QuadPart;
3105 /* return tell(fd); */
3107 return _telli64(fd);
3115 win32_open(const char *path, int flag, ...)
3122 pmode = va_arg(ap, int);
3125 if (stricmp(path, "/dev/null")==0)
3128 return open(PerlDir_mapA(path), flag, pmode);
3131 /* close() that understands socket */
3132 extern int my_close(int); /* in win32sck.c */
3137 return my_close(fd);
3147 win32_isatty(int fd)
3149 /* The Microsoft isatty() function returns true for *all*
3150 * character mode devices, including "nul". Our implementation
3151 * should only return true if the handle has a console buffer.
3154 HANDLE fh = (HANDLE)_get_osfhandle(fd);
3155 if (fh == (HANDLE)-1) {
3156 /* errno is already set to EBADF */
3160 if (GetConsoleMode(fh, &mode))
3174 win32_dup2(int fd1,int fd2)
3176 return dup2(fd1,fd2);
3180 win32_read(int fd, void *buf, unsigned int cnt)
3182 return read(fd, buf, cnt);
3186 win32_write(int fd, const void *buf, unsigned int cnt)
3188 return write(fd, buf, cnt);
3192 win32_mkdir(const char *dir, int mode)
3195 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3199 win32_rmdir(const char *dir)
3202 return rmdir(PerlDir_mapA(dir));
3206 win32_chdir(const char *dir)
3217 win32_access(const char *path, int mode)
3220 return access(PerlDir_mapA(path), mode);
3224 win32_chmod(const char *path, int mode)
3227 return chmod(PerlDir_mapA(path), mode);
3232 create_command_line(char *cname, STRLEN clen, const char * const *args)
3239 bool bat_file = FALSE;
3240 bool cmd_shell = FALSE;
3241 bool dumb_shell = FALSE;
3242 bool extra_quotes = FALSE;
3243 bool quote_next = FALSE;
3246 cname = (char*)args[0];
3248 /* The NT cmd.exe shell has the following peculiarity that needs to be
3249 * worked around. It strips a leading and trailing dquote when any
3250 * of the following is true:
3251 * 1. the /S switch was used
3252 * 2. there are more than two dquotes
3253 * 3. there is a special character from this set: &<>()@^|
3254 * 4. no whitespace characters within the two dquotes
3255 * 5. string between two dquotes isn't an executable file
3256 * To work around this, we always add a leading and trailing dquote
3257 * to the string, if the first argument is either "cmd.exe" or "cmd",
3258 * and there were at least two or more arguments passed to cmd.exe
3259 * (not including switches).
3260 * XXX the above rules (from "cmd /?") don't seem to be applied
3261 * always, making for the convolutions below :-(
3265 clen = strlen(cname);
3268 && (stricmp(&cname[clen-4], ".bat") == 0
3269 || (stricmp(&cname[clen-4], ".cmd") == 0)))
3275 char *exe = strrchr(cname, '/');
3276 char *exe2 = strrchr(cname, '\\');
3283 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3287 else if (stricmp(exe, "command.com") == 0
3288 || stricmp(exe, "command") == 0)
3295 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3296 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3297 STRLEN curlen = strlen(arg);
3298 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3299 len += 2; /* assume quoting needed (worst case) */
3301 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3303 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3306 Newx(cmd, len, char);
3311 extra_quotes = TRUE;
3314 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3316 STRLEN curlen = strlen(arg);
3318 /* we want to protect empty arguments and ones with spaces with
3319 * dquotes, but only if they aren't already there */
3324 else if (quote_next) {
3325 /* see if it really is multiple arguments pretending to
3326 * be one and force a set of quotes around it */
3327 if (*find_next_space(arg))
3330 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3332 while (i < curlen) {
3333 if (isSPACE(arg[i])) {
3336 else if (arg[i] == '"') {
3360 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3361 && stricmp(arg+curlen-2, "/c") == 0)
3363 /* is there a next argument? */
3364 if (args[index+1]) {
3365 /* are there two or more next arguments? */
3366 if (args[index+2]) {
3368 extra_quotes = TRUE;
3371 /* single argument, force quoting if it has spaces */
3387 qualified_path(const char *cmd)
3391 char *fullcmd, *curfullcmd;
3397 fullcmd = (char*)cmd;
3399 if (*fullcmd == '/' || *fullcmd == '\\')
3406 pathstr = PerlEnv_getenv("PATH");
3408 /* worst case: PATH is a single directory; we need additional space
3409 * to append "/", ".exe" and trailing "\0" */
3410 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3411 curfullcmd = fullcmd;
3416 /* start by appending the name to the current prefix */
3417 strcpy(curfullcmd, cmd);
3418 curfullcmd += cmdlen;
3420 /* if it doesn't end with '.', or has no extension, try adding
3421 * a trailing .exe first */
3422 if (cmd[cmdlen-1] != '.'
3423 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3425 strcpy(curfullcmd, ".exe");
3426 res = GetFileAttributes(fullcmd);
3427 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3432 /* that failed, try the bare name */
3433 res = GetFileAttributes(fullcmd);
3434 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3437 /* quit if no other path exists, or if cmd already has path */
3438 if (!pathstr || !*pathstr || has_slash)
3441 /* skip leading semis */
3442 while (*pathstr == ';')
3445 /* build a new prefix from scratch */
3446 curfullcmd = fullcmd;
3447 while (*pathstr && *pathstr != ';') {
3448 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3449 pathstr++; /* skip initial '"' */
3450 while (*pathstr && *pathstr != '"') {
3451 *curfullcmd++ = *pathstr++;
3454 pathstr++; /* skip trailing '"' */
3457 *curfullcmd++ = *pathstr++;
3461 pathstr++; /* skip trailing semi */
3462 if (curfullcmd > fullcmd /* append a dir separator */
3463 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3465 *curfullcmd++ = '\\';
3473 /* The following are just place holders.
3474 * Some hosts may provide and environment that the OS is
3475 * not tracking, therefore, these host must provide that
3476 * environment and the current directory to CreateProcess
3480 win32_get_childenv(void)
3486 win32_free_childenv(void* d)
3491 win32_clearenv(void)
3493 char *envv = GetEnvironmentStrings();
3497 char *end = strchr(cur,'=');
3498 if (end && end != cur) {
3500 SetEnvironmentVariable(cur, NULL);
3502 cur = end + strlen(end+1)+2;
3504 else if ((len = strlen(cur)))
3507 FreeEnvironmentStrings(envv);
3511 win32_get_childdir(void)
3515 char szfilename[MAX_PATH+1];
3517 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3518 Newx(ptr, strlen(szfilename)+1, char);
3519 strcpy(ptr, szfilename);
3524 win32_free_childdir(char* d)
3531 /* XXX this needs to be made more compatible with the spawnvp()
3532 * provided by the various RTLs. In particular, searching for
3533 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3534 * This doesn't significantly affect perl itself, because we
3535 * always invoke things using PERL5SHELL if a direct attempt to
3536 * spawn the executable fails.
3538 * XXX splitting and rejoining the commandline between do_aspawn()
3539 * and win32_spawnvp() could also be avoided.
3543 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3545 #ifdef USE_RTL_SPAWNVP
3546 return spawnvp(mode, cmdname, (char * const *)argv);
3553 STARTUPINFO StartupInfo;
3554 PROCESS_INFORMATION ProcessInformation;
3557 char *fullcmd = NULL;
3558 char *cname = (char *)cmdname;
3562 clen = strlen(cname);
3563 /* if command name contains dquotes, must remove them */
3564 if (strchr(cname, '"')) {
3566 Newx(cname,clen+1,char);
3579 cmd = create_command_line(cname, clen, argv);
3581 env = PerlEnv_get_childenv();
3582 dir = PerlEnv_get_childdir();
3585 case P_NOWAIT: /* asynch + remember result */
3586 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3591 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3594 create |= CREATE_NEW_PROCESS_GROUP;
3597 case P_WAIT: /* synchronous execution */
3599 default: /* invalid mode */
3604 memset(&StartupInfo,0,sizeof(StartupInfo));
3605 StartupInfo.cb = sizeof(StartupInfo);
3606 memset(&tbl,0,sizeof(tbl));
3607 PerlEnv_get_child_IO(&tbl);
3608 StartupInfo.dwFlags = tbl.dwFlags;
3609 StartupInfo.dwX = tbl.dwX;
3610 StartupInfo.dwY = tbl.dwY;
3611 StartupInfo.dwXSize = tbl.dwXSize;
3612 StartupInfo.dwYSize = tbl.dwYSize;
3613 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3614 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3615 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3616 StartupInfo.wShowWindow = tbl.wShowWindow;
3617 StartupInfo.hStdInput = tbl.childStdIn;
3618 StartupInfo.hStdOutput = tbl.childStdOut;
3619 StartupInfo.hStdError = tbl.childStdErr;
3620 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3621 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3622 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3624 create |= CREATE_NEW_CONSOLE;
3627 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3629 if (w32_use_showwindow) {
3630 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3631 StartupInfo.wShowWindow = w32_showwindow;
3634 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3637 if (!CreateProcess(cname, /* search PATH to find executable */
3638 cmd, /* executable, and its arguments */
3639 NULL, /* process attributes */
3640 NULL, /* thread attributes */
3641 TRUE, /* inherit handles */
3642 create, /* creation flags */
3643 (LPVOID)env, /* inherit environment */
3644 dir, /* inherit cwd */
3646 &ProcessInformation))
3648 /* initial NULL argument to CreateProcess() does a PATH
3649 * search, but it always first looks in the directory
3650 * where the current process was started, which behavior
3651 * is undesirable for backward compatibility. So we
3652 * jump through our own hoops by picking out the path
3653 * we really want it to use. */
3655 fullcmd = qualified_path(cname);
3657 if (cname != cmdname)
3660 DEBUG_p(PerlIO_printf(Perl_debug_log,
3661 "Retrying [%s] with same args\n",
3671 if (mode == P_NOWAIT) {
3672 /* asynchronous spawn -- store handle, return PID */
3673 ret = (int)ProcessInformation.dwProcessId;
3675 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3676 w32_child_pids[w32_num_children] = (DWORD)ret;
3681 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3682 /* FIXME: if msgwait returned due to message perhaps forward the
3683 "signal" to the process
3685 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3687 CloseHandle(ProcessInformation.hProcess);
3690 CloseHandle(ProcessInformation.hThread);
3693 PerlEnv_free_childenv(env);
3694 PerlEnv_free_childdir(dir);
3696 if (cname != cmdname)
3703 win32_execv(const char *cmdname, const char *const *argv)
3707 /* if this is a pseudo-forked child, we just want to spawn
3708 * the new program, and return */
3710 # ifdef __BORLANDC__
3711 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3713 return spawnv(P_WAIT, cmdname, argv);
3717 return execv(cmdname, (char *const *)argv);
3719 return execv(cmdname, argv);
3724 win32_execvp(const char *cmdname, const char *const *argv)
3728 /* if this is a pseudo-forked child, we just want to spawn
3729 * the new program, and return */
3730 if (w32_pseudo_id) {
3731 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3741 return execvp(cmdname, (char *const *)argv);
3743 return execvp(cmdname, argv);
3748 win32_perror(const char *str)
3754 win32_setbuf(FILE *pf, char *buf)
3760 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3762 return setvbuf(pf, buf, type, size);
3766 win32_flushall(void)
3772 win32_fcloseall(void)
3778 win32_fgets(char *s, int n, FILE *pf)
3780 return fgets(s, n, pf);
3790 win32_fgetc(FILE *pf)
3796 win32_putc(int c, FILE *pf)
3802 win32_puts(const char *s)
3814 win32_putchar(int c)
3821 #ifndef USE_PERL_SBRK
3823 static char *committed = NULL; /* XXX threadead */
3824 static char *base = NULL; /* XXX threadead */
3825 static char *reserved = NULL; /* XXX threadead */
3826 static char *brk = NULL; /* XXX threadead */
3827 static DWORD pagesize = 0; /* XXX threadead */
3830 sbrk(ptrdiff_t need)
3835 GetSystemInfo(&info);
3836 /* Pretend page size is larger so we don't perpetually
3837 * call the OS to commit just one page ...
3839 pagesize = info.dwPageSize << 3;
3841 if (brk+need >= reserved)
3843 DWORD size = brk+need-reserved;
3845 char *prev_committed = NULL;
3846 if (committed && reserved && committed < reserved)
3848 /* Commit last of previous chunk cannot span allocations */
3849 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3852 /* Remember where we committed from in case we want to decommit later */
3853 prev_committed = committed;
3854 committed = reserved;
3857 /* Reserve some (more) space
3858 * Contiguous blocks give us greater efficiency, so reserve big blocks -
3859 * this is only address space not memory...
3860 * Note this is a little sneaky, 1st call passes NULL as reserved
3861 * so lets system choose where we start, subsequent calls pass
3862 * the old end address so ask for a contiguous block
3865 if (size < 64*1024*1024)
3866 size = 64*1024*1024;
3867 size = ((size + pagesize - 1) / pagesize) * pagesize;
3868 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3871 reserved = addr+size;
3881 /* The existing block could not be extended far enough, so decommit
3882 * anything that was just committed above and start anew */
3885 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
3888 reserved = base = committed = brk = NULL;
3899 if (brk > committed)
3901 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3903 if (committed+size > reserved)
3904 size = reserved-committed;
3905 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
3918 win32_malloc(size_t size)
3920 return malloc(size);
3924 win32_calloc(size_t numitems, size_t size)
3926 return calloc(numitems,size);
3930 win32_realloc(void *block, size_t size)
3932 return realloc(block,size);
3936 win32_free(void *block)
3943 win32_open_osfhandle(intptr_t handle, int flags)
3945 return _open_osfhandle(handle, flags);
3949 win32_get_osfhandle(int fd)
3951 return (intptr_t)_get_osfhandle(fd);
3955 win32_fdupopen(FILE *pf)
3960 int fileno = win32_dup(win32_fileno(pf));
3962 /* open the file in the same mode */
3964 if((pf)->flags & _F_READ) {
3968 else if((pf)->flags & _F_WRIT) {
3972 else if((pf)->flags & _F_RDWR) {
3978 if((pf)->_flag & _IOREAD) {
3982 else if((pf)->_flag & _IOWRT) {
3986 else if((pf)->_flag & _IORW) {
3993 /* it appears that the binmode is attached to the
3994 * file descriptor so binmode files will be handled
3997 pfdup = win32_fdopen(fileno, mode);
3999 /* move the file pointer to the same position */
4000 if (!fgetpos(pf, &pos)) {
4001 fsetpos(pfdup, &pos);
4007 win32_dynaload(const char* filename)
4010 char buf[MAX_PATH+1];
4013 /* LoadLibrary() doesn't recognize forward slashes correctly,
4014 * so turn 'em back. */
4015 first = strchr(filename, '/');
4017 STRLEN len = strlen(filename);
4018 if (len <= MAX_PATH) {
4019 strcpy(buf, filename);
4020 filename = &buf[first - filename];
4022 if (*filename == '/')
4023 *(char*)filename = '\\';
4029 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4032 XS(w32_SetChildShowWindow)
4035 BOOL use_showwindow = w32_use_showwindow;
4036 /* use "unsigned short" because Perl has redefined "WORD" */
4037 unsigned short showwindow = w32_showwindow;
4040 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4042 if (items == 0 || !SvOK(ST(0)))
4043 w32_use_showwindow = FALSE;
4045 w32_use_showwindow = TRUE;
4046 w32_showwindow = (unsigned short)SvIV(ST(0));
4051 ST(0) = sv_2mortal(newSViv(showwindow));
4053 ST(0) = &PL_sv_undef;
4058 Perl_init_os_extras(void)
4061 char *file = __FILE__;
4063 /* Initialize Win32CORE if it has been statically linked. */
4064 void (*pfn_init)(pTHX);
4065 #if defined(__BORLANDC__)
4066 /* makedef.pl seems to have given up on fixing this issue in the .def file */
4067 pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "_init_Win32CORE");
4069 pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "init_Win32CORE");
4074 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4078 win32_signal_context(void)
4083 my_perl = PL_curinterp;
4084 PERL_SET_THX(my_perl);
4088 return PL_curinterp;
4094 win32_ctrlhandler(DWORD dwCtrlType)
4097 dTHXa(PERL_GET_SIG_CONTEXT);
4103 switch(dwCtrlType) {
4104 case CTRL_CLOSE_EVENT:
4105 /* A signal that the system sends to all processes attached to a console when
4106 the user closes the console (either by choosing the Close command from the
4107 console window's System menu, or by choosing the End Task command from the
4110 if (do_raise(aTHX_ 1)) /* SIGHUP */
4111 sig_terminate(aTHX_ 1);
4115 /* A CTRL+c signal was received */
4116 if (do_raise(aTHX_ SIGINT))
4117 sig_terminate(aTHX_ SIGINT);
4120 case CTRL_BREAK_EVENT:
4121 /* A CTRL+BREAK signal was received */
4122 if (do_raise(aTHX_ SIGBREAK))
4123 sig_terminate(aTHX_ SIGBREAK);
4126 case CTRL_LOGOFF_EVENT:
4127 /* A signal that the system sends to all console processes when a user is logging
4128 off. This signal does not indicate which user is logging off, so no
4129 assumptions can be made.
4132 case CTRL_SHUTDOWN_EVENT:
4133 /* A signal that the system sends to all console processes when the system is
4136 if (do_raise(aTHX_ SIGTERM))
4137 sig_terminate(aTHX_ SIGTERM);
4146 #ifdef SET_INVALID_PARAMETER_HANDLER
4147 # include <crtdbg.h>
4158 /* fetch Unicode version of PATH */
4160 wide_path = win32_malloc(len*sizeof(WCHAR));
4162 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4166 wide_path = win32_realloc(wide_path, len*sizeof(WCHAR));
4171 /* convert to ANSI pathnames */
4172 wide_dir = wide_path;
4175 WCHAR *sep = wcschr(wide_dir, ';');
4183 /* remove quotes around pathname */
4184 if (*wide_dir == '"')
4186 wide_len = wcslen(wide_dir);
4187 if (wide_len && wide_dir[wide_len-1] == '"')
4188 wide_dir[wide_len-1] = '\0';
4190 /* append ansi_dir to ansi_path */
4191 ansi_dir = win32_ansipath(wide_dir);
4192 ansi_len = strlen(ansi_dir);
4194 size_t newlen = len + 1 + ansi_len;
4195 ansi_path = win32_realloc(ansi_path, newlen+1);
4198 ansi_path[len] = ';';
4199 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4204 ansi_path = win32_malloc(5+len+1);
4207 memcpy(ansi_path, "PATH=", 5);
4208 memcpy(ansi_path+5, ansi_dir, len+1);
4211 win32_free(ansi_dir);
4216 /* Update C RTL environ array. This will only have full effect if
4217 * perl_parse() is later called with `environ` as the `env` argument.
4218 * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4220 * We do have to ansify() the PATH before Perl has been fully
4221 * initialized because S_find_script() uses the PATH when perl
4222 * is being invoked with the -S option. This happens before %ENV
4223 * is initialized in S_init_postdump_symbols().
4225 * XXX Is this a bug? Should S_find_script() use the environment
4226 * XXX passed in the `env` arg to parse_perl()?
4229 /* Keep system environment in sync because S_init_postdump_symbols()
4230 * will not call mg_set() if it initializes %ENV from `environ`.
4232 SetEnvironmentVariableA("PATH", ansi_path+5);
4233 /* We are intentionally leaking the ansi_path string here because
4234 * the Borland runtime library puts it directly into the environ
4235 * array. The Microsoft runtime library seems to make a copy,
4236 * but will leak the copy should it be replaced again later.
4237 * Since this code is only called once during PERL_SYS_INIT this
4238 * shouldn't really matter.
4241 win32_free(wide_path);
4245 Perl_win32_init(int *argcp, char ***argvp)
4247 #ifdef SET_INVALID_PARAMETER_HANDLER
4248 _invalid_parameter_handler oldHandler, newHandler;
4249 newHandler = my_invalid_parameter_handler;
4250 oldHandler = _set_invalid_parameter_handler(newHandler);
4251 _CrtSetReportMode(_CRT_ASSERT, 0);
4253 /* Disable floating point errors, Perl will trap the ones we
4254 * care about. VC++ RTL defaults to switching these off
4255 * already, but the Borland RTL doesn't. Since we don't
4256 * want to be at the vendor's whim on the default, we set
4257 * it explicitly here.
4259 #if !defined(__GNUC__)
4260 _control87(MCW_EM, MCW_EM);
4264 /* When the manifest resource requests Common-Controls v6 then
4265 * user32.dll no longer registers all the Windows classes used for
4266 * standard controls but leaves some of them to be registered by
4267 * comctl32.dll. InitCommonControls() doesn't do anything but calling
4268 * it makes sure comctl32.dll gets loaded into the process and registers
4269 * the standard control classes. Without this even normal Windows APIs
4270 * like MessageBox() can fail under some versions of Windows XP.
4272 InitCommonControls();
4274 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4275 GetVersionEx(&g_osver);
4281 Perl_win32_term(void)
4291 win32_get_child_IO(child_IO_table* ptbl)
4293 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4294 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4295 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4299 win32_signal(int sig, Sighandler_t subcode)
4302 if (sig < SIG_SIZE) {
4303 int save_errno = errno;
4304 Sighandler_t result = signal(sig, subcode);
4305 if (result == SIG_ERR) {
4306 result = w32_sighandler[sig];
4309 w32_sighandler[sig] = subcode;
4318 /* The PerlMessageWindowClass's WindowProc */
4320 win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4322 return win32_process_message(hwnd, msg, wParam, lParam) ?
4323 0 : DefWindowProc(hwnd, msg, wParam, lParam);
4326 /* The real message handler. Can be called with
4327 * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4328 * that it processes */
4330 win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4332 /* BEWARE. The context retrieved using dTHX; is the context of the
4333 * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4334 * up to and including WM_CREATE. If it ever happens that you need the
4335 * 'child' context before this, then it needs to be passed into
4336 * win32_create_message_window(), and passed to the WM_NCCREATE handler
4337 * from the lparam of CreateWindow(). It could then be stored/retrieved
4338 * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4339 * the dTHX calls here. */
4340 /* XXX For now it is assumed that the overhead of the dTHX; for what
4341 * are relativley infrequent code-paths, is better than the added
4342 * complexity of getting the correct context passed into
4343 * win32_create_message_window() */
4348 case WM_USER_MESSAGE: {
4349 long child = find_pseudo_pid((int)wParam);
4352 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
4359 case WM_USER_KILL: {
4361 /* We use WM_USER_KILL to fake kill() with other signals */
4362 int sig = (int)wParam;
4363 if (do_raise(aTHX_ sig))
4364 sig_terminate(aTHX_ sig);
4371 /* alarm() is a one-shot but SetTimer() repeats so kill it */
4372 if (w32_timerid && w32_timerid==(UINT)wParam) {
4373 KillTimer(w32_message_hwnd, w32_timerid);
4376 /* Now fake a call to signal handler */
4377 if (do_raise(aTHX_ 14))
4378 sig_terminate(aTHX_ 14);
4390 /* Above or other stuff may have set a signal flag, and we may not have
4391 * been called from win32_async_check() (e.g. some other GUI's message
4392 * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
4393 * handler that die's, and the message loop that calls here is wrapped
4394 * in an eval, then you may well end up with orphaned windows - signals
4395 * are dispatched by win32_async_check() */
4401 win32_create_message_window_class(void)
4403 /* create the window class for "message only" windows */
4407 wc.lpfnWndProc = win32_message_window_proc;
4408 wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
4409 wc.lpszClassName = "PerlMessageWindowClass";
4411 /* second and subsequent calls will fail, but class
4412 * will already be registered */
4417 win32_create_message_window(void)
4419 win32_create_message_window_class();
4420 return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
4421 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
4424 #ifdef HAVE_INTERP_INTERN
4427 win32_csighandler(int sig)
4430 dTHXa(PERL_GET_SIG_CONTEXT);
4431 Perl_warn(aTHX_ "Got signal %d",sig);
4436 #if defined(__MINGW32__) && defined(__cplusplus)
4437 #define CAST_HWND__(x) (HWND__*)(x)
4439 #define CAST_HWND__(x) x
4443 Perl_sys_intern_init(pTHX)
4447 w32_perlshell_tokens = NULL;
4448 w32_perlshell_vec = (char**)NULL;
4449 w32_perlshell_items = 0;
4450 w32_fdpid = newAV();
4451 Newx(w32_children, 1, child_tab);
4452 w32_num_children = 0;
4453 # ifdef USE_ITHREADS
4455 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4456 w32_num_pseudo_children = 0;
4459 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4461 for (i=0; i < SIG_SIZE; i++) {
4462 w32_sighandler[i] = SIG_DFL;
4464 # ifdef MULTIPLICITY
4465 if (my_perl == PL_curinterp) {
4469 /* Force C runtime signal stuff to set its console handler */
4470 signal(SIGINT,win32_csighandler);
4471 signal(SIGBREAK,win32_csighandler);
4473 /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
4474 * flag. This has the side-effect of disabling Ctrl-C events in all
4475 * processes in this group.
4476 * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
4477 * with a NULL handler.
4479 SetConsoleCtrlHandler(NULL,FALSE);
4481 /* Push our handler on top */
4482 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4487 Perl_sys_intern_clear(pTHX)
4489 Safefree(w32_perlshell_tokens);
4490 Safefree(w32_perlshell_vec);
4491 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4492 Safefree(w32_children);
4494 KillTimer(w32_message_hwnd, w32_timerid);
4497 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4498 DestroyWindow(w32_message_hwnd);
4499 # ifdef MULTIPLICITY
4500 if (my_perl == PL_curinterp) {
4504 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4506 # ifdef USE_ITHREADS
4507 Safefree(w32_pseudo_children);
4511 # ifdef USE_ITHREADS
4514 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4516 PERL_ARGS_ASSERT_SYS_INTERN_DUP;
4518 dst->perlshell_tokens = NULL;
4519 dst->perlshell_vec = (char**)NULL;
4520 dst->perlshell_items = 0;
4521 dst->fdpid = newAV();
4522 Newxz(dst->children, 1, child_tab);
4524 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4526 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4527 dst->poll_count = 0;
4528 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4530 # endif /* USE_ITHREADS */
4531 #endif /* HAVE_INTERP_INTERN */