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 Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
1181 (w32_num_pseudo_children-child-1), char);
1182 w32_num_pseudo_children--;
1187 win32_wait_for_children(pTHX)
1189 if (w32_pseudo_children && w32_num_pseudo_children) {
1192 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1194 for (child = 0; child < w32_num_pseudo_children; ++child) {
1195 if (!w32_pseudo_child_sigterm[child])
1196 handles[count++] = w32_pseudo_child_handles[child];
1198 /* XXX should use MsgWaitForMultipleObjects() to continue
1199 * XXX processing messages while we wait.
1201 WaitForMultipleObjects(count, handles, TRUE, INFINITE);
1203 while (w32_num_pseudo_children)
1204 CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
1210 terminate_process(DWORD pid, HANDLE process_handle, int sig)
1214 /* "Does process exist?" use of kill */
1217 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1222 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1225 default: /* For now be backwards compatible with perl 5.6 */
1227 /* Note that we will only be able to kill processes owned by the
1228 * current process owner, even when we are running as an administrator.
1229 * To kill processes of other owners we would need to set the
1230 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1232 if (TerminateProcess(process_handle, sig))
1240 killpg(int pid, int sig)
1242 HANDLE process_handle;
1243 HANDLE snapshot_handle;
1246 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1247 if (process_handle == NULL)
1250 killed += terminate_process(pid, process_handle, sig);
1252 snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1253 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1254 PROCESSENTRY32 entry;
1256 entry.dwSize = sizeof(entry);
1257 if (Process32First(snapshot_handle, &entry)) {
1259 if (entry.th32ParentProcessID == (DWORD)pid)
1260 killed += killpg(entry.th32ProcessID, sig);
1261 entry.dwSize = sizeof(entry);
1263 while (Process32Next(snapshot_handle, &entry));
1265 CloseHandle(snapshot_handle);
1267 CloseHandle(process_handle);
1272 my_kill(int pid, int sig)
1275 HANDLE process_handle;
1278 return killpg(pid, -sig);
1280 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1281 /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1282 if (process_handle != NULL) {
1283 retval = terminate_process(pid, process_handle, sig);
1284 CloseHandle(process_handle);
1290 win32_kill(int pid, int sig)
1296 /* it is a pseudo-forked child */
1297 child = find_pseudo_pid(-pid);
1299 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1300 HANDLE hProcess = w32_pseudo_child_handles[child];
1303 /* "Does process exist?" use of kill */
1307 /* kill -9 style un-graceful exit */
1308 if (TerminateThread(hProcess, sig)) {
1309 /* Allow the scheduler to finish cleaning up the other thread.
1310 * Otherwise, if we ExitProcess() before another context switch
1311 * happens we will end up with a process exit code of "sig" instead
1312 * of our own exit status.
1313 * See also: https://rt.cpan.org/Ticket/Display.html?id=66016#txn-908976
1316 remove_dead_pseudo_process(child);
1323 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1324 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1325 /* Yield and wait for the other thread to send us its message_hwnd */
1327 win32_async_check(aTHX);
1328 hwnd = w32_pseudo_child_message_hwnds[child];
1331 if (hwnd != INVALID_HANDLE_VALUE) {
1332 /* We fake signals to pseudo-processes using Win32
1333 * message queue. In Win9X the pids are negative already. */
1334 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1335 PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1337 /* Don't wait for child process to terminate after we send a SIGTERM
1338 * because the child may be blocked in a system call and never receive
1341 if (sig == SIGTERM) {
1343 w32_pseudo_child_sigterm[child] = 1;
1345 /* It might be us ... */
1358 child = find_pid(pid);
1360 if (my_kill(pid, sig)) {
1362 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1363 exitcode != STILL_ACTIVE)
1365 remove_dead_process(child);
1371 if (my_kill(pid, sig))
1380 win32_stat(const char *path, Stat_t *sbuf)
1383 char buffer[MAX_PATH+1];
1384 int l = strlen(path);
1387 BOOL expect_dir = FALSE;
1389 GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
1390 GV_NOTQUAL, SVt_PV);
1391 BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
1394 switch(path[l - 1]) {
1395 /* FindFirstFile() and stat() are buggy with a trailing
1396 * slashes, except for the root directory of a drive */
1399 if (l > sizeof(buffer)) {
1400 errno = ENAMETOOLONG;
1404 strncpy(buffer, path, l);
1405 /* remove additional trailing slashes */
1406 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1408 /* add back slash if we otherwise end up with just a drive letter */
1409 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1416 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1418 if (l == 2 && isALPHA(path[0])) {
1419 buffer[0] = path[0];
1430 path = PerlDir_mapA(path);
1434 /* We must open & close the file once; otherwise file attribute changes */
1435 /* might not yet have propagated to "other" hard links of the same file. */
1436 /* This also gives us an opportunity to determine the number of links. */
1437 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1438 if (handle != INVALID_HANDLE_VALUE) {
1439 BY_HANDLE_FILE_INFORMATION bhi;
1440 if (GetFileInformationByHandle(handle, &bhi))
1441 nlink = bhi.nNumberOfLinks;
1442 CloseHandle(handle);
1446 /* path will be mapped correctly above */
1447 #if defined(WIN64) || defined(USE_LARGE_FILES)
1448 res = _stati64(path, sbuf);
1450 res = stat(path, sbuf);
1452 sbuf->st_nlink = nlink;
1455 /* CRT is buggy on sharenames, so make sure it really isn't.
1456 * XXX using GetFileAttributesEx() will enable us to set
1457 * sbuf->st_*time (but note that's not available on the
1458 * Windows of 1995) */
1459 DWORD r = GetFileAttributesA(path);
1460 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1461 /* sbuf may still contain old garbage since stat() failed */
1462 Zero(sbuf, 1, Stat_t);
1463 sbuf->st_mode = S_IFDIR | S_IREAD;
1465 if (!(r & FILE_ATTRIBUTE_READONLY))
1466 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1471 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1472 && (path[2] == '\\' || path[2] == '/'))
1474 /* The drive can be inaccessible, some _stat()s are buggy */
1475 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1480 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1484 if (S_ISDIR(sbuf->st_mode)) {
1485 /* Ensure the "write" bit is switched off in the mode for
1486 * directories with the read-only attribute set. Borland (at least)
1487 * switches it on for directories, which is technically correct
1488 * (directories are indeed always writable unless denied by DACLs),
1489 * but we want stat() and -w to reflect the state of the read-only
1490 * attribute for symmetry with chmod(). */
1491 DWORD r = GetFileAttributesA(path);
1492 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
1493 sbuf->st_mode &= ~S_IWRITE;
1497 if (S_ISDIR(sbuf->st_mode)) {
1498 sbuf->st_mode |= S_IEXEC;
1500 else if (S_ISREG(sbuf->st_mode)) {
1502 if (l >= 4 && path[l-4] == '.') {
1503 const char *e = path + l - 3;
1504 if (strnicmp(e,"exe",3)
1505 && strnicmp(e,"bat",3)
1506 && strnicmp(e,"com",3)
1507 && strnicmp(e,"cmd",3))
1508 sbuf->st_mode &= ~S_IEXEC;
1510 sbuf->st_mode |= S_IEXEC;
1513 sbuf->st_mode &= ~S_IEXEC;
1514 /* Propagate permissions to _group_ and _others_ */
1515 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1516 sbuf->st_mode |= (perms>>3) | (perms>>6);
1523 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1524 #define SKIP_SLASHES(s) \
1526 while (*(s) && isSLASH(*(s))) \
1529 #define COPY_NONSLASHES(d,s) \
1531 while (*(s) && !isSLASH(*(s))) \
1535 /* Find the longname of a given path. path is destructively modified.
1536 * It should have space for at least MAX_PATH characters. */
1538 win32_longpath(char *path)
1540 WIN32_FIND_DATA fdata;
1542 char tmpbuf[MAX_PATH+1];
1543 char *tmpstart = tmpbuf;
1550 if (isALPHA(path[0]) && path[1] == ':') {
1552 *tmpstart++ = path[0];
1556 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1558 *tmpstart++ = path[0];
1559 *tmpstart++ = path[1];
1560 SKIP_SLASHES(start);
1561 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1563 *tmpstart++ = *start++;
1564 SKIP_SLASHES(start);
1565 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1570 /* copy initial slash, if any */
1571 if (isSLASH(*start)) {
1572 *tmpstart++ = *start++;
1574 SKIP_SLASHES(start);
1577 /* FindFirstFile() expands "." and "..", so we need to pass
1578 * those through unmolested */
1580 && (!start[1] || isSLASH(start[1])
1581 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1583 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1588 /* if this is the end, bust outta here */
1592 /* now we're at a non-slash; walk up to next slash */
1593 while (*start && !isSLASH(*start))
1596 /* stop and find full name of component */
1599 fhand = FindFirstFile(path,&fdata);
1601 if (fhand != INVALID_HANDLE_VALUE) {
1602 STRLEN len = strlen(fdata.cFileName);
1603 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1604 strcpy(tmpstart, fdata.cFileName);
1615 /* failed a step, just return without side effects */
1616 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1621 strcpy(path,tmpbuf);
1630 /* Can't use PerlIO to write as it allocates memory */
1631 PerlLIO_write(PerlIO_fileno(Perl_error_log),
1632 PL_no_mem, strlen(PL_no_mem));
1638 /* The win32_ansipath() function takes a Unicode filename and converts it
1639 * into the current Windows codepage. If some characters cannot be mapped,
1640 * then it will convert the short name instead.
1642 * The buffer to the ansi pathname must be freed with win32_free() when it
1643 * it no longer needed.
1645 * The argument to win32_ansipath() must exist before this function is
1646 * called; otherwise there is no way to determine the short path name.
1648 * Ideas for future refinement:
1649 * - Only convert those segments of the path that are not in the current
1650 * codepage, but leave the other segments in their long form.
1651 * - If the resulting name is longer than MAX_PATH, start converting
1652 * additional path segments into short names until the full name
1653 * is shorter than MAX_PATH. Shorten the filename part last!
1656 win32_ansipath(const WCHAR *widename)
1659 BOOL use_default = FALSE;
1660 size_t widelen = wcslen(widename)+1;
1661 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1662 NULL, 0, NULL, NULL);
1663 name = win32_malloc(len);
1667 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1668 name, len, NULL, &use_default);
1670 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
1672 WCHAR *shortname = win32_malloc(shortlen*sizeof(WCHAR));
1675 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1677 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1678 NULL, 0, NULL, NULL);
1679 name = win32_realloc(name, len);
1682 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1683 name, len, NULL, NULL);
1684 win32_free(shortname);
1691 win32_getenv(const char *name)
1698 needlen = GetEnvironmentVariableA(name,NULL,0);
1700 curitem = sv_2mortal(newSVpvn("", 0));
1702 SvGROW(curitem, needlen+1);
1703 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1705 } while (needlen >= SvLEN(curitem));
1706 SvCUR_set(curitem, needlen);
1709 last_err = GetLastError();
1710 if (last_err == ERROR_NOT_ENOUGH_MEMORY) {
1711 /* It appears the variable is in the env, but the Win32 API
1712 doesn't have a canned way of getting it. So we fall back to
1713 grabbing the whole env and pulling this value out if possible */
1714 char *envv = GetEnvironmentStrings();
1718 char *end = strchr(cur,'=');
1719 if (end && end != cur) {
1721 if (!strcmp(cur,name)) {
1722 curitem = sv_2mortal(newSVpv(end+1,0));
1727 cur = end + strlen(end+1)+2;
1729 else if ((len = strlen(cur)))
1732 FreeEnvironmentStrings(envv);
1735 /* last ditch: allow any environment variables that begin with 'PERL'
1736 to be obtained from the registry, if found there */
1737 if (strncmp(name, "PERL", 4) == 0)
1738 (void)get_regstr(name, &curitem);
1741 if (curitem && SvCUR(curitem))
1742 return SvPVX(curitem);
1748 win32_putenv(const char *name)
1756 Newx(curitem,strlen(name)+1,char);
1757 strcpy(curitem, name);
1758 val = strchr(curitem, '=');
1760 /* The sane way to deal with the environment.
1761 * Has these advantages over putenv() & co.:
1762 * * enables us to store a truly empty value in the
1763 * environment (like in UNIX).
1764 * * we don't have to deal with RTL globals, bugs and leaks
1765 * (specifically, see http://support.microsoft.com/kb/235601).
1767 * Why you may want to use the RTL environment handling
1768 * (previously enabled by USE_WIN32_RTL_ENV):
1769 * * environ[] and RTL functions will not reflect changes,
1770 * which might be an issue if extensions want to access
1771 * the env. via RTL. This cuts both ways, since RTL will
1772 * not see changes made by extensions that call the Win32
1773 * functions directly, either.
1777 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1786 filetime_to_clock(PFILETIME ft)
1788 __int64 qw = ft->dwHighDateTime;
1790 qw |= ft->dwLowDateTime;
1791 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1796 win32_times(struct tms *timebuf)
1801 clock_t process_time_so_far = clock();
1802 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1804 timebuf->tms_utime = filetime_to_clock(&user);
1805 timebuf->tms_stime = filetime_to_clock(&kernel);
1806 timebuf->tms_cutime = 0;
1807 timebuf->tms_cstime = 0;
1809 /* That failed - e.g. Win95 fallback to clock() */
1810 timebuf->tms_utime = process_time_so_far;
1811 timebuf->tms_stime = 0;
1812 timebuf->tms_cutime = 0;
1813 timebuf->tms_cstime = 0;
1815 return process_time_so_far;
1818 /* fix utime() so it works on directories in NT */
1820 filetime_from_time(PFILETIME pFileTime, time_t Time)
1822 struct tm *pTM = localtime(&Time);
1823 SYSTEMTIME SystemTime;
1829 SystemTime.wYear = pTM->tm_year + 1900;
1830 SystemTime.wMonth = pTM->tm_mon + 1;
1831 SystemTime.wDay = pTM->tm_mday;
1832 SystemTime.wHour = pTM->tm_hour;
1833 SystemTime.wMinute = pTM->tm_min;
1834 SystemTime.wSecond = pTM->tm_sec;
1835 SystemTime.wMilliseconds = 0;
1837 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1838 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1842 win32_unlink(const char *filename)
1848 filename = PerlDir_mapA(filename);
1849 attrs = GetFileAttributesA(filename);
1850 if (attrs == 0xFFFFFFFF) {
1854 if (attrs & FILE_ATTRIBUTE_READONLY) {
1855 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1856 ret = unlink(filename);
1858 (void)SetFileAttributesA(filename, attrs);
1861 ret = unlink(filename);
1866 win32_utime(const char *filename, struct utimbuf *times)
1873 struct utimbuf TimeBuffer;
1876 filename = PerlDir_mapA(filename);
1877 rc = utime(filename, times);
1879 /* EACCES: path specifies directory or readonly file */
1880 if (rc == 0 || errno != EACCES)
1883 if (times == NULL) {
1884 times = &TimeBuffer;
1885 time(×->actime);
1886 times->modtime = times->actime;
1889 /* This will (and should) still fail on readonly files */
1890 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1891 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1892 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1893 if (handle == INVALID_HANDLE_VALUE)
1896 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1897 filetime_from_time(&ftAccess, times->actime) &&
1898 filetime_from_time(&ftWrite, times->modtime) &&
1899 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1904 CloseHandle(handle);
1909 unsigned __int64 ft_i64;
1914 #define Const64(x) x##LL
1916 #define Const64(x) x##i64
1918 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1919 #define EPOCH_BIAS Const64(116444736000000000)
1921 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1922 * and appears to be unsupported even by glibc) */
1924 win32_gettimeofday(struct timeval *tp, void *not_used)
1928 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1929 GetSystemTimeAsFileTime(&ft.ft_val);
1931 /* seconds since epoch */
1932 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1934 /* microseconds remaining */
1935 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1941 win32_uname(struct utsname *name)
1943 struct hostent *hep;
1944 STRLEN nodemax = sizeof(name->nodename)-1;
1947 switch (g_osver.dwPlatformId) {
1948 case VER_PLATFORM_WIN32_WINDOWS:
1949 strcpy(name->sysname, "Windows");
1951 case VER_PLATFORM_WIN32_NT:
1952 strcpy(name->sysname, "Windows NT");
1954 case VER_PLATFORM_WIN32s:
1955 strcpy(name->sysname, "Win32s");
1958 strcpy(name->sysname, "Win32 Unknown");
1963 sprintf(name->release, "%d.%d",
1964 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1967 sprintf(name->version, "Build %d",
1968 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1969 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1970 if (g_osver.szCSDVersion[0]) {
1971 char *buf = name->version + strlen(name->version);
1972 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1976 hep = win32_gethostbyname("localhost");
1978 STRLEN len = strlen(hep->h_name);
1979 if (len <= nodemax) {
1980 strcpy(name->nodename, hep->h_name);
1983 strncpy(name->nodename, hep->h_name, nodemax);
1984 name->nodename[nodemax] = '\0';
1989 if (!GetComputerName(name->nodename, &sz))
1990 *name->nodename = '\0';
1993 /* machine (architecture) */
1998 GetSystemInfo(&info);
2000 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
2001 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
2002 procarch = info.u.s.wProcessorArchitecture;
2004 procarch = info.wProcessorArchitecture;
2007 case PROCESSOR_ARCHITECTURE_INTEL:
2008 arch = "x86"; break;
2009 case PROCESSOR_ARCHITECTURE_IA64:
2010 arch = "ia64"; break;
2011 case PROCESSOR_ARCHITECTURE_AMD64:
2012 arch = "amd64"; break;
2013 case PROCESSOR_ARCHITECTURE_UNKNOWN:
2014 arch = "unknown"; break;
2016 sprintf(name->machine, "unknown(0x%x)", procarch);
2017 arch = name->machine;
2020 if (name->machine != arch)
2021 strcpy(name->machine, arch);
2026 /* Timing related stuff */
2029 do_raise(pTHX_ int sig)
2031 if (sig < SIG_SIZE) {
2032 Sighandler_t handler = w32_sighandler[sig];
2033 if (handler == SIG_IGN) {
2036 else if (handler != SIG_DFL) {
2041 /* Choose correct default behaviour */
2057 /* Tell caller to exit thread/process as approriate */
2062 sig_terminate(pTHX_ int sig)
2064 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2065 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2072 win32_async_check(pTHX)
2075 HWND hwnd = w32_message_hwnd;
2077 /* Reset w32_poll_count before doing anything else, incase we dispatch
2078 * messages that end up calling back into perl */
2081 if (hwnd != INVALID_HANDLE_VALUE) {
2082 /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2083 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2088 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2089 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2091 /* re-post a WM_QUIT message (we'll mark it as read later) */
2092 if(msg.message == WM_QUIT) {
2093 PostQuitMessage((int)msg.wParam);
2097 if(!CallMsgFilter(&msg, MSGF_USER))
2099 TranslateMessage(&msg);
2100 DispatchMessage(&msg);
2105 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2106 * This is necessary when we are being called by win32_msgwait() to
2107 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2108 * message over and over. An example how this can happen is when
2109 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2110 * is generating messages before the process terminated.
2112 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
2114 /* Above or other stuff may have set a signal flag */
2121 /* This function will not return until the timeout has elapsed, or until
2122 * one of the handles is ready. */
2124 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2126 /* We may need several goes at this - so compute when we stop */
2128 if (timeout != INFINITE) {
2129 ticks = GetTickCount();
2133 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
2136 if (result == WAIT_TIMEOUT) {
2137 /* Ran out of time - explicit return of zero to avoid -ve if we
2138 have scheduling issues
2142 if (timeout != INFINITE) {
2143 ticks = GetTickCount();
2145 if (result == WAIT_OBJECT_0 + count) {
2146 /* Message has arrived - check it */
2147 (void)win32_async_check(aTHX);
2150 /* Not timeout or message - one of handles is ready */
2154 /* compute time left to wait */
2155 ticks = timeout - ticks;
2156 /* If we are past the end say zero */
2157 return (ticks > 0) ? ticks : 0;
2161 win32_internal_wait(int *status, DWORD timeout)
2163 /* XXX this wait emulation only knows about processes
2164 * spawned via win32_spawnvp(P_NOWAIT, ...).
2168 DWORD exitcode, waitcode;
2171 if (w32_num_pseudo_children) {
2172 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2173 timeout, &waitcode);
2174 /* Time out here if there are no other children to wait for. */
2175 if (waitcode == WAIT_TIMEOUT) {
2176 if (!w32_num_children) {
2180 else if (waitcode != WAIT_FAILED) {
2181 if (waitcode >= WAIT_ABANDONED_0
2182 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2183 i = waitcode - WAIT_ABANDONED_0;
2185 i = waitcode - WAIT_OBJECT_0;
2186 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2187 *status = (int)((exitcode & 0xff) << 8);
2188 retval = (int)w32_pseudo_child_pids[i];
2189 remove_dead_pseudo_process(i);
2196 if (!w32_num_children) {
2201 /* if a child exists, wait for it to die */
2202 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
2203 if (waitcode == WAIT_TIMEOUT) {
2206 if (waitcode != WAIT_FAILED) {
2207 if (waitcode >= WAIT_ABANDONED_0
2208 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2209 i = waitcode - WAIT_ABANDONED_0;
2211 i = waitcode - WAIT_OBJECT_0;
2212 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2213 *status = (int)((exitcode & 0xff) << 8);
2214 retval = (int)w32_child_pids[i];
2215 remove_dead_process(i);
2220 errno = GetLastError();
2225 win32_waitpid(int pid, int *status, int flags)
2228 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2231 if (pid == -1) /* XXX threadid == 1 ? */
2232 return win32_internal_wait(status, timeout);
2235 child = find_pseudo_pid(-pid);
2237 HANDLE hThread = w32_pseudo_child_handles[child];
2239 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2240 if (waitcode == WAIT_TIMEOUT) {
2243 else if (waitcode == WAIT_OBJECT_0) {
2244 if (GetExitCodeThread(hThread, &waitcode)) {
2245 *status = (int)((waitcode & 0xff) << 8);
2246 retval = (int)w32_pseudo_child_pids[child];
2247 remove_dead_pseudo_process(child);
2259 child = find_pid(pid);
2261 hProcess = w32_child_handles[child];
2262 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2263 if (waitcode == WAIT_TIMEOUT) {
2266 else if (waitcode == WAIT_OBJECT_0) {
2267 if (GetExitCodeProcess(hProcess, &waitcode)) {
2268 *status = (int)((waitcode & 0xff) << 8);
2269 retval = (int)w32_child_pids[child];
2270 remove_dead_process(child);
2278 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
2280 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2281 if (waitcode == WAIT_TIMEOUT) {
2282 CloseHandle(hProcess);
2285 else if (waitcode == WAIT_OBJECT_0) {
2286 if (GetExitCodeProcess(hProcess, &waitcode)) {
2287 *status = (int)((waitcode & 0xff) << 8);
2288 CloseHandle(hProcess);
2292 CloseHandle(hProcess);
2298 return retval >= 0 ? pid : retval;
2302 win32_wait(int *status)
2304 return win32_internal_wait(status, INFINITE);
2307 DllExport unsigned int
2308 win32_sleep(unsigned int t)
2311 /* Win32 times are in ms so *1000 in and /1000 out */
2312 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2315 DllExport unsigned int
2316 win32_alarm(unsigned int sec)
2319 * the 'obvious' implentation is SetTimer() with a callback
2320 * which does whatever receiving SIGALRM would do
2321 * we cannot use SIGALRM even via raise() as it is not
2322 * one of the supported codes in <signal.h>
2326 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2327 w32_message_hwnd = win32_create_message_window();
2330 if (w32_message_hwnd == NULL)
2331 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2334 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2339 KillTimer(w32_message_hwnd, w32_timerid);
2346 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2349 win32_crypt(const char *txt, const char *salt)
2352 return des_fcrypt(txt, salt, w32_crypt_buffer);
2355 /* simulate flock by locking a range on the file */
2357 #define LK_LEN 0xffff0000
2360 win32_flock(int fd, int oper)
2366 fh = (HANDLE)_get_osfhandle(fd);
2367 if (fh == (HANDLE)-1) /* _get_osfhandle() already sets errno to EBADF */
2370 memset(&o, 0, sizeof(o));
2373 case LOCK_SH: /* shared lock */
2374 if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2377 case LOCK_EX: /* exclusive lock */
2378 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2381 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2382 if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2385 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2386 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2390 case LOCK_UN: /* unlock lock */
2391 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2394 default: /* unknown */
2399 if (GetLastError() == ERROR_LOCK_VIOLATION)
2400 errno = WSAEWOULDBLOCK;
2410 * redirected io subsystem for all XS modules
2423 return (&(_environ));
2426 /* the rest are the remapped stdio routines */
2446 win32_ferror(FILE *fp)
2448 return (ferror(fp));
2453 win32_feof(FILE *fp)
2459 * Since the errors returned by the socket error function
2460 * WSAGetLastError() are not known by the library routine strerror
2461 * we have to roll our own.
2465 win32_strerror(int e)
2467 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2468 extern int sys_nerr;
2471 if (e < 0 || e > sys_nerr) {
2476 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2477 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2478 w32_strerror_buffer, sizeof(w32_strerror_buffer),
2481 strcpy(w32_strerror_buffer, "Unknown Error");
2483 return w32_strerror_buffer;
2487 #define strerror win32_strerror
2491 win32_str_os_error(void *sv, DWORD dwErr)
2495 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2496 |FORMAT_MESSAGE_IGNORE_INSERTS
2497 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2498 dwErr, 0, (char *)&sMsg, 1, NULL);
2499 /* strip trailing whitespace and period */
2502 --dwLen; /* dwLen doesn't include trailing null */
2503 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2504 if ('.' != sMsg[dwLen])
2509 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2511 dwLen = sprintf(sMsg,
2512 "Unknown error #0x%lX (lookup 0x%lX)",
2513 dwErr, GetLastError());
2517 sv_setpvn((SV*)sv, sMsg, dwLen);
2523 win32_fprintf(FILE *fp, const char *format, ...)
2526 va_start(marker, format); /* Initialize variable arguments. */
2528 return (vfprintf(fp, format, marker));
2532 win32_printf(const char *format, ...)
2535 va_start(marker, format); /* Initialize variable arguments. */
2537 return (vprintf(format, marker));
2541 win32_vfprintf(FILE *fp, const char *format, va_list args)
2543 return (vfprintf(fp, format, args));
2547 win32_vprintf(const char *format, va_list args)
2549 return (vprintf(format, args));
2553 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2555 return fread(buf, size, count, fp);
2559 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2561 return fwrite(buf, size, count, fp);
2564 #define MODE_SIZE 10
2567 win32_fopen(const char *filename, const char *mode)
2575 if (stricmp(filename, "/dev/null")==0)
2578 f = fopen(PerlDir_mapA(filename), mode);
2579 /* avoid buffering headaches for child processes */
2580 if (f && *mode == 'a')
2581 win32_fseek(f, 0, SEEK_END);
2585 #ifndef USE_SOCKETS_AS_HANDLES
2587 #define fdopen my_fdopen
2591 win32_fdopen(int handle, const char *mode)
2595 f = fdopen(handle, (char *) mode);
2596 /* avoid buffering headaches for child processes */
2597 if (f && *mode == 'a')
2598 win32_fseek(f, 0, SEEK_END);
2603 win32_freopen(const char *path, const char *mode, FILE *stream)
2606 if (stricmp(path, "/dev/null")==0)
2609 return freopen(PerlDir_mapA(path), mode, stream);
2613 win32_fclose(FILE *pf)
2615 return my_fclose(pf); /* defined in win32sck.c */
2619 win32_fputs(const char *s,FILE *pf)
2621 return fputs(s, pf);
2625 win32_fputc(int c,FILE *pf)
2631 win32_ungetc(int c,FILE *pf)
2633 return ungetc(c,pf);
2637 win32_getc(FILE *pf)
2643 win32_fileno(FILE *pf)
2649 win32_clearerr(FILE *pf)
2656 win32_fflush(FILE *pf)
2662 win32_ftell(FILE *pf)
2664 #if defined(WIN64) || defined(USE_LARGE_FILES)
2665 #if defined(__BORLANDC__) /* buk */
2666 return win32_tell( fileno( pf ) );
2669 if (fgetpos(pf, &pos))
2679 win32_fseek(FILE *pf, Off_t offset,int origin)
2681 #if defined(WIN64) || defined(USE_LARGE_FILES)
2682 #if defined(__BORLANDC__) /* buk */
2692 if (fgetpos(pf, &pos))
2697 fseek(pf, 0, SEEK_END);
2698 pos = _telli64(fileno(pf));
2707 return fsetpos(pf, &offset);
2710 return fseek(pf, (long)offset, origin);
2715 win32_fgetpos(FILE *pf,fpos_t *p)
2717 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2718 if( win32_tell(fileno(pf)) == -1L ) {
2724 return fgetpos(pf, p);
2729 win32_fsetpos(FILE *pf,const fpos_t *p)
2731 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2732 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2734 return fsetpos(pf, p);
2739 win32_rewind(FILE *pf)
2749 char prefix[MAX_PATH+1];
2750 char filename[MAX_PATH+1];
2751 DWORD len = GetTempPath(MAX_PATH, prefix);
2752 if (len && len < MAX_PATH) {
2753 if (GetTempFileName(prefix, "plx", 0, filename)) {
2754 HANDLE fh = CreateFile(filename,
2755 DELETE | GENERIC_READ | GENERIC_WRITE,
2759 FILE_ATTRIBUTE_NORMAL
2760 | FILE_FLAG_DELETE_ON_CLOSE,
2762 if (fh != INVALID_HANDLE_VALUE) {
2763 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2765 #if defined(__BORLANDC__)
2766 setmode(fd,O_BINARY);
2768 DEBUG_p(PerlIO_printf(Perl_debug_log,
2769 "Created tmpfile=%s\n",filename));
2781 int fd = win32_tmpfd();
2783 return win32_fdopen(fd, "w+b");
2795 win32_fstat(int fd, Stat_t *sbufptr)
2798 /* A file designated by filehandle is not shown as accessible
2799 * for write operations, probably because it is opened for reading.
2802 BY_HANDLE_FILE_INFORMATION bhfi;
2803 # if defined(WIN64) || defined(USE_LARGE_FILES)
2804 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2806 int rc = fstat(fd,&tmp);
2808 sbufptr->st_dev = tmp.st_dev;
2809 sbufptr->st_ino = tmp.st_ino;
2810 sbufptr->st_mode = tmp.st_mode;
2811 sbufptr->st_nlink = tmp.st_nlink;
2812 sbufptr->st_uid = tmp.st_uid;
2813 sbufptr->st_gid = tmp.st_gid;
2814 sbufptr->st_rdev = tmp.st_rdev;
2815 sbufptr->st_size = tmp.st_size;
2816 sbufptr->st_atime = tmp.st_atime;
2817 sbufptr->st_mtime = tmp.st_mtime;
2818 sbufptr->st_ctime = tmp.st_ctime;
2820 int rc = fstat(fd,sbufptr);
2823 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2824 # if defined(WIN64) || defined(USE_LARGE_FILES)
2825 sbufptr->st_size = ((__int64)bhfi.nFileSizeHigh << 32) | bhfi.nFileSizeLow ;
2827 sbufptr->st_mode &= 0xFE00;
2828 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2829 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2831 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2832 + ((S_IREAD|S_IWRITE) >> 6));
2836 # if defined(WIN64) || defined(USE_LARGE_FILES)
2837 return _fstati64(fd, sbufptr);
2839 return fstat(fd, sbufptr);
2845 win32_pipe(int *pfd, unsigned int size, int mode)
2847 return _pipe(pfd, size, mode);
2851 win32_popenlist(const char *mode, IV narg, SV **args)
2854 Perl_croak(aTHX_ "List form of pipe open not implemented");
2859 * a popen() clone that respects PERL5SHELL
2861 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2865 win32_popen(const char *command, const char *mode)
2867 #ifdef USE_RTL_POPEN
2868 return _popen(command, mode);
2880 /* establish which ends read and write */
2881 if (strchr(mode,'w')) {
2882 stdfd = 0; /* stdin */
2885 nhandle = STD_INPUT_HANDLE;
2887 else if (strchr(mode,'r')) {
2888 stdfd = 1; /* stdout */
2891 nhandle = STD_OUTPUT_HANDLE;
2896 /* set the correct mode */
2897 if (strchr(mode,'b'))
2899 else if (strchr(mode,'t'))
2902 ourmode = _fmode & (O_TEXT | O_BINARY);
2904 /* the child doesn't inherit handles */
2905 ourmode |= O_NOINHERIT;
2907 if (win32_pipe(p, 512, ourmode) == -1)
2910 /* save the old std handle (this needs to happen before the
2911 * dup2(), since that might call SetStdHandle() too) */
2914 old_h = GetStdHandle(nhandle);
2916 /* save current stdfd */
2917 if ((oldfd = win32_dup(stdfd)) == -1)
2920 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2921 /* stdfd will be inherited by the child */
2922 if (win32_dup2(p[child], stdfd) == -1)
2925 /* close the child end in parent */
2926 win32_close(p[child]);
2928 /* set the new std handle (in case dup2() above didn't) */
2929 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2931 /* start the child */
2934 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2937 /* revert stdfd to whatever it was before */
2938 if (win32_dup2(oldfd, stdfd) == -1)
2941 /* close saved handle */
2944 /* restore the old std handle (this needs to happen after the
2945 * dup2(), since that might call SetStdHandle() too */
2947 SetStdHandle(nhandle, old_h);
2952 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2954 /* set process id so that it can be returned by perl's open() */
2955 PL_forkprocess = childpid;
2958 /* we have an fd, return a file stream */
2959 return (PerlIO_fdopen(p[parent], (char *)mode));
2962 /* we don't need to check for errors here */
2966 win32_dup2(oldfd, stdfd);
2970 SetStdHandle(nhandle, old_h);
2976 #endif /* USE_RTL_POPEN */
2984 win32_pclose(PerlIO *pf)
2986 #ifdef USE_RTL_POPEN
2990 int childpid, status;
2993 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2996 childpid = SvIVX(sv);
3012 if (win32_waitpid(childpid, &status, 0) == -1)
3017 #endif /* USE_RTL_POPEN */
3021 win32_link(const char *oldname, const char *newname)
3024 WCHAR wOldName[MAX_PATH+1];
3025 WCHAR wNewName[MAX_PATH+1];
3027 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3028 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
3029 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
3030 CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
3034 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
3039 win32_rename(const char *oname, const char *newname)
3041 char szOldName[MAX_PATH+1];
3043 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3046 if (stricmp(newname, oname))
3047 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3048 strcpy(szOldName, PerlDir_mapA(oname));
3050 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3052 DWORD err = GetLastError();
3054 case ERROR_BAD_NET_NAME:
3055 case ERROR_BAD_NETPATH:
3056 case ERROR_BAD_PATHNAME:
3057 case ERROR_FILE_NOT_FOUND:
3058 case ERROR_FILENAME_EXCED_RANGE:
3059 case ERROR_INVALID_DRIVE:
3060 case ERROR_NO_MORE_FILES:
3061 case ERROR_PATH_NOT_FOUND:
3074 win32_setmode(int fd, int mode)
3076 return setmode(fd, mode);
3080 win32_chsize(int fd, Off_t size)
3082 #if defined(WIN64) || defined(USE_LARGE_FILES)
3084 Off_t cur, end, extend;
3086 cur = win32_tell(fd);
3089 end = win32_lseek(fd, 0, SEEK_END);
3092 extend = size - end;
3096 else if (extend > 0) {
3097 /* must grow the file, padding with nulls */
3099 int oldmode = win32_setmode(fd, O_BINARY);
3101 memset(b, '\0', sizeof(b));
3103 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3104 count = win32_write(fd, b, count);
3105 if ((int)count < 0) {
3109 } while ((extend -= count) > 0);
3110 win32_setmode(fd, oldmode);
3113 /* shrink the file */
3114 win32_lseek(fd, size, SEEK_SET);
3115 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3121 win32_lseek(fd, cur, SEEK_SET);
3124 return chsize(fd, (long)size);
3129 win32_lseek(int fd, Off_t offset, int origin)
3131 #if defined(WIN64) || defined(USE_LARGE_FILES)
3132 #if defined(__BORLANDC__) /* buk */
3134 pos.QuadPart = offset;
3135 pos.LowPart = SetFilePointer(
3136 (HANDLE)_get_osfhandle(fd),
3141 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3145 return pos.QuadPart;
3147 return _lseeki64(fd, offset, origin);
3150 return lseek(fd, (long)offset, origin);
3157 #if defined(WIN64) || defined(USE_LARGE_FILES)
3158 #if defined(__BORLANDC__) /* buk */
3161 pos.LowPart = SetFilePointer(
3162 (HANDLE)_get_osfhandle(fd),
3167 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3171 return pos.QuadPart;
3172 /* return tell(fd); */
3174 return _telli64(fd);
3182 win32_open(const char *path, int flag, ...)
3189 pmode = va_arg(ap, int);
3192 if (stricmp(path, "/dev/null")==0)
3195 return open(PerlDir_mapA(path), flag, pmode);
3198 /* close() that understands socket */
3199 extern int my_close(int); /* in win32sck.c */
3204 return my_close(fd);
3214 win32_isatty(int fd)
3216 /* The Microsoft isatty() function returns true for *all*
3217 * character mode devices, including "nul". Our implementation
3218 * should only return true if the handle has a console buffer.
3221 HANDLE fh = (HANDLE)_get_osfhandle(fd);
3222 if (fh == (HANDLE)-1) {
3223 /* errno is already set to EBADF */
3227 if (GetConsoleMode(fh, &mode))
3241 win32_dup2(int fd1,int fd2)
3243 return dup2(fd1,fd2);
3247 win32_read(int fd, void *buf, unsigned int cnt)
3249 return read(fd, buf, cnt);
3253 win32_write(int fd, const void *buf, unsigned int cnt)
3255 return write(fd, buf, cnt);
3259 win32_mkdir(const char *dir, int mode)
3262 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3266 win32_rmdir(const char *dir)
3269 return rmdir(PerlDir_mapA(dir));
3273 win32_chdir(const char *dir)
3284 win32_access(const char *path, int mode)
3287 return access(PerlDir_mapA(path), mode);
3291 win32_chmod(const char *path, int mode)
3294 return chmod(PerlDir_mapA(path), mode);
3299 create_command_line(char *cname, STRLEN clen, const char * const *args)
3306 bool bat_file = FALSE;
3307 bool cmd_shell = FALSE;
3308 bool dumb_shell = FALSE;
3309 bool extra_quotes = FALSE;
3310 bool quote_next = FALSE;
3313 cname = (char*)args[0];
3315 /* The NT cmd.exe shell has the following peculiarity that needs to be
3316 * worked around. It strips a leading and trailing dquote when any
3317 * of the following is true:
3318 * 1. the /S switch was used
3319 * 2. there are more than two dquotes
3320 * 3. there is a special character from this set: &<>()@^|
3321 * 4. no whitespace characters within the two dquotes
3322 * 5. string between two dquotes isn't an executable file
3323 * To work around this, we always add a leading and trailing dquote
3324 * to the string, if the first argument is either "cmd.exe" or "cmd",
3325 * and there were at least two or more arguments passed to cmd.exe
3326 * (not including switches).
3327 * XXX the above rules (from "cmd /?") don't seem to be applied
3328 * always, making for the convolutions below :-(
3332 clen = strlen(cname);
3335 && (stricmp(&cname[clen-4], ".bat") == 0
3336 || (stricmp(&cname[clen-4], ".cmd") == 0)))
3342 char *exe = strrchr(cname, '/');
3343 char *exe2 = strrchr(cname, '\\');
3350 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3354 else if (stricmp(exe, "command.com") == 0
3355 || stricmp(exe, "command") == 0)
3362 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3363 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3364 STRLEN curlen = strlen(arg);
3365 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3366 len += 2; /* assume quoting needed (worst case) */
3368 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3370 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3373 Newx(cmd, len, char);
3378 extra_quotes = TRUE;
3381 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3383 STRLEN curlen = strlen(arg);
3385 /* we want to protect empty arguments and ones with spaces with
3386 * dquotes, but only if they aren't already there */
3391 else if (quote_next) {
3392 /* see if it really is multiple arguments pretending to
3393 * be one and force a set of quotes around it */
3394 if (*find_next_space(arg))
3397 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3399 while (i < curlen) {
3400 if (isSPACE(arg[i])) {
3403 else if (arg[i] == '"') {
3427 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3428 && stricmp(arg+curlen-2, "/c") == 0)
3430 /* is there a next argument? */
3431 if (args[index+1]) {
3432 /* are there two or more next arguments? */
3433 if (args[index+2]) {
3435 extra_quotes = TRUE;
3438 /* single argument, force quoting if it has spaces */
3454 qualified_path(const char *cmd)
3458 char *fullcmd, *curfullcmd;
3464 fullcmd = (char*)cmd;
3466 if (*fullcmd == '/' || *fullcmd == '\\')
3473 pathstr = PerlEnv_getenv("PATH");
3475 /* worst case: PATH is a single directory; we need additional space
3476 * to append "/", ".exe" and trailing "\0" */
3477 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3478 curfullcmd = fullcmd;
3483 /* start by appending the name to the current prefix */
3484 strcpy(curfullcmd, cmd);
3485 curfullcmd += cmdlen;
3487 /* if it doesn't end with '.', or has no extension, try adding
3488 * a trailing .exe first */
3489 if (cmd[cmdlen-1] != '.'
3490 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3492 strcpy(curfullcmd, ".exe");
3493 res = GetFileAttributes(fullcmd);
3494 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3499 /* that failed, try the bare name */
3500 res = GetFileAttributes(fullcmd);
3501 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3504 /* quit if no other path exists, or if cmd already has path */
3505 if (!pathstr || !*pathstr || has_slash)
3508 /* skip leading semis */
3509 while (*pathstr == ';')
3512 /* build a new prefix from scratch */
3513 curfullcmd = fullcmd;
3514 while (*pathstr && *pathstr != ';') {
3515 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3516 pathstr++; /* skip initial '"' */
3517 while (*pathstr && *pathstr != '"') {
3518 *curfullcmd++ = *pathstr++;
3521 pathstr++; /* skip trailing '"' */
3524 *curfullcmd++ = *pathstr++;
3528 pathstr++; /* skip trailing semi */
3529 if (curfullcmd > fullcmd /* append a dir separator */
3530 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3532 *curfullcmd++ = '\\';
3540 /* The following are just place holders.
3541 * Some hosts may provide and environment that the OS is
3542 * not tracking, therefore, these host must provide that
3543 * environment and the current directory to CreateProcess
3547 win32_get_childenv(void)
3553 win32_free_childenv(void* d)
3558 win32_clearenv(void)
3560 char *envv = GetEnvironmentStrings();
3564 char *end = strchr(cur,'=');
3565 if (end && end != cur) {
3567 SetEnvironmentVariable(cur, NULL);
3569 cur = end + strlen(end+1)+2;
3571 else if ((len = strlen(cur)))
3574 FreeEnvironmentStrings(envv);
3578 win32_get_childdir(void)
3582 char szfilename[MAX_PATH+1];
3584 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3585 Newx(ptr, strlen(szfilename)+1, char);
3586 strcpy(ptr, szfilename);
3591 win32_free_childdir(char* d)
3598 /* XXX this needs to be made more compatible with the spawnvp()
3599 * provided by the various RTLs. In particular, searching for
3600 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3601 * This doesn't significantly affect perl itself, because we
3602 * always invoke things using PERL5SHELL if a direct attempt to
3603 * spawn the executable fails.
3605 * XXX splitting and rejoining the commandline between do_aspawn()
3606 * and win32_spawnvp() could also be avoided.
3610 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3612 #ifdef USE_RTL_SPAWNVP
3613 return spawnvp(mode, cmdname, (char * const *)argv);
3620 STARTUPINFO StartupInfo;
3621 PROCESS_INFORMATION ProcessInformation;
3624 char *fullcmd = NULL;
3625 char *cname = (char *)cmdname;
3629 clen = strlen(cname);
3630 /* if command name contains dquotes, must remove them */
3631 if (strchr(cname, '"')) {
3633 Newx(cname,clen+1,char);
3646 cmd = create_command_line(cname, clen, argv);
3648 env = PerlEnv_get_childenv();
3649 dir = PerlEnv_get_childdir();
3652 case P_NOWAIT: /* asynch + remember result */
3653 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3658 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3661 create |= CREATE_NEW_PROCESS_GROUP;
3664 case P_WAIT: /* synchronous execution */
3666 default: /* invalid mode */
3671 memset(&StartupInfo,0,sizeof(StartupInfo));
3672 StartupInfo.cb = sizeof(StartupInfo);
3673 memset(&tbl,0,sizeof(tbl));
3674 PerlEnv_get_child_IO(&tbl);
3675 StartupInfo.dwFlags = tbl.dwFlags;
3676 StartupInfo.dwX = tbl.dwX;
3677 StartupInfo.dwY = tbl.dwY;
3678 StartupInfo.dwXSize = tbl.dwXSize;
3679 StartupInfo.dwYSize = tbl.dwYSize;
3680 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3681 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3682 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3683 StartupInfo.wShowWindow = tbl.wShowWindow;
3684 StartupInfo.hStdInput = tbl.childStdIn;
3685 StartupInfo.hStdOutput = tbl.childStdOut;
3686 StartupInfo.hStdError = tbl.childStdErr;
3687 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3688 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3689 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3691 create |= CREATE_NEW_CONSOLE;
3694 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3696 if (w32_use_showwindow) {
3697 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3698 StartupInfo.wShowWindow = w32_showwindow;
3701 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3704 if (!CreateProcess(cname, /* search PATH to find executable */
3705 cmd, /* executable, and its arguments */
3706 NULL, /* process attributes */
3707 NULL, /* thread attributes */
3708 TRUE, /* inherit handles */
3709 create, /* creation flags */
3710 (LPVOID)env, /* inherit environment */
3711 dir, /* inherit cwd */
3713 &ProcessInformation))
3715 /* initial NULL argument to CreateProcess() does a PATH
3716 * search, but it always first looks in the directory
3717 * where the current process was started, which behavior
3718 * is undesirable for backward compatibility. So we
3719 * jump through our own hoops by picking out the path
3720 * we really want it to use. */
3722 fullcmd = qualified_path(cname);
3724 if (cname != cmdname)
3727 DEBUG_p(PerlIO_printf(Perl_debug_log,
3728 "Retrying [%s] with same args\n",
3738 if (mode == P_NOWAIT) {
3739 /* asynchronous spawn -- store handle, return PID */
3740 ret = (int)ProcessInformation.dwProcessId;
3742 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3743 w32_child_pids[w32_num_children] = (DWORD)ret;
3748 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3749 /* FIXME: if msgwait returned due to message perhaps forward the
3750 "signal" to the process
3752 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3754 CloseHandle(ProcessInformation.hProcess);
3757 CloseHandle(ProcessInformation.hThread);
3760 PerlEnv_free_childenv(env);
3761 PerlEnv_free_childdir(dir);
3763 if (cname != cmdname)
3770 win32_execv(const char *cmdname, const char *const *argv)
3774 /* if this is a pseudo-forked child, we just want to spawn
3775 * the new program, and return */
3777 # ifdef __BORLANDC__
3778 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3780 return spawnv(P_WAIT, cmdname, argv);
3784 return execv(cmdname, (char *const *)argv);
3786 return execv(cmdname, argv);
3791 win32_execvp(const char *cmdname, const char *const *argv)
3795 /* if this is a pseudo-forked child, we just want to spawn
3796 * the new program, and return */
3797 if (w32_pseudo_id) {
3798 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
3808 return execvp(cmdname, (char *const *)argv);
3810 return execvp(cmdname, argv);
3815 win32_perror(const char *str)
3821 win32_setbuf(FILE *pf, char *buf)
3827 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3829 return setvbuf(pf, buf, type, size);
3833 win32_flushall(void)
3839 win32_fcloseall(void)
3845 win32_fgets(char *s, int n, FILE *pf)
3847 return fgets(s, n, pf);
3857 win32_fgetc(FILE *pf)
3863 win32_putc(int c, FILE *pf)
3869 win32_puts(const char *s)
3881 win32_putchar(int c)
3888 #ifndef USE_PERL_SBRK
3890 static char *committed = NULL; /* XXX threadead */
3891 static char *base = NULL; /* XXX threadead */
3892 static char *reserved = NULL; /* XXX threadead */
3893 static char *brk = NULL; /* XXX threadead */
3894 static DWORD pagesize = 0; /* XXX threadead */
3897 sbrk(ptrdiff_t need)
3902 GetSystemInfo(&info);
3903 /* Pretend page size is larger so we don't perpetually
3904 * call the OS to commit just one page ...
3906 pagesize = info.dwPageSize << 3;
3908 if (brk+need >= reserved)
3910 DWORD size = brk+need-reserved;
3912 char *prev_committed = NULL;
3913 if (committed && reserved && committed < reserved)
3915 /* Commit last of previous chunk cannot span allocations */
3916 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
3919 /* Remember where we committed from in case we want to decommit later */
3920 prev_committed = committed;
3921 committed = reserved;
3924 /* Reserve some (more) space
3925 * Contiguous blocks give us greater efficiency, so reserve big blocks -
3926 * this is only address space not memory...
3927 * Note this is a little sneaky, 1st call passes NULL as reserved
3928 * so lets system choose where we start, subsequent calls pass
3929 * the old end address so ask for a contiguous block
3932 if (size < 64*1024*1024)
3933 size = 64*1024*1024;
3934 size = ((size + pagesize - 1) / pagesize) * pagesize;
3935 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
3938 reserved = addr+size;
3948 /* The existing block could not be extended far enough, so decommit
3949 * anything that was just committed above and start anew */
3952 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
3955 reserved = base = committed = brk = NULL;
3966 if (brk > committed)
3968 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
3970 if (committed+size > reserved)
3971 size = reserved-committed;
3972 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
3985 win32_malloc(size_t size)
3987 return malloc(size);
3991 win32_calloc(size_t numitems, size_t size)
3993 return calloc(numitems,size);
3997 win32_realloc(void *block, size_t size)
3999 return realloc(block,size);
4003 win32_free(void *block)
4010 win32_open_osfhandle(intptr_t handle, int flags)
4012 return _open_osfhandle(handle, flags);
4016 win32_get_osfhandle(int fd)
4018 return (intptr_t)_get_osfhandle(fd);
4022 win32_fdupopen(FILE *pf)
4027 int fileno = win32_dup(win32_fileno(pf));
4029 /* open the file in the same mode */
4031 if((pf)->flags & _F_READ) {
4035 else if((pf)->flags & _F_WRIT) {
4039 else if((pf)->flags & _F_RDWR) {
4045 if((pf)->_flag & _IOREAD) {
4049 else if((pf)->_flag & _IOWRT) {
4053 else if((pf)->_flag & _IORW) {
4060 /* it appears that the binmode is attached to the
4061 * file descriptor so binmode files will be handled
4064 pfdup = win32_fdopen(fileno, mode);
4066 /* move the file pointer to the same position */
4067 if (!fgetpos(pf, &pos)) {
4068 fsetpos(pfdup, &pos);
4074 win32_dynaload(const char* filename)
4077 char buf[MAX_PATH+1];
4080 /* LoadLibrary() doesn't recognize forward slashes correctly,
4081 * so turn 'em back. */
4082 first = strchr(filename, '/');
4084 STRLEN len = strlen(filename);
4085 if (len <= MAX_PATH) {
4086 strcpy(buf, filename);
4087 filename = &buf[first - filename];
4089 if (*filename == '/')
4090 *(char*)filename = '\\';
4096 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4099 XS(w32_SetChildShowWindow)
4102 BOOL use_showwindow = w32_use_showwindow;
4103 /* use "unsigned short" because Perl has redefined "WORD" */
4104 unsigned short showwindow = w32_showwindow;
4107 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4109 if (items == 0 || !SvOK(ST(0)))
4110 w32_use_showwindow = FALSE;
4112 w32_use_showwindow = TRUE;
4113 w32_showwindow = (unsigned short)SvIV(ST(0));
4118 ST(0) = sv_2mortal(newSViv(showwindow));
4120 ST(0) = &PL_sv_undef;
4125 Perl_init_os_extras(void)
4128 char *file = __FILE__;
4130 /* Initialize Win32CORE if it has been statically linked. */
4131 void (*pfn_init)(pTHX);
4132 #if defined(__BORLANDC__)
4133 /* makedef.pl seems to have given up on fixing this issue in the .def file */
4134 pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "_init_Win32CORE");
4136 pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "init_Win32CORE");
4141 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4145 win32_signal_context(void)
4150 my_perl = PL_curinterp;
4151 PERL_SET_THX(my_perl);
4155 return PL_curinterp;
4161 win32_ctrlhandler(DWORD dwCtrlType)
4164 dTHXa(PERL_GET_SIG_CONTEXT);
4170 switch(dwCtrlType) {
4171 case CTRL_CLOSE_EVENT:
4172 /* A signal that the system sends to all processes attached to a console when
4173 the user closes the console (either by choosing the Close command from the
4174 console window's System menu, or by choosing the End Task command from the
4177 if (do_raise(aTHX_ 1)) /* SIGHUP */
4178 sig_terminate(aTHX_ 1);
4182 /* A CTRL+c signal was received */
4183 if (do_raise(aTHX_ SIGINT))
4184 sig_terminate(aTHX_ SIGINT);
4187 case CTRL_BREAK_EVENT:
4188 /* A CTRL+BREAK signal was received */
4189 if (do_raise(aTHX_ SIGBREAK))
4190 sig_terminate(aTHX_ SIGBREAK);
4193 case CTRL_LOGOFF_EVENT:
4194 /* A signal that the system sends to all console processes when a user is logging
4195 off. This signal does not indicate which user is logging off, so no
4196 assumptions can be made.
4199 case CTRL_SHUTDOWN_EVENT:
4200 /* A signal that the system sends to all console processes when the system is
4203 if (do_raise(aTHX_ SIGTERM))
4204 sig_terminate(aTHX_ SIGTERM);
4213 #ifdef SET_INVALID_PARAMETER_HANDLER
4214 # include <crtdbg.h>
4225 /* fetch Unicode version of PATH */
4227 wide_path = win32_malloc(len*sizeof(WCHAR));
4229 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
4233 wide_path = win32_realloc(wide_path, len*sizeof(WCHAR));
4238 /* convert to ANSI pathnames */
4239 wide_dir = wide_path;
4242 WCHAR *sep = wcschr(wide_dir, ';');
4250 /* remove quotes around pathname */
4251 if (*wide_dir == '"')
4253 wide_len = wcslen(wide_dir);
4254 if (wide_len && wide_dir[wide_len-1] == '"')
4255 wide_dir[wide_len-1] = '\0';
4257 /* append ansi_dir to ansi_path */
4258 ansi_dir = win32_ansipath(wide_dir);
4259 ansi_len = strlen(ansi_dir);
4261 size_t newlen = len + 1 + ansi_len;
4262 ansi_path = win32_realloc(ansi_path, newlen+1);
4265 ansi_path[len] = ';';
4266 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4271 ansi_path = win32_malloc(5+len+1);
4274 memcpy(ansi_path, "PATH=", 5);
4275 memcpy(ansi_path+5, ansi_dir, len+1);
4278 win32_free(ansi_dir);
4283 /* Update C RTL environ array. This will only have full effect if
4284 * perl_parse() is later called with `environ` as the `env` argument.
4285 * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4287 * We do have to ansify() the PATH before Perl has been fully
4288 * initialized because S_find_script() uses the PATH when perl
4289 * is being invoked with the -S option. This happens before %ENV
4290 * is initialized in S_init_postdump_symbols().
4292 * XXX Is this a bug? Should S_find_script() use the environment
4293 * XXX passed in the `env` arg to parse_perl()?
4296 /* Keep system environment in sync because S_init_postdump_symbols()
4297 * will not call mg_set() if it initializes %ENV from `environ`.
4299 SetEnvironmentVariableA("PATH", ansi_path+5);
4300 /* We are intentionally leaking the ansi_path string here because
4301 * the Borland runtime library puts it directly into the environ
4302 * array. The Microsoft runtime library seems to make a copy,
4303 * but will leak the copy should it be replaced again later.
4304 * Since this code is only called once during PERL_SYS_INIT this
4305 * shouldn't really matter.
4308 win32_free(wide_path);
4312 Perl_win32_init(int *argcp, char ***argvp)
4314 #ifdef SET_INVALID_PARAMETER_HANDLER
4315 _invalid_parameter_handler oldHandler, newHandler;
4316 newHandler = my_invalid_parameter_handler;
4317 oldHandler = _set_invalid_parameter_handler(newHandler);
4318 _CrtSetReportMode(_CRT_ASSERT, 0);
4320 /* Disable floating point errors, Perl will trap the ones we
4321 * care about. VC++ RTL defaults to switching these off
4322 * already, but the Borland RTL doesn't. Since we don't
4323 * want to be at the vendor's whim on the default, we set
4324 * it explicitly here.
4326 #if !defined(__GNUC__)
4327 _control87(MCW_EM, MCW_EM);
4331 /* When the manifest resource requests Common-Controls v6 then
4332 * user32.dll no longer registers all the Windows classes used for
4333 * standard controls but leaves some of them to be registered by
4334 * comctl32.dll. InitCommonControls() doesn't do anything but calling
4335 * it makes sure comctl32.dll gets loaded into the process and registers
4336 * the standard control classes. Without this even normal Windows APIs
4337 * like MessageBox() can fail under some versions of Windows XP.
4339 InitCommonControls();
4341 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4342 GetVersionEx(&g_osver);
4348 Perl_win32_term(void)
4358 win32_get_child_IO(child_IO_table* ptbl)
4360 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4361 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4362 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4366 win32_signal(int sig, Sighandler_t subcode)
4369 if (sig < SIG_SIZE) {
4370 int save_errno = errno;
4371 Sighandler_t result = signal(sig, subcode);
4372 if (result == SIG_ERR) {
4373 result = w32_sighandler[sig];
4376 w32_sighandler[sig] = subcode;
4385 /* The PerlMessageWindowClass's WindowProc */
4387 win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4389 return win32_process_message(hwnd, msg, wParam, lParam) ?
4390 0 : DefWindowProc(hwnd, msg, wParam, lParam);
4393 /* The real message handler. Can be called with
4394 * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4395 * that it processes */
4397 win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4399 /* BEWARE. The context retrieved using dTHX; is the context of the
4400 * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4401 * up to and including WM_CREATE. If it ever happens that you need the
4402 * 'child' context before this, then it needs to be passed into
4403 * win32_create_message_window(), and passed to the WM_NCCREATE handler
4404 * from the lparam of CreateWindow(). It could then be stored/retrieved
4405 * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4406 * the dTHX calls here. */
4407 /* XXX For now it is assumed that the overhead of the dTHX; for what
4408 * are relativley infrequent code-paths, is better than the added
4409 * complexity of getting the correct context passed into
4410 * win32_create_message_window() */
4415 case WM_USER_MESSAGE: {
4416 long child = find_pseudo_pid((int)wParam);
4419 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
4426 case WM_USER_KILL: {
4428 /* We use WM_USER_KILL to fake kill() with other signals */
4429 int sig = (int)wParam;
4430 if (do_raise(aTHX_ sig))
4431 sig_terminate(aTHX_ sig);
4438 /* alarm() is a one-shot but SetTimer() repeats so kill it */
4439 if (w32_timerid && w32_timerid==(UINT)wParam) {
4440 KillTimer(w32_message_hwnd, w32_timerid);
4443 /* Now fake a call to signal handler */
4444 if (do_raise(aTHX_ 14))
4445 sig_terminate(aTHX_ 14);
4457 /* Above or other stuff may have set a signal flag, and we may not have
4458 * been called from win32_async_check() (e.g. some other GUI's message
4459 * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
4460 * handler that die's, and the message loop that calls here is wrapped
4461 * in an eval, then you may well end up with orphaned windows - signals
4462 * are dispatched by win32_async_check() */
4468 win32_create_message_window_class(void)
4470 /* create the window class for "message only" windows */
4474 wc.lpfnWndProc = win32_message_window_proc;
4475 wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
4476 wc.lpszClassName = "PerlMessageWindowClass";
4478 /* second and subsequent calls will fail, but class
4479 * will already be registered */
4484 win32_create_message_window(void)
4486 win32_create_message_window_class();
4487 return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
4488 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
4491 #ifdef HAVE_INTERP_INTERN
4494 win32_csighandler(int sig)
4497 dTHXa(PERL_GET_SIG_CONTEXT);
4498 Perl_warn(aTHX_ "Got signal %d",sig);
4503 #if defined(__MINGW32__) && defined(__cplusplus)
4504 #define CAST_HWND__(x) (HWND__*)(x)
4506 #define CAST_HWND__(x) x
4510 Perl_sys_intern_init(pTHX)
4514 w32_perlshell_tokens = NULL;
4515 w32_perlshell_vec = (char**)NULL;
4516 w32_perlshell_items = 0;
4517 w32_fdpid = newAV();
4518 Newx(w32_children, 1, child_tab);
4519 w32_num_children = 0;
4520 # ifdef USE_ITHREADS
4522 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4523 w32_num_pseudo_children = 0;
4526 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4528 for (i=0; i < SIG_SIZE; i++) {
4529 w32_sighandler[i] = SIG_DFL;
4531 # ifdef MULTIPLICITY
4532 if (my_perl == PL_curinterp) {
4536 /* Force C runtime signal stuff to set its console handler */
4537 signal(SIGINT,win32_csighandler);
4538 signal(SIGBREAK,win32_csighandler);
4540 /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
4541 * flag. This has the side-effect of disabling Ctrl-C events in all
4542 * processes in this group.
4543 * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
4544 * with a NULL handler.
4546 SetConsoleCtrlHandler(NULL,FALSE);
4548 /* Push our handler on top */
4549 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4554 Perl_sys_intern_clear(pTHX)
4556 Safefree(w32_perlshell_tokens);
4557 Safefree(w32_perlshell_vec);
4558 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4559 Safefree(w32_children);
4561 KillTimer(w32_message_hwnd, w32_timerid);
4564 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4565 DestroyWindow(w32_message_hwnd);
4566 # ifdef MULTIPLICITY
4567 if (my_perl == PL_curinterp) {
4571 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4573 # ifdef USE_ITHREADS
4574 Safefree(w32_pseudo_children);
4578 # ifdef USE_ITHREADS
4581 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4583 PERL_ARGS_ASSERT_SYS_INTERN_DUP;
4585 dst->perlshell_tokens = NULL;
4586 dst->perlshell_vec = (char**)NULL;
4587 dst->perlshell_items = 0;
4588 dst->fdpid = newAV();
4589 Newxz(dst->children, 1, child_tab);
4591 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4593 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4594 dst->poll_count = 0;
4595 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4597 # endif /* USE_ITHREADS */
4598 #endif /* HAVE_INTERP_INTERN */