/* WIN32.C
*
* (c) 1995 Microsoft Corporation. All rights reserved.
- * Developed by hip communications inc., http://info.hip.com/info/
+ * Developed by hip communications inc.
* Portions (c) 1993 Intergraph Corporation. All rights reserved.
*
* You may distribute under the terms of either the GNU General Public
#define Win32_Winsock
#endif
#include <windows.h>
-/* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
-#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
-# include <shellapi.h>
-#else
- LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
+#ifndef HWND_MESSAGE
+# define HWND_MESSAGE ((HWND)-3)
+#endif
+#ifndef WC_NO_BEST_FIT_CHARS
+# define WC_NO_BEST_FIT_CHARS 0x00000400 /* requires Windows 2000 or later */
#endif
#include <winnt.h>
+#include <tlhelp32.h>
#include <io.h>
#include <signal.h>
+#define SystemProcessesAndThreadsInformation 5
+
+/* Inline some definitions from the DDK */
+typedef struct {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING;
+
+typedef struct {
+ ULONG NextEntryDelta;
+ ULONG ThreadCount;
+ ULONG Reserved1[6];
+ LARGE_INTEGER CreateTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER KernelTime;
+ UNICODE_STRING ProcessName;
+ LONG BasePriority;
+ ULONG ProcessId;
+ ULONG InheritedFromProcessId;
+ /* Remainder of the structure depends on the Windows version,
+ * but we don't need those additional fields anyways... */
+} SYSTEM_PROCESSES;
+
/* #include "config.h" */
#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
/* Mingw32-1.1 is missing some prototypes */
+START_EXTERN_C
FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
FILE * _wfdopen(int nFd, LPCWSTR wszMode);
FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
int _flushall();
int _fcloseall();
+END_EXTERN_C
#endif
#if defined(__BORLANDC__)
static void get_shell(void);
static long tokenize(const char *str, char **dest, char ***destv);
-static int do_spawn2(pTHX_ char *cmd, int exectype);
-static BOOL has_shell_metachars(char *ptr);
+static int do_spawn2(pTHX_ const char *cmd, int exectype);
+static BOOL has_shell_metachars(const char *ptr);
static long filetime_to_clock(PFILETIME ft);
static BOOL filetime_from_time(PFILETIME ft, time_t t);
-static char * get_emd_part(SV **leading, char *trailing, ...);
+static char * get_emd_part(SV **leading, STRLEN *const len,
+ char *trailing, ...);
static void remove_dead_process(long deceased);
static long find_pid(int pid);
static char * qualified_path(const char *cmd);
static char * win32_get_xlib(const char *pl, const char *xlib,
- const char *libname);
+ const char *libname, STRLEN *const len);
+static LRESULT win32_process_message(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam);
#ifdef USE_ITHREADS
static void remove_dead_pseudo_process(long child);
char w32_module_name[MAX_PATH+1];
END_EXTERN_C
-static DWORD w32_platform = (DWORD)-1;
+static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
+
+static HANDLE (WINAPI *pfnCreateToolhelp32Snapshot)(DWORD, DWORD) = NULL;
+static BOOL (WINAPI *pfnProcess32First)(HANDLE, PROCESSENTRY32*) = NULL;
+static BOOL (WINAPI *pfnProcess32Next)(HANDLE, PROCESSENTRY32*) = NULL;
+static LONG (WINAPI *pfnZwQuerySystemInformation)(UINT, PVOID, ULONG, PULONG);
+
+#ifdef __BORLANDC__
+/* Silence STDERR grumblings from Borland's math library. */
+DllExport int
+_matherr(struct _exception *a)
+{
+ PERL_UNUSED_VAR(a);
+ return 1;
+}
+#endif
+
+/* VS2005 (MSC version 14) provides a mechanism to set an invalid
+ * parameter handler. This functionality is not available in the
+ * 64-bit compiler from the Platform SDK, which unfortunately also
+ * believes itself to be MSC version 14.
+ *
+ * There is no #define related to _set_invalid_parameter_handler(),
+ * but we can check for one of the constants defined for
+ * _set_abort_behavior(), which was introduced into stdlib.h at
+ * the same time.
+ */
+
+#if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
+# define SET_INVALID_PARAMETER_HANDLER
+#endif
-#define ONE_K_BUFSIZE 1024
+#ifdef SET_INVALID_PARAMETER_HANDLER
+void my_invalid_parameter_handler(const wchar_t* expression,
+ const wchar_t* function,
+ const wchar_t* file,
+ unsigned int line,
+ uintptr_t pReserved)
+{
+# ifdef _DEBUG
+ wprintf(L"Invalid parameter detected in function %s."
+ L" File: %s Line: %d\n", function, file, line);
+ wprintf(L"Expression: %s\n", expression);
+# endif
+}
+#endif
int
IsWin95(void)
{
- return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
+ return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
}
int
IsWinNT(void)
{
- return (win32_os_id() == VER_PLATFORM_WIN32_NT);
+ return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+
+int
+IsWin2000(void)
+{
+ return (g_osver.dwMajorVersion > 4);
}
EXTERN_C void
set_w32_module_name(void)
{
+ /* this function may be called at DLL_PROCESS_ATTACH time */
char* ptr;
- GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
- ? GetModuleHandle(NULL)
- : w32_perldll_handle),
- w32_module_name, sizeof(w32_module_name));
+ HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
+ ? GetModuleHandle(NULL)
+ : w32_perldll_handle);
+
+ OSVERSIONINFO osver; /* g_osver may not yet be initialized */
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ GetVersionEx(&osver);
+
+ if (osver.dwMajorVersion > 4) {
+ WCHAR modulename[MAX_PATH];
+ WCHAR fullname[MAX_PATH];
+ char *ansi;
+
+ DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
+ (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
+ GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
+
+ GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
+
+ /* Make sure we get an absolute pathname in case the module was loaded
+ * explicitly by LoadLibrary() with a relative path. */
+ GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
+
+ /* Make sure we start with the long path name of the module because we
+ * later scan for pathname components to match "5.xx" to locate
+ * compatible sitelib directories, and the short pathname might mangle
+ * this path segment (e.g. by removing the dot on NTFS to something
+ * like "5xx~1.yy") */
+ if (pfnGetLongPathNameW)
+ pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
- /* try to get full path to binary (which may be mangled when perl is
- * run from a 16-bit app) */
- /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
- (void)win32_longpath(w32_module_name);
- /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
+ /* remove \\?\ prefix */
+ if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
+ memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
+
+ ansi = win32_ansipath(fullname);
+ my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
+ win32_free(ansi);
+ }
+ else {
+ GetModuleFileName(module, w32_module_name, sizeof(w32_module_name));
+
+ /* remove \\?\ prefix */
+ if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
+ memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
+
+ /* try to get full path to binary (which may be mangled when perl is
+ * run from a 16-bit app) */
+ /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
+ win32_longpath(w32_module_name);
+ /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
+ }
/* normalize to forward slashes */
ptr = w32_module_name;
HKEY handle;
DWORD type;
const char *subkey = "Software\\Perl";
- char *str = Nullch;
+ char *str = NULL;
long retval;
retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
/* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
static char *
-get_emd_part(SV **prev_pathp, char *trailing_path, ...)
+get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
{
char base[10];
va_list ap;
dTHX;
if (!*prev_pathp)
*prev_pathp = sv_2mortal(newSVpvn("",0));
- sv_catpvn(*prev_pathp, ";", 1);
+ else if (SvPVX(*prev_pathp))
+ sv_catpvn(*prev_pathp, ";", 1);
sv_catpv(*prev_pathp, mod_name);
+ if(len)
+ *len = SvCUR(*prev_pathp);
return SvPVX(*prev_pathp);
}
- return Nullch;
+ return NULL;
}
char *
-win32_get_privlib(const char *pl)
+win32_get_privlib(const char *pl, STRLEN *const len)
{
dTHX;
char *stdlib = "lib";
char buffer[MAX_PATH+1];
- SV *sv = Nullsv;
+ SV *sv = NULL;
/* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
sprintf(buffer, "%s-%s", stdlib, pl);
(void)get_regstr(stdlib, &sv);
/* $stdlib .= ";$EMD/../../lib" */
- return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
+ return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
}
static char *
-win32_get_xlib(const char *pl, const char *xlib, const char *libname)
+win32_get_xlib(const char *pl, const char *xlib, const char *libname,
+ STRLEN *const len)
{
dTHX;
char regstr[40];
char pathstr[MAX_PATH+1];
- SV *sv1 = Nullsv;
- SV *sv2 = Nullsv;
+ SV *sv1 = NULL;
+ SV *sv2 = NULL;
/* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
sprintf(regstr, "%s-%s", xlib, pl);
/* $xlib .=
* ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
sprintf(pathstr, "%s/%s/lib", libname, pl);
- (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
+ (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
/* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
(void)get_regstr(xlib, &sv2);
/* $xlib .=
* ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
sprintf(pathstr, "%s/lib", libname);
- (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
+ (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
if (!sv1 && !sv2)
- return Nullch;
- if (!sv1)
- return SvPVX(sv2);
- if (!sv2)
- return SvPVX(sv1);
-
- sv_catpvn(sv1, ";", 1);
- sv_catsv(sv1, sv2);
+ return NULL;
+ if (!sv1) {
+ sv1 = sv2;
+ } else if (sv2) {
+ sv_catpvn(sv1, ";", 1);
+ sv_catsv(sv1, sv2);
+ }
+ if (len)
+ *len = SvCUR(sv1);
return SvPVX(sv1);
}
char *
-win32_get_sitelib(const char *pl)
+win32_get_sitelib(const char *pl, STRLEN *const len)
{
- return win32_get_xlib(pl, "sitelib", "site");
+ return win32_get_xlib(pl, "sitelib", "site", len);
}
#ifndef PERL_VENDORLIB_NAME
#endif
char *
-win32_get_vendorlib(const char *pl)
+win32_get_vendorlib(const char *pl, STRLEN *const len)
{
- return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
+ return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME, len);
}
static BOOL
-has_shell_metachars(char *ptr)
+has_shell_metachars(const char *ptr)
{
int inquote = 0;
char quote = '\0';
* the library functions will get the correct environment
*/
PerlIO *
-Perl_my_popen(pTHX_ char *cmd, char *mode)
+Perl_my_popen(pTHX_ const char *cmd, const char *mode)
{
#ifdef FIXCMD
#define fixcmd(x) { \
DllExport unsigned long
win32_os_id(void)
{
- static OSVERSIONINFO osver;
-
- if (osver.dwPlatformId != w32_platform) {
- memset(&osver, 0, sizeof(OSVERSIONINFO));
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&osver);
- w32_platform = osver.dwPlatformId;
- }
- return (unsigned long)w32_platform;
+ return (unsigned long)g_osver.dwPlatformId;
}
DllExport int
static long
tokenize(const char *str, char **dest, char ***destv)
{
- char *retstart = Nullch;
+ char *retstart = NULL;
char **retvstart = 0;
int items = -1;
if (str) {
int slen = strlen(str);
register char *ret;
register char **retv;
- New(1307, ret, slen+2, char);
- New(1308, retv, (slen+3)/2, char*);
+ Newx(ret, slen+2, char);
+ Newx(retv, (slen+3)/2, char*);
retstart = ret;
retvstart = retv;
++items;
ret++;
}
- retvstart[items] = Nullch;
+ retvstart[items] = NULL;
*ret++ = '\0';
*ret = '\0';
}
int flag = P_WAIT;
int index = 0;
+ PERL_ARGS_ASSERT_DO_ASPAWN;
+
if (sp <= mark)
return -1;
get_shell();
- New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
+ Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
++mark;
}
if (flag == P_NOWAIT) {
- if (IsWin95())
- PL_statusvalue = -1; /* >16bits hint for pp_system() */
+ PL_statusvalue = -1; /* >16bits hint for pp_system() */
}
else {
if (status < 0) {
}
static int
-do_spawn2(pTHX_ char *cmd, int exectype)
+do_spawn2(pTHX_ const char *cmd, int exectype)
{
char **a;
char *s;
/* Save an extra exec if possible. See if there are shell
* metacharacters in it */
if (!has_shell_metachars(cmd)) {
- New(1301,argv, strlen(cmd) / 2 + 2, char*);
- New(1302,cmd2, strlen(cmd) + 1, char);
+ Newx(argv, strlen(cmd) / 2 + 2, char*);
+ Newx(cmd2, strlen(cmd) + 1, char);
strcpy(cmd2, cmd);
a = argv;
for (s = cmd2; *s;) {
if (*s)
*s++ = '\0';
}
- *a = Nullch;
+ *a = NULL;
if (argv[0]) {
switch (exectype) {
case EXECF_SPAWN:
char **argv;
int i = -1;
get_shell();
- New(1306, argv, w32_perlshell_items + 2, char*);
+ Newx(argv, w32_perlshell_items + 2, char*);
while (++i < w32_perlshell_items)
argv[i] = w32_perlshell_vec[i];
- argv[i++] = cmd;
- argv[i] = Nullch;
+ argv[i++] = (char *)cmd;
+ argv[i] = NULL;
switch (exectype) {
case EXECF_SPAWN:
status = win32_spawnvp(P_WAIT, argv[0],
Safefree(argv);
}
if (exectype == EXECF_SPAWN_NOWAIT) {
- if (IsWin95())
- PL_statusvalue = -1; /* >16bits hint for pp_system() */
+ PL_statusvalue = -1; /* >16bits hint for pp_system() */
}
else {
if (status < 0) {
int
Perl_do_spawn(pTHX_ char *cmd)
{
+ PERL_ARGS_ASSERT_DO_SPAWN;
+
return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
}
int
Perl_do_spawn_nowait(pTHX_ char *cmd)
{
+ PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
+
return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
}
bool
-Perl_do_exec(pTHX_ char *cmd)
+Perl_do_exec(pTHX_ const char *cmd)
{
+ PERL_ARGS_ASSERT_DO_EXEC;
+
do_spawn2(aTHX_ cmd, EXECF_EXEC);
return FALSE;
}
* return the pointer to the current file name.
*/
DllExport DIR *
-win32_opendir(char *filename)
+win32_opendir(const char *filename)
{
dTHX;
DIR *dirp;
Stat_t sbuf;
WIN32_FIND_DATAA aFindData;
WIN32_FIND_DATAW wFindData;
- HANDLE fh;
+ bool using_wide;
char buffer[MAX_PATH*2];
- WCHAR wbuffer[MAX_PATH+1];
- char* ptr;
+ char *ptr;
len = strlen(filename);
if (len > MAX_PATH)
return NULL;
/* Get us a DIR structure */
- Newz(1303, dirp, 1, DIR);
+ Newxz(dirp, 1, DIR);
/* Create the search pattern */
strcpy(scanname, filename);
scanname[len] = '\0';
/* do the FindFirstFile call */
- if (USING_WIDE()) {
- A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
- fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
+ if (IsWin2000()) {
+ WCHAR wscanname[sizeof(scanname)];
+ MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
+ dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
+ using_wide = TRUE;
}
else {
- fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
+ dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
}
- dirp->handle = fh;
- if (fh == INVALID_HANDLE_VALUE) {
+ if (dirp->handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
/* FindFirstFile() fails on empty drives! */
switch (err) {
return NULL;
}
- /* now allocate the first part of the string table for
- * the filenames that we find.
- */
- if (USING_WIDE()) {
- W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
- ptr = buffer;
+ if (using_wide) {
+ BOOL use_default = FALSE;
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
+ wFindData.cFileName, -1,
+ buffer, sizeof(buffer), NULL, &use_default);
+ if (use_default && *wFindData.cAlternateFileName) {
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
+ wFindData.cAlternateFileName, -1,
+ buffer, sizeof(buffer), NULL, NULL);
+ }
+ ptr = buffer;
}
else {
- ptr = aFindData.cFileName;
+ ptr = aFindData.cFileName;
}
+ /* now allocate the first part of the string table for
+ * the filenames that we find.
+ */
idx = strlen(ptr)+1;
if (idx < 256)
- dirp->size = 128;
+ dirp->size = 256;
else
dirp->size = idx;
- New(1304, dirp->start, dirp->size, char);
+ Newx(dirp->start, dirp->size, char);
strcpy(dirp->start, ptr);
dirp->nfiles++;
dirp->end = dirp->curr = dirp->start;
dirp->curr += len + 1;
if (dirp->curr >= dirp->end) {
dTHX;
- char* ptr;
- BOOL res;
- WIN32_FIND_DATAW wFindData;
- WIN32_FIND_DATAA aFindData;
- char buffer[MAX_PATH*2];
+ BOOL res;
+ WIN32_FIND_DATAA aFindData;
+ char buffer[MAX_PATH*2];
+ char *ptr;
/* finding the next file that matches the wildcard
* (which should be all of them in this directory!).
*/
- if (USING_WIDE()) {
+ if (IsWin2000()) {
+ WIN32_FIND_DATAW wFindData;
res = FindNextFileW(dirp->handle, &wFindData);
if (res) {
- W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
- ptr = buffer;
- }
- }
- else {
- res = FindNextFileA(dirp->handle, &aFindData);
- if (res)
- ptr = aFindData.cFileName;
- }
+ BOOL use_default = FALSE;
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
+ wFindData.cFileName, -1,
+ buffer, sizeof(buffer), NULL, &use_default);
+ if (use_default && *wFindData.cAlternateFileName) {
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
+ wFindData.cAlternateFileName, -1,
+ buffer, sizeof(buffer), NULL, NULL);
+ }
+ ptr = buffer;
+ }
+ }
+ else {
+ res = FindNextFileA(dirp->handle, &aFindData);
+ ptr = aFindData.cFileName;
+ }
if (res) {
long endpos = dirp->end - dirp->start;
long newsize = endpos + strlen(ptr) + 1;
(w32_num_pseudo_children-child-1), HANDLE);
Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
(w32_num_pseudo_children-child-1), DWORD);
+ Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
+ (w32_num_pseudo_children-child-1), HWND);
w32_num_pseudo_children--;
}
}
#endif
+static int
+terminate_process(DWORD pid, HANDLE process_handle, int sig)
+{
+ switch(sig) {
+ case 0:
+ /* "Does process exist?" use of kill */
+ return 1;
+ case 2:
+ if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
+ return 1;
+ break;
+ case SIGBREAK:
+ case SIGTERM:
+ if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
+ return 1;
+ break;
+ default: /* For now be backwards compatible with perl 5.6 */
+ case 9:
+ /* Note that we will only be able to kill processes owned by the
+ * current process owner, even when we are running as an administrator.
+ * To kill processes of other owners we would need to set the
+ * 'SeDebugPrivilege' privilege before obtaining the process handle.
+ */
+ if (TerminateProcess(process_handle, sig))
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+/* Traverse process tree using ToolHelp functions */
+static int
+kill_process_tree_toolhelp(DWORD pid, int sig)
+{
+ HANDLE process_handle;
+ HANDLE snapshot_handle;
+ int killed = 0;
+
+ process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (process_handle == NULL)
+ return 0;
+
+ killed += terminate_process(pid, process_handle, sig);
+
+ snapshot_handle = pfnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (snapshot_handle != INVALID_HANDLE_VALUE) {
+ PROCESSENTRY32 entry;
+
+ entry.dwSize = sizeof(entry);
+ if (pfnProcess32First(snapshot_handle, &entry)) {
+ do {
+ if (entry.th32ParentProcessID == pid)
+ killed += kill_process_tree_toolhelp(entry.th32ProcessID, sig);
+ entry.dwSize = sizeof(entry);
+ }
+ while (pfnProcess32Next(snapshot_handle, &entry));
+ }
+ CloseHandle(snapshot_handle);
+ }
+ CloseHandle(process_handle);
+ return killed;
+}
+
+/* Traverse process tree using undocumented system information structures.
+ * This is only necessary on Windows NT, which lacks the ToolHelp functions.
+ */
+static int
+kill_process_tree_sysinfo(SYSTEM_PROCESSES *process_info, DWORD pid, int sig)
+{
+ HANDLE process_handle;
+ SYSTEM_PROCESSES *p = process_info;
+ int killed = 0;
+
+ process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (process_handle == NULL)
+ return 0;
+
+ killed += terminate_process(pid, process_handle, sig);
+
+ while (1) {
+ if (p->InheritedFromProcessId == (DWORD)pid)
+ killed += kill_process_tree_sysinfo(process_info, p->ProcessId, sig);
+
+ if (p->NextEntryDelta == 0)
+ break;
+
+ p = (SYSTEM_PROCESSES*)((char*)p + p->NextEntryDelta);
+ }
+
+ CloseHandle(process_handle);
+ return killed;
+}
+
+int
+killpg(int pid, int sig)
+{
+ /* Use "documented" method whenever available */
+ if (pfnCreateToolhelp32Snapshot && pfnProcess32First && pfnProcess32Next) {
+ return kill_process_tree_toolhelp((DWORD)pid, sig);
+ }
+
+ /* Fall back to undocumented Windows internals on Windows NT */
+ if (pfnZwQuerySystemInformation) {
+ dTHX;
+ char *buffer;
+ DWORD size = 0;
+
+ pfnZwQuerySystemInformation(SystemProcessesAndThreadsInformation, NULL, 0, &size);
+ Newx(buffer, size, char);
+
+ if (pfnZwQuerySystemInformation(SystemProcessesAndThreadsInformation, buffer, size, NULL) >= 0) {
+ int killed = kill_process_tree_sysinfo((SYSTEM_PROCESSES*)buffer, (DWORD)pid, sig);
+ Safefree(buffer);
+ return killed;
+ }
+ }
+ return 0;
+}
+
+static int
+my_kill(int pid, int sig)
+{
+ int retval = 0;
+ HANDLE process_handle;
+
+ if (sig < 0)
+ return killpg(pid, -sig);
+
+ process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
+ if (process_handle != NULL) {
+ retval = terminate_process(pid, process_handle, sig);
+ CloseHandle(process_handle);
+ }
+ return retval;
+}
+
DllExport int
win32_kill(int pid, int sig)
{
dTHX;
- HANDLE hProcess;
long child;
- int retval;
#ifdef USE_ITHREADS
if (pid < 0) {
/* it is a pseudo-forked child */
child = find_pseudo_pid(-pid);
if (child >= 0) {
- hProcess = w32_pseudo_child_handles[child];
+ HWND hwnd = w32_pseudo_child_message_hwnds[child];
+ HANDLE hProcess = w32_pseudo_child_handles[child];
switch (sig) {
case 0:
/* "Does process exist?" use of kill */
return 0;
+
case 9:
/* kill -9 style un-graceful exit */
if (TerminateThread(hProcess, sig)) {
return 0;
}
break;
- default:
- /* We fake signals to pseudo-processes using Win32
- * message queue. In Win9X the pids are negative already. */
- if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) {
- /* It might be us ... */
- PERL_ASYNC_CHECK();
- return 0;
- }
+
+ default: {
+ int count = 0;
+ /* pseudo-process has not yet properly initialized if hwnd isn't set */
+ while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
+ /* Yield and wait for the other thread to send us its message_hwnd */
+ Sleep(0);
+ win32_async_check(aTHX);
+ hwnd = w32_pseudo_child_message_hwnds[child];
+ ++count;
+ }
+ if (hwnd != INVALID_HANDLE_VALUE) {
+ /* We fake signals to pseudo-processes using Win32
+ * message queue. In Win9X the pids are negative already. */
+ if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
+ PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
+ {
+ /* It might be us ... */
+ PERL_ASYNC_CHECK();
+ return 0;
+ }
+ }
break;
}
+ } /* switch */
}
else if (IsWin95()) {
pid = -pid;
{
child = find_pid(pid);
if (child >= 0) {
- hProcess = w32_child_handles[child];
- switch(sig) {
- case 0:
- /* "Does process exist?" use of kill */
- return 0;
- case 2:
- if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
- return 0;
- break;
- case SIGBREAK:
- case SIGTERM:
- if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
- return 0;
- break;
- default: /* For now be backwards compatible with perl5.6 */
- case 9:
- if (TerminateProcess(hProcess, sig)) {
- remove_dead_process(child);
- return 0;
- }
- break;
+ if (my_kill(pid, sig)) {
+ DWORD exitcode = 0;
+ if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
+ exitcode != STILL_ACTIVE)
+ {
+ remove_dead_process(child);
+ }
+ return 0;
}
}
else {
alien_process:
- retval = -1;
- hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
- (IsWin95() ? -pid : pid));
- if (hProcess) {
- switch(sig) {
- case 0:
- /* "Does process exist?" use of kill */
- retval = 0;
- break;
- case 2:
- if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
- retval = 0;
- break;
- case SIGBREAK:
- case SIGTERM:
- if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
- retval = 0;
- break;
- default: /* For now be backwards compatible with perl5.6 */
- case 9:
- if (TerminateProcess(hProcess, sig))
- retval = 0;
- break;
- }
- }
- CloseHandle(hProcess);
- if (retval == 0)
+ if (my_kill((IsWin95() ? -pid : pid), sig))
return 0;
}
}
char buffer[MAX_PATH+1];
int l = strlen(path);
int res;
- WCHAR wbuffer[MAX_PATH+1];
- WCHAR* pwbuffer;
- HANDLE handle;
int nlink = 1;
+ BOOL expect_dir = FALSE;
+
+ GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
+ GV_NOTQUAL, SVt_PV);
+ BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
if (l > 1) {
switch(path[l - 1]) {
/* FindFirstFile() and stat() are buggy with a trailing
- * backslash, so change it to a forward slash :-( */
+ * slashes, except for the root directory of a drive */
case '\\':
- if (l >= sizeof(buffer)) {
+ case '/':
+ if (l > sizeof(buffer)) {
errno = ENAMETOOLONG;
return -1;
}
- strncpy(buffer, path, l-1);
- buffer[l - 1] = '/';
- buffer[l] = '\0';
- path = buffer;
+ --l;
+ strncpy(buffer, path, l);
+ /* remove additional trailing slashes */
+ while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
+ --l;
+ /* add back slash if we otherwise end up with just a drive letter */
+ if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
+ buffer[l++] = '\\';
+ buffer[l] = '\0';
+ path = buffer;
+ expect_dir = TRUE;
break;
+
/* FindFirstFile() is buggy with "x:", so add a dot :-( */
case ':':
if (l == 2 && isALPHA(path[0])) {
}
}
- /* We *must* open & close the file once; otherwise file attribute changes */
- /* might not yet have propagated to "other" hard links of the same file. */
- /* This also gives us an opportunity to determine the number of links. */
- if (USING_WIDE()) {
- A2WHELPER(path, wbuffer, sizeof(wbuffer));
- pwbuffer = PerlDir_mapW(wbuffer);
- handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
- }
- else {
- path = PerlDir_mapA(path);
- l = strlen(path);
- handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
- }
- if (handle != INVALID_HANDLE_VALUE) {
- BY_HANDLE_FILE_INFORMATION bhi;
- if (GetFileInformationByHandle(handle, &bhi))
- nlink = bhi.nNumberOfLinks;
- CloseHandle(handle);
- }
+ path = PerlDir_mapA(path);
+ l = strlen(path);
- /* pwbuffer or path will be mapped correctly above */
- if (USING_WIDE()) {
-#if defined(WIN64) || defined(USE_LARGE_FILES)
- res = _wstati64(pwbuffer, sbuf);
-#else
- res = _wstat(pwbuffer, (struct _stat*)sbuf);
-#endif
+ if (!sloppy) {
+ /* We must open & close the file once; otherwise file attribute changes */
+ /* might not yet have propagated to "other" hard links of the same file. */
+ /* This also gives us an opportunity to determine the number of links. */
+ HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (handle != INVALID_HANDLE_VALUE) {
+ BY_HANDLE_FILE_INFORMATION bhi;
+ if (GetFileInformationByHandle(handle, &bhi))
+ nlink = bhi.nNumberOfLinks;
+ CloseHandle(handle);
+ }
}
- else {
+
+ /* path will be mapped correctly above */
#if defined(WIN64) || defined(USE_LARGE_FILES)
- res = _stati64(path, sbuf);
+ res = _stati64(path, sbuf);
#else
- res = stat(path, sbuf);
+ res = stat(path, sbuf);
#endif
- }
sbuf->st_nlink = nlink;
if (res < 0) {
* XXX using GetFileAttributesEx() will enable us to set
* sbuf->st_*time (but note that's not available on the
* Windows of 1995) */
- DWORD r;
- if (USING_WIDE()) {
- r = GetFileAttributesW(pwbuffer);
- }
- else {
- r = GetFileAttributesA(path);
- }
+ DWORD r = GetFileAttributesA(path);
if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
/* sbuf may still contain old garbage since stat() failed */
Zero(sbuf, 1, Stat_t);
&& (path[2] == '\\' || path[2] == '/'))
{
/* The drive can be inaccessible, some _stat()s are buggy */
- if (USING_WIDE()
- ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
- : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
+ if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
errno = ENOENT;
return -1;
}
}
+ if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
+ errno = ENOTDIR;
+ return -1;
+ }
+ if (S_ISDIR(sbuf->st_mode)) {
+ /* Ensure the "write" bit is switched off in the mode for
+ * directories with the read-only attribute set. Borland (at least)
+ * switches it on for directories, which is technically correct
+ * (directories are indeed always writable unless denied by DACLs),
+ * but we want stat() and -w to reflect the state of the read-only
+ * attribute for symmetry with chmod(). */
+ DWORD r = GetFileAttributesA(path);
+ if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
+ sbuf->st_mode &= ~S_IWRITE;
+ }
+ }
#ifdef __BORLANDC__
- if (S_ISDIR(sbuf->st_mode))
- sbuf->st_mode |= S_IWRITE | S_IEXEC;
+ if (S_ISDIR(sbuf->st_mode)) {
+ sbuf->st_mode |= S_IEXEC;
+ }
else if (S_ISREG(sbuf->st_mode)) {
int perms;
if (l >= 4 && path[l-4] == '.') {
char *start = path;
char sep;
if (!path)
- return Nullch;
+ return NULL;
/* drive prefix */
if (isALPHA(path[0]) && path[1] == ':') {
else {
FindClose(fhand);
errno = ERANGE;
- return Nullch;
+ return NULL;
}
}
else {
/* failed a step, just return without side effects */
/*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
errno = EINVAL;
- return Nullch;
+ return NULL;
}
}
strcpy(path,tmpbuf);
return path;
}
+static void
+out_of_memory(void)
+{
+ if (PL_curinterp) {
+ dTHX;
+ /* Can't use PerlIO to write as it allocates memory */
+ PerlLIO_write(PerlIO_fileno(Perl_error_log),
+ PL_no_mem, strlen(PL_no_mem));
+ my_exit(1);
+ }
+ exit(1);
+}
+
+/* The win32_ansipath() function takes a Unicode filename and converts it
+ * into the current Windows codepage. If some characters cannot be mapped,
+ * then it will convert the short name instead.
+ *
+ * The buffer to the ansi pathname must be freed with win32_free() when it
+ * it no longer needed.
+ *
+ * The argument to win32_ansipath() must exist before this function is
+ * called; otherwise there is no way to determine the short path name.
+ *
+ * Ideas for future refinement:
+ * - Only convert those segments of the path that are not in the current
+ * codepage, but leave the other segments in their long form.
+ * - If the resulting name is longer than MAX_PATH, start converting
+ * additional path segments into short names until the full name
+ * is shorter than MAX_PATH. Shorten the filename part last!
+ */
+DllExport char *
+win32_ansipath(const WCHAR *widename)
+{
+ char *name;
+ BOOL use_default = FALSE;
+ size_t widelen = wcslen(widename)+1;
+ int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
+ NULL, 0, NULL, NULL);
+ name = win32_malloc(len);
+ if (!name)
+ out_of_memory();
+
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
+ name, len, NULL, &use_default);
+ if (use_default) {
+ DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
+ if (shortlen) {
+ WCHAR *shortname = win32_malloc(shortlen*sizeof(WCHAR));
+ if (!shortname)
+ out_of_memory();
+ shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
+
+ len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
+ NULL, 0, NULL, NULL);
+ name = win32_realloc(name, len);
+ if (!name)
+ out_of_memory();
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
+ name, len, NULL, NULL);
+ win32_free(shortname);
+ }
+ }
+ return name;
+}
+
DllExport char *
win32_getenv(const char *name)
{
dTHX;
- WCHAR wBuffer[MAX_PATH+1];
DWORD needlen;
- SV *curitem = Nullsv;
+ SV *curitem = NULL;
- if (USING_WIDE()) {
- A2WHELPER(name, wBuffer, sizeof(wBuffer));
- needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
- }
- else
- needlen = GetEnvironmentVariableA(name,NULL,0);
+ needlen = GetEnvironmentVariableA(name,NULL,0);
if (needlen != 0) {
curitem = sv_2mortal(newSVpvn("", 0));
- if (USING_WIDE()) {
- SV *acuritem;
- do {
- SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
- needlen = GetEnvironmentVariableW(wBuffer,
- (WCHAR*)SvPVX(curitem),
- needlen);
- } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
- SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
- acuritem = sv_2mortal(newSVsv(curitem));
- W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
- }
- else {
- do {
- SvGROW(curitem, needlen+1);
- needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
- needlen);
- } while (needlen >= SvLEN(curitem));
- SvCUR_set(curitem, needlen);
- }
+ do {
+ SvGROW(curitem, needlen+1);
+ needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
+ needlen);
+ } while (needlen >= SvLEN(curitem));
+ SvCUR_set(curitem, needlen);
}
else {
/* allow any environment variables that begin with 'PERL'
if (curitem && SvCUR(curitem))
return SvPVX(curitem);
- return Nullch;
+ return NULL;
}
DllExport int
dTHX;
char* curitem;
char* val;
- WCHAR* wCuritem;
- WCHAR* wVal;
- int length, relval = -1;
+ int relval = -1;
if (name) {
- if (USING_WIDE()) {
- length = strlen(name)+1;
- New(1309,wCuritem,length,WCHAR);
- A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
- wVal = wcschr(wCuritem, '=');
- if (wVal) {
- *wVal++ = '\0';
- if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
- relval = 0;
- }
- Safefree(wCuritem);
- }
- else {
- New(1309,curitem,strlen(name)+1,char);
- strcpy(curitem, name);
- val = strchr(curitem, '=');
- if (val) {
- /* The sane way to deal with the environment.
- * Has these advantages over putenv() & co.:
- * * enables us to store a truly empty value in the
- * environment (like in UNIX).
- * * we don't have to deal with RTL globals, bugs and leaks.
- * * Much faster.
- * Why you may want to enable USE_WIN32_RTL_ENV:
- * * environ[] and RTL functions will not reflect changes,
- * which might be an issue if extensions want to access
- * the env. via RTL. This cuts both ways, since RTL will
- * not see changes made by extensions that call the Win32
- * functions directly, either.
- * GSAR 97-06-07
- */
- *val++ = '\0';
- if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
- relval = 0;
- }
- Safefree(curitem);
- }
+ Newx(curitem,strlen(name)+1,char);
+ strcpy(curitem, name);
+ val = strchr(curitem, '=');
+ if (val) {
+ /* The sane way to deal with the environment.
+ * Has these advantages over putenv() & co.:
+ * * enables us to store a truly empty value in the
+ * environment (like in UNIX).
+ * * we don't have to deal with RTL globals, bugs and leaks
+ * (specifically, see http://support.microsoft.com/kb/235601).
+ * * Much faster.
+ * Why you may want to use the RTL environment handling
+ * (previously enabled by USE_WIN32_RTL_ENV):
+ * * environ[] and RTL functions will not reflect changes,
+ * which might be an issue if extensions want to access
+ * the env. via RTL. This cuts both ways, since RTL will
+ * not see changes made by extensions that call the Win32
+ * functions directly, either.
+ * GSAR 97-06-07
+ */
+ *val++ = '\0';
+ if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
+ relval = 0;
+ }
+ Safefree(curitem);
}
return relval;
}
int ret;
DWORD attrs;
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- WCHAR* pwBuffer;
-
- A2WHELPER(filename, wBuffer, sizeof(wBuffer));
- pwBuffer = PerlDir_mapW(wBuffer);
- attrs = GetFileAttributesW(pwBuffer);
- if (attrs == 0xFFFFFFFF)
- goto fail;
- if (attrs & FILE_ATTRIBUTE_READONLY) {
- (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
- ret = _wunlink(pwBuffer);
- if (ret == -1)
- (void)SetFileAttributesW(pwBuffer, attrs);
- }
- else
- ret = _wunlink(pwBuffer);
+ filename = PerlDir_mapA(filename);
+ attrs = GetFileAttributesA(filename);
+ if (attrs == 0xFFFFFFFF) {
+ errno = ENOENT;
+ return -1;
}
- else {
- filename = PerlDir_mapA(filename);
- attrs = GetFileAttributesA(filename);
- if (attrs == 0xFFFFFFFF)
- goto fail;
- if (attrs & FILE_ATTRIBUTE_READONLY) {
- (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
- ret = unlink(filename);
- if (ret == -1)
- (void)SetFileAttributesA(filename, attrs);
- }
- else
- ret = unlink(filename);
+ if (attrs & FILE_ATTRIBUTE_READONLY) {
+ (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
+ ret = unlink(filename);
+ if (ret == -1)
+ (void)SetFileAttributesA(filename, attrs);
}
+ else
+ ret = unlink(filename);
return ret;
-fail:
- errno = ENOENT;
- return -1;
}
DllExport int
FILETIME ftAccess;
FILETIME ftWrite;
struct utimbuf TimeBuffer;
- WCHAR wbuffer[MAX_PATH+1];
- WCHAR* pwbuffer;
-
int rc;
- if (USING_WIDE()) {
- A2WHELPER(filename, wbuffer, sizeof(wbuffer));
- pwbuffer = PerlDir_mapW(wbuffer);
- rc = _wutime(pwbuffer, (struct _utimbuf*)times);
- }
- else {
- filename = PerlDir_mapA(filename);
- rc = utime(filename, times);
- }
+
+ filename = PerlDir_mapA(filename);
+ rc = utime(filename, times);
+
/* EACCES: path specifies directory or readonly file */
if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
return rc;
}
/* This will (and should) still fail on readonly files */
- if (USING_WIDE()) {
- handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- }
- else {
- handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- }
+ handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (handle == INVALID_HANDLE_VALUE)
return rc;
{
struct hostent *hep;
STRLEN nodemax = sizeof(name->nodename)-1;
- OSVERSIONINFO osver;
-
- memset(&osver, 0, sizeof(OSVERSIONINFO));
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (GetVersionEx(&osver)) {
- /* sysname */
- switch (osver.dwPlatformId) {
- case VER_PLATFORM_WIN32_WINDOWS:
- strcpy(name->sysname, "Windows");
- break;
- case VER_PLATFORM_WIN32_NT:
- strcpy(name->sysname, "Windows NT");
- break;
- case VER_PLATFORM_WIN32s:
- strcpy(name->sysname, "Win32s");
- break;
- default:
- strcpy(name->sysname, "Win32 Unknown");
- break;
- }
- /* release */
- sprintf(name->release, "%d.%d",
- osver.dwMajorVersion, osver.dwMinorVersion);
-
- /* version */
- sprintf(name->version, "Build %d",
- osver.dwPlatformId == VER_PLATFORM_WIN32_NT
- ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
- if (osver.szCSDVersion[0]) {
- char *buf = name->version + strlen(name->version);
- sprintf(buf, " (%s)", osver.szCSDVersion);
- }
+ /* sysname */
+ switch (g_osver.dwPlatformId) {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ strcpy(name->sysname, "Windows");
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ strcpy(name->sysname, "Windows NT");
+ break;
+ case VER_PLATFORM_WIN32s:
+ strcpy(name->sysname, "Win32s");
+ break;
+ default:
+ strcpy(name->sysname, "Win32 Unknown");
+ break;
}
- else {
- *name->sysname = '\0';
- *name->version = '\0';
- *name->release = '\0';
+
+ /* release */
+ sprintf(name->release, "%d.%d",
+ g_osver.dwMajorVersion, g_osver.dwMinorVersion);
+
+ /* version */
+ sprintf(name->version, "Build %d",
+ g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
+ ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
+ if (g_osver.szCSDVersion[0]) {
+ char *buf = name->version + strlen(name->version);
+ sprintf(buf, " (%s)", g_osver.szCSDVersion);
}
/* nodename */
win32_async_check(pTHX)
{
MSG msg;
- int ours = 1;
- /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
- * and ignores window messages - should co-exist better with windows apps e.g. Tk
- */
- while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
- int sig;
- switch(msg.message) {
-
-#if 0
- /* Perhaps some other messages could map to signals ? ... */
- case WM_CLOSE:
- case WM_QUIT:
- /* Treat WM_QUIT like SIGHUP? */
- sig = SIGHUP;
- goto Raise;
- break;
-#endif
+ HWND hwnd = w32_message_hwnd;
- /* We use WM_USER to fake kill() with other signals */
- case WM_USER: {
- sig = msg.wParam;
- Raise:
- if (do_raise(aTHX_ sig)) {
- sig_terminate(aTHX_ sig);
- }
- break;
- }
+ /* Reset w32_poll_count before doing anything else, incase we dispatch
+ * messages that end up calling back into perl */
+ w32_poll_count = 0;
- case WM_TIMER: {
- /* alarm() is a one-shot but SetTimer() repeats so kill it */
- if (w32_timerid && w32_timerid==msg.wParam) {
- KillTimer(NULL,w32_timerid);
- w32_timerid=0;
- }
- else
- goto FallThrough;
- /* Now fake a call to signal handler */
- if (do_raise(aTHX_ 14)) {
- sig_terminate(aTHX_ 14);
- }
- break;
- }
+ if (hwnd != INVALID_HANDLE_VALUE) {
+ /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
+ * and ignores window messages - should co-exist better with windows apps e.g. Tk
+ */
+ if (hwnd == NULL)
+ hwnd = (HWND)-1;
+
+ while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
+ PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
+ {
+ /* re-post a WM_QUIT message (we'll mark it as read later) */
+ if(msg.message == WM_QUIT) {
+ PostQuitMessage((int)msg.wParam);
+ break;
+ }
- /* Otherwise do normal Win32 thing - in case it is useful */
- default:
- FallThrough:
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- ours = 0;
- break;
- }
+ if(!CallMsgFilter(&msg, MSGF_USER))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
}
- w32_poll_count = 0;
+
+ /* Call PeekMessage() to mark all pending messages in the queue as "old".
+ * This is necessary when we are being called by win32_msgwait() to
+ * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
+ * message over and over. An example how this can happen is when
+ * Perl is calling win32_waitpid() inside a GUI application and the GUI
+ * is generating messages before the process terminated.
+ */
+ PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
/* Above or other stuff may have set a signal flag */
- if (PL_sig_pending) {
- despatch_signals();
- }
- return ours;
+ if (PL_sig_pending)
+ despatch_signals();
+
+ return 1;
}
/* This function will not return until the timeout has elapsed, or until
timeout += ticks;
}
while (1) {
- DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
+ DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
if (resultp)
*resultp = result;
if (result == WAIT_TIMEOUT) {
* one of the supported codes in <signal.h>
*/
dTHX;
+
+ if (w32_message_hwnd == INVALID_HANDLE_VALUE)
+ w32_message_hwnd = win32_create_message_window();
+
if (sec) {
- w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL);
+ if (w32_message_hwnd == NULL)
+ w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
+ else {
+ w32_timerid = 1;
+ SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
+ }
}
else {
if (w32_timerid) {
- KillTimer(NULL,w32_timerid);
- w32_timerid=0;
+ KillTimer(w32_message_hwnd, w32_timerid);
+ w32_timerid = 0;
}
}
return 0;
return des_fcrypt(txt, salt, w32_crypt_buffer);
#else
Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
- return Nullch;
+ return NULL;
#endif
}
}
DllExport FILE *
-win32_stdout()
+win32_stdout(void)
{
return (stdout);
}
win32_fopen(const char *filename, const char *mode)
{
dTHX;
- WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
FILE *f;
if (!*filename)
if (stricmp(filename, "/dev/null")==0)
filename = "NUL";
- if (USING_WIDE()) {
- A2WHELPER(mode, wMode, sizeof(wMode));
- A2WHELPER(filename, wBuffer, sizeof(wBuffer));
- f = _wfopen(PerlDir_mapW(wBuffer), wMode);
- }
- else
- f = fopen(PerlDir_mapA(filename), mode);
+ f = fopen(PerlDir_mapA(filename), mode);
/* avoid buffering headaches for child processes */
if (f && *mode == 'a')
win32_fseek(f, 0, SEEK_END);
win32_fdopen(int handle, const char *mode)
{
dTHX;
- WCHAR wMode[MODE_SIZE];
FILE *f;
- if (USING_WIDE()) {
- A2WHELPER(mode, wMode, sizeof(wMode));
- f = _wfdopen(handle, wMode);
- }
- else
- f = fdopen(handle, (char *) mode);
+ f = fdopen(handle, (char *) mode);
/* avoid buffering headaches for child processes */
if (f && *mode == 'a')
win32_fseek(f, 0, SEEK_END);
win32_freopen(const char *path, const char *mode, FILE *stream)
{
dTHX;
- WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
if (stricmp(path, "/dev/null")==0)
path = "NUL";
- if (USING_WIDE()) {
- A2WHELPER(mode, wMode, sizeof(wMode));
- A2WHELPER(path, wBuffer, sizeof(wBuffer));
- return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
- }
return freopen(PerlDir_mapA(path), mode, stream);
}
win32_ftell(FILE *pf)
{
#if defined(WIN64) || defined(USE_LARGE_FILES)
-#if defined(__BORLAND__) /* buk */
+#if defined(__BORLANDC__) /* buk */
return win32_tell( fileno( pf ) );
#else
fpos_t pos;
return fsetpos(pf, &offset);
#endif
#else
- return fseek(pf, offset, origin);
+ return fseek(pf, (long)offset, origin);
#endif
}
* for write operations, probably because it is opened for reading.
* --Vadim Konovalov
*/
- int rc = fstat(fd,sbufptr);
BY_HANDLE_FILE_INFORMATION bhfi;
+#if defined(WIN64) || defined(USE_LARGE_FILES)
+ /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
+ struct stat tmp;
+ int rc = fstat(fd,&tmp);
+
+ sbufptr->st_dev = tmp.st_dev;
+ sbufptr->st_ino = tmp.st_ino;
+ sbufptr->st_mode = tmp.st_mode;
+ sbufptr->st_nlink = tmp.st_nlink;
+ sbufptr->st_uid = tmp.st_uid;
+ sbufptr->st_gid = tmp.st_gid;
+ sbufptr->st_rdev = tmp.st_rdev;
+ sbufptr->st_size = tmp.st_size;
+ sbufptr->st_atime = tmp.st_atime;
+ sbufptr->st_mtime = tmp.st_mtime;
+ sbufptr->st_ctime = tmp.st_ctime;
+#else
+ int rc = fstat(fd,sbufptr);
+#endif
+
if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
+#if defined(WIN64) || defined(USE_LARGE_FILES)
+ sbufptr->st_size = ((__int64)bhfi.nFileSizeHigh << 32) | bhfi.nFileSizeLow ;
+#endif
sbufptr->st_mode &= 0xFE00;
if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
if (win32_pipe(p, 512, ourmode) == -1)
return NULL;
- /* save current stdfd */
- if ((oldfd = win32_dup(stdfd)) == -1)
- goto cleanup;
-
/* save the old std handle (this needs to happen before the
* dup2(), since that might call SetStdHandle() too) */
OP_REFCNT_LOCK;
lock_held = 1;
old_h = GetStdHandle(nhandle);
+ /* save current stdfd */
+ if ((oldfd = win32_dup(stdfd)) == -1)
+ goto cleanup;
+
/* make stdfd go to child end of pipe (implicitly closes stdfd) */
/* stdfd will be inherited by the child */
if (win32_dup2(p[child], stdfd) == -1)
if (win32_dup2(oldfd, stdfd) == -1)
goto cleanup;
+ /* close saved handle */
+ win32_close(oldfd);
+
/* restore the old std handle (this needs to happen after the
* dup2(), since that might call SetStdHandle() too */
if (lock_held) {
lock_held = 0;
}
- /* close saved handle */
- win32_close(oldfd);
-
- LOCK_FDPID_MUTEX;
sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
- UNLOCK_FDPID_MUTEX;
/* set process id so that it can be returned by perl's open() */
PL_forkprocess = childpid;
/* we don't need to check for errors here */
win32_close(p[0]);
win32_close(p[1]);
+ if (oldfd != -1) {
+ win32_dup2(oldfd, stdfd);
+ win32_close(oldfd);
+ }
if (lock_held) {
SetStdHandle(nhandle, old_h);
OP_REFCNT_UNLOCK;
lock_held = 0;
}
- if (oldfd != -1) {
- win32_dup2(oldfd, stdfd);
- win32_close(oldfd);
- }
return (NULL);
#endif /* USE_RTL_POPEN */
int childpid, status;
SV *sv;
- LOCK_FDPID_MUTEX;
sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
if (SvIOK(sv))
fclose(pf);
#endif
SvIVX(sv) = 0;
- UNLOCK_FDPID_MUTEX;
if (win32_waitpid(childpid, &status, 0) == -1)
return -1;
if (pfnCreateHardLinkW == NULL)
pfnCreateHardLinkW = Nt4CreateHardLinkW;
- if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
- (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
+ if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
+ MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
(wcscpy(wOldName, PerlDir_mapW(wOldName)),
- pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
+ pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
{
return 0;
}
DllExport int
win32_rename(const char *oname, const char *newname)
{
- WCHAR wOldName[MAX_PATH+1];
- WCHAR wNewName[MAX_PATH+1];
char szOldName[MAX_PATH+1];
char szNewName[MAX_PATH+1];
BOOL bResult;
*/
if (IsWinNT()) {
DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
- if (USING_WIDE()) {
- A2WHELPER(oname, wOldName, sizeof(wOldName));
- A2WHELPER(newname, wNewName, sizeof(wNewName));
- if (wcsicmp(wNewName, wOldName))
- dwFlags |= MOVEFILE_REPLACE_EXISTING;
- wcscpy(wOldName, PerlDir_mapW(wOldName));
- bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
- }
- else {
- if (stricmp(newname, oname))
- dwFlags |= MOVEFILE_REPLACE_EXISTING;
- strcpy(szOldName, PerlDir_mapA(oname));
- bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
- }
+ if (stricmp(newname, oname))
+ dwFlags |= MOVEFILE_REPLACE_EXISTING;
+ strcpy(szOldName, PerlDir_mapA(oname));
+ bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
if (!bResult) {
DWORD err = GetLastError();
switch (err) {
int retval = 0;
char szTmpName[MAX_PATH+1];
char dname[MAX_PATH+1];
- char *endname = Nullch;
+ char *endname = NULL;
STRLEN tmplen = 0;
DWORD from_attr, to_attr;
retval = rename(szOldName, szNewName);
/* if we created a temporary file before ... */
- if (endname != Nullch) {
+ if (endname != NULL) {
/* ...and rename succeeded, delete temporary file/directory */
if (retval == 0)
DeleteFile(szTmpName);
win32_lseek(fd, cur, SEEK_SET);
return retval;
#else
- return chsize(fd, size);
+ return chsize(fd, (long)size);
#endif
}
return _lseeki64(fd, offset, origin);
#endif
#else
- return lseek(fd, offset, origin);
+ return lseek(fd, (long)offset, origin);
#endif
}
dTHX;
va_list ap;
int pmode;
- WCHAR wBuffer[MAX_PATH+1];
va_start(ap, flag);
pmode = va_arg(ap, int);
if (stricmp(path, "/dev/null")==0)
path = "NUL";
- if (USING_WIDE()) {
- A2WHELPER(path, wBuffer, sizeof(wBuffer));
- return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
- }
return open(PerlDir_mapA(path), flag, pmode);
}
win32_mkdir(const char *dir, int mode)
{
dTHX;
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- A2WHELPER(dir, wBuffer, sizeof(wBuffer));
- return _wmkdir(PerlDir_mapW(wBuffer));
- }
return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
}
win32_rmdir(const char *dir)
{
dTHX;
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- A2WHELPER(dir, wBuffer, sizeof(wBuffer));
- return _wrmdir(PerlDir_mapW(wBuffer));
- }
return rmdir(PerlDir_mapA(dir));
}
errno = ENOENT;
return -1;
}
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- A2WHELPER(dir, wBuffer, sizeof(wBuffer));
- return _wchdir(wBuffer);
- }
return chdir(dir);
}
win32_access(const char *path, int mode)
{
dTHX;
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- A2WHELPER(path, wBuffer, sizeof(wBuffer));
- return _waccess(PerlDir_mapW(wBuffer), mode);
- }
return access(PerlDir_mapA(path), mode);
}
win32_chmod(const char *path, int mode)
{
dTHX;
- if (USING_WIDE()) {
- WCHAR wBuffer[MAX_PATH+1];
- A2WHELPER(path, wBuffer, sizeof(wBuffer));
- return _wchmod(PerlDir_mapW(wBuffer), mode);
- }
return chmod(PerlDir_mapA(path), mode);
}
DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
argc = index;
- New(1310, cmd, len, char);
+ Newx(cmd, len, char);
ptr = cmd;
if (bat_file && !IsWin95()) {
int has_slash = 0;
if (!cmd)
- return Nullch;
+ return NULL;
fullcmd = (char*)cmd;
while (*fullcmd) {
if (*fullcmd == '/' || *fullcmd == '\\')
/* worst case: PATH is a single directory; we need additional space
* to append "/", ".exe" and trailing "\0" */
- New(0, fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
+ Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
curfullcmd = fullcmd;
while (1) {
}
Safefree(fullcmd);
- return Nullch;
+ return NULL;
}
/* The following are just place holders.
{
dTHX;
char* ptr;
- char szfilename[(MAX_PATH+1)*2];
- if (USING_WIDE()) {
- WCHAR wfilename[MAX_PATH+1];
- GetCurrentDirectoryW(MAX_PATH+1, wfilename);
- W2AHELPER(wfilename, szfilename, sizeof(szfilename));
- }
- else {
- GetCurrentDirectoryA(MAX_PATH+1, szfilename);
- }
+ char szfilename[MAX_PATH+1];
- New(0, ptr, strlen(szfilename)+1, char);
+ GetCurrentDirectoryA(MAX_PATH+1, szfilename);
+ Newx(ptr, strlen(szfilename)+1, char);
strcpy(ptr, szfilename);
return ptr;
}
PROCESS_INFORMATION ProcessInformation;
DWORD create = 0;
char *cmd;
- char *fullcmd = Nullch;
+ char *fullcmd = NULL;
char *cname = (char *)cmdname;
STRLEN clen = 0;
/* if command name contains dquotes, must remove them */
if (strchr(cname, '"')) {
cmd = cname;
- New(0,cname,clen+1,char);
+ Newx(cname,clen+1,char);
clen = 0;
while (*cmd) {
if (*cmd != '"') {
/* if this is a pseudo-forked child, we just want to spawn
* the new program, and return */
if (w32_pseudo_id)
+# ifdef __BORLANDC__
return spawnv(P_WAIT, cmdname, (char *const *)argv);
+# else
+ return spawnv(P_WAIT, cmdname, argv);
+# endif
#endif
+#ifdef __BORLANDC__
return execv(cmdname, (char *const *)argv);
+#else
+ return execv(cmdname, argv);
+#endif
}
DllExport int
return status;
}
#endif
+#ifdef __BORLANDC__
return execvp(cmdname, (char *const *)argv);
+#else
+ return execvp(cmdname, argv);
+#endif
}
DllExport void
win32_dynaload(const char* filename)
{
dTHX;
- HMODULE hModule;
char buf[MAX_PATH+1];
char *first;
filename = buf;
}
}
- if (USING_WIDE()) {
- WCHAR wfilename[MAX_PATH+1];
- A2WHELPER(filename, wfilename, sizeof(wfilename));
- hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- }
- else {
- hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- }
- return hModule;
+ return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
}
-/*
- * Extras.
- */
-
-static
XS(w32_SetChildShowWindow)
{
dXSARGS;
XSRETURN(1);
}
-static
-XS(w32_GetCwd)
-{
- dXSARGS;
- /* Make the host for current directory */
- char* ptr = PerlEnv_get_childdir();
- /*
- * If ptr != Nullch
- * then it worked, set PV valid,
- * else return 'undef'
- */
- if (ptr) {
- SV *sv = sv_newmortal();
- sv_setpv(sv, ptr);
- PerlEnv_free_childdir(ptr);
-
-#ifndef INCOMPLETE_TAINTS
- SvTAINTED_on(sv);
-#endif
-
- EXTEND(SP,1);
- SvPOK_on(sv);
- ST(0) = sv;
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_SetCwd)
-{
- dXSARGS;
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
- if (!PerlDir_chdir(SvPV_nolen(ST(0))))
- XSRETURN_YES;
-
- XSRETURN_NO;
-}
-
-static
-XS(w32_GetNextAvailDrive)
-{
- dXSARGS;
- char ix = 'C';
- char root[] = "_:\\";
-
- EXTEND(SP,1);
- while (ix <= 'Z') {
- root[0] = ix++;
- if (GetDriveType(root) == 1) {
- root[2] = '\0';
- XSRETURN_PV(root);
- }
- }
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_GetLastError)
-{
- dXSARGS;
- EXTEND(SP,1);
- XSRETURN_IV(GetLastError());
-}
-
-static
-XS(w32_SetLastError)
-{
- dXSARGS;
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
- SetLastError(SvIV(ST(0)));
- XSRETURN_EMPTY;
-}
-
-static
-XS(w32_LoginName)
-{
- dXSARGS;
- char *name = w32_getlogin_buffer;
- DWORD size = sizeof(w32_getlogin_buffer);
- EXTEND(SP,1);
- if (GetUserName(name,&size)) {
- /* size includes NULL */
- ST(0) = sv_2mortal(newSVpvn(name,size-1));
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_NodeName)
-{
- dXSARGS;
- char name[MAX_COMPUTERNAME_LENGTH+1];
- DWORD size = sizeof(name);
- EXTEND(SP,1);
- if (GetComputerName(name,&size)) {
- /* size does NOT include NULL :-( */
- ST(0) = sv_2mortal(newSVpvn(name,size));
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
-}
-
-
-static
-XS(w32_DomainName)
-{
- dXSARGS;
- HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
- DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
- DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
- void *bufptr);
-
- if (hNetApi32) {
- pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
- GetProcAddress(hNetApi32, "NetApiBufferFree");
- pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
- GetProcAddress(hNetApi32, "NetWkstaGetInfo");
- }
- EXTEND(SP,1);
- if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
- /* this way is more reliable, in case user has a local account. */
- char dname[256];
- DWORD dnamelen = sizeof(dname);
- struct {
- DWORD wki100_platform_id;
- LPWSTR wki100_computername;
- LPWSTR wki100_langroup;
- DWORD wki100_ver_major;
- DWORD wki100_ver_minor;
- } *pwi;
- /* NERR_Success *is* 0*/
- if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
- if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
- WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup,
- -1, (LPSTR)dname, dnamelen, NULL, NULL);
- }
- else {
- WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername,
- -1, (LPSTR)dname, dnamelen, NULL, NULL);
- }
- pfnNetApiBufferFree(pwi);
- FreeLibrary(hNetApi32);
- XSRETURN_PV(dname);
- }
- FreeLibrary(hNetApi32);
- }
- else {
- /* Win95 doesn't have NetWksta*(), so do it the old way */
- char name[256];
- DWORD size = sizeof(name);
- if (hNetApi32)
- FreeLibrary(hNetApi32);
- if (GetUserName(name,&size)) {
- char sid[ONE_K_BUFSIZE];
- DWORD sidlen = sizeof(sid);
- char dname[256];
- DWORD dnamelen = sizeof(dname);
- SID_NAME_USE snu;
- if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
- dname, &dnamelen, &snu)) {
- XSRETURN_PV(dname); /* all that for this */
- }
- }
- }
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_FsType)
-{
- dXSARGS;
- char fsname[256];
- DWORD flags, filecomplen;
- if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
- &flags, fsname, sizeof(fsname))) {
- if (GIMME_V == G_ARRAY) {
- XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
- XPUSHs(sv_2mortal(newSViv(flags)));
- XPUSHs(sv_2mortal(newSViv(filecomplen)));
- PUTBACK;
- return;
- }
- EXTEND(SP,1);
- XSRETURN_PV(fsname);
- }
- XSRETURN_EMPTY;
-}
-
-static
-XS(w32_GetOSVersion)
-{
- dXSARGS;
- /* Use explicit struct definition because wSuiteMask and
- * wProductType are not defined in the VC++ 6.0 headers.
- * WORD type has been replaced by unsigned short because
- * WORD is already used by Perl itself.
- */
- struct {
- DWORD dwOSVersionInfoSize;
- DWORD dwMajorVersion;
- DWORD dwMinorVersion;
- DWORD dwBuildNumber;
- DWORD dwPlatformId;
- CHAR szCSDVersion[128];
- unsigned short wServicePackMajor;
- unsigned short wServicePackMinor;
- unsigned short wSuiteMask;
- BYTE wProductType;
- BYTE wReserved;
- } osver;
- BOOL bEx = TRUE;
-
- if (USING_WIDE()) {
- struct {
- DWORD dwOSVersionInfoSize;
- DWORD dwMajorVersion;
- DWORD dwMinorVersion;
- DWORD dwBuildNumber;
- DWORD dwPlatformId;
- WCHAR szCSDVersion[128];
- unsigned short wServicePackMajor;
- unsigned short wServicePackMinor;
- unsigned short wSuiteMask;
- BYTE wProductType;
- BYTE wReserved;
- } osverw;
- char szCSDVersion[sizeof(osverw.szCSDVersion)];
- osverw.dwOSVersionInfoSize = sizeof(osverw);
- if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
- bEx = FALSE;
- osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
- if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
- XSRETURN_EMPTY;
- }
- }
- if (GIMME_V == G_SCALAR) {
- XSRETURN_IV(osverw.dwPlatformId);
- }
- W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
- XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
- osver.dwMajorVersion = osverw.dwMajorVersion;
- osver.dwMinorVersion = osverw.dwMinorVersion;
- osver.dwBuildNumber = osverw.dwBuildNumber;
- osver.dwPlatformId = osverw.dwPlatformId;
- osver.wServicePackMajor = osverw.wServicePackMajor;
- osver.wServicePackMinor = osverw.wServicePackMinor;
- osver.wSuiteMask = osverw.wSuiteMask;
- osver.wProductType = osverw.wProductType;
- }
- else {
- osver.dwOSVersionInfoSize = sizeof(osver);
- if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
- bEx = FALSE;
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
- XSRETURN_EMPTY;
- }
- }
- if (GIMME_V == G_SCALAR) {
- XSRETURN_IV(osver.dwPlatformId);
- }
- XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
- }
- XPUSHs(newSViv(osver.dwMajorVersion));
- XPUSHs(newSViv(osver.dwMinorVersion));
- XPUSHs(newSViv(osver.dwBuildNumber));
- XPUSHs(newSViv(osver.dwPlatformId));
- if (bEx) {
- XPUSHs(newSViv(osver.wServicePackMajor));
- XPUSHs(newSViv(osver.wServicePackMinor));
- XPUSHs(newSViv(osver.wSuiteMask));
- XPUSHs(newSViv(osver.wProductType));
- }
- PUTBACK;
-}
-
-static
-XS(w32_IsWinNT)
-{
- dXSARGS;
- EXTEND(SP,1);
- XSRETURN_IV(IsWinNT());
-}
-
-static
-XS(w32_IsWin95)
-{
- dXSARGS;
- EXTEND(SP,1);
- XSRETURN_IV(IsWin95());
-}
-
-static
-XS(w32_FormatMessage)
-{
- dXSARGS;
- DWORD source = 0;
- char msgbuf[ONE_K_BUFSIZE];
-
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
-
- if (USING_WIDE()) {
- WCHAR wmsgbuf[ONE_K_BUFSIZE];
- if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
- &source, SvIV(ST(0)), 0,
- wmsgbuf, ONE_K_BUFSIZE-1, NULL))
- {
- W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
- XSRETURN_PV(msgbuf);
- }
- }
- else {
- if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
- &source, SvIV(ST(0)), 0,
- msgbuf, sizeof(msgbuf)-1, NULL))
- XSRETURN_PV(msgbuf);
- }
-
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_Spawn)
-{
- dXSARGS;
- char *cmd, *args;
- void *env;
- char *dir;
- PROCESS_INFORMATION stProcInfo;
- STARTUPINFO stStartInfo;
- BOOL bSuccess = FALSE;
-
- if (items != 3)
- Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
-
- cmd = SvPV_nolen(ST(0));
- args = SvPV_nolen(ST(1));
-
- env = PerlEnv_get_childenv();
- dir = PerlEnv_get_childdir();
-
- memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
- stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
- stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
- stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
-
- if (CreateProcess(
- cmd, /* Image path */
- args, /* Arguments for command line */
- NULL, /* Default process security */
- NULL, /* Default thread security */
- FALSE, /* Must be TRUE to use std handles */
- NORMAL_PRIORITY_CLASS, /* No special scheduling */
- env, /* Inherit our environment block */
- dir, /* Inherit our currrent directory */
- &stStartInfo, /* -> Startup info */
- &stProcInfo)) /* <- Process info (if OK) */
- {
- int pid = (int)stProcInfo.dwProcessId;
- if (IsWin95() && pid < 0)
- pid = -pid;
- sv_setiv(ST(2), pid);
- CloseHandle(stProcInfo.hThread);/* library source code does this. */
- bSuccess = TRUE;
- }
- PerlEnv_free_childenv(env);
- PerlEnv_free_childdir(dir);
- XSRETURN_IV(bSuccess);
-}
-
-static
-XS(w32_GetTickCount)
-{
- dXSARGS;
- DWORD msec = GetTickCount();
- EXTEND(SP,1);
- if ((IV)msec > 0)
- XSRETURN_IV(msec);
- XSRETURN_NV(msec);
-}
-
-static
-XS(w32_GetShortPathName)
-{
- dXSARGS;
- SV *shortpath;
- DWORD len;
-
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
-
- shortpath = sv_mortalcopy(ST(0));
- SvUPGRADE(shortpath, SVt_PV);
- if (!SvPVX(shortpath) || !SvLEN(shortpath))
- XSRETURN_UNDEF;
-
- /* src == target is allowed */
- do {
- len = GetShortPathName(SvPVX(shortpath),
- SvPVX(shortpath),
- SvLEN(shortpath));
- } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
- if (len) {
- SvCUR_set(shortpath,len);
- *SvEND(shortpath) = '\0';
- ST(0) = shortpath;
- XSRETURN(1);
- }
- XSRETURN_UNDEF;
-}
-
-static
-XS(w32_GetFullPathName)
-{
- dXSARGS;
- SV *filename;
- SV *fullpath;
- char *filepart;
- DWORD len;
- STRLEN filename_len;
- char *filename_p;
-
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
-
- filename = ST(0);
- filename_p = SvPV(filename, filename_len);
- fullpath = sv_2mortal(newSVpvn(filename_p, filename_len));
- if (!SvPVX(fullpath) || !SvLEN(fullpath))
- XSRETURN_UNDEF;
-
- do {
- len = GetFullPathName(SvPVX(filename),
- SvLEN(fullpath),
- SvPVX(fullpath),
- &filepart);
- } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
- if (len) {
- if (GIMME_V == G_ARRAY) {
- EXTEND(SP,1);
- if (filepart) {
- XST_mPV(1,filepart);
- len = filepart - SvPVX(fullpath);
- }
- else {
- XST_mPVN(1,"",0);
- }
- items = 2;
- }
- SvCUR_set(fullpath,len);
- *SvEND(fullpath) = '\0';
- ST(0) = fullpath;
- XSRETURN(items);
- }
- XSRETURN_EMPTY;
-}
-
-static
-XS(w32_GetLongPathName)
-{
- dXSARGS;
- SV *path;
- char tmpbuf[MAX_PATH+1];
- char *pathstr;
- STRLEN len;
-
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
-
- path = ST(0);
- pathstr = SvPV(path,len);
- strcpy(tmpbuf, pathstr);
- pathstr = win32_longpath(tmpbuf);
- if (pathstr) {
- ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
- XSRETURN(1);
- }
- XSRETURN_EMPTY;
-}
-
-static
-XS(w32_Sleep)
-{
- dXSARGS;
- if (items != 1)
- Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
- Sleep(SvIV(ST(0)));
- XSRETURN_YES;
-}
-
-static
-XS(w32_CopyFile)
-{
- dXSARGS;
- BOOL bResult;
- if (items != 3)
- Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
- if (USING_WIDE()) {
- WCHAR wSourceFile[MAX_PATH+1];
- WCHAR wDestFile[MAX_PATH+1];
- A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
- wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
- A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
- bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
- }
- else {
- char szSourceFile[MAX_PATH+1];
- strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
- bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
- }
-
- if (bResult)
- XSRETURN_YES;
- XSRETURN_NO;
-}
-
void
Perl_init_os_extras(void)
{
dTHX;
char *file = __FILE__;
- dXSUB_SYS;
-
- /* these names are Activeware compatible */
- newXS("Win32::GetCwd", w32_GetCwd, file);
- newXS("Win32::SetCwd", w32_SetCwd, file);
- newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
- newXS("Win32::GetLastError", w32_GetLastError, file);
- newXS("Win32::SetLastError", w32_SetLastError, file);
- newXS("Win32::LoginName", w32_LoginName, file);
- newXS("Win32::NodeName", w32_NodeName, file);
- newXS("Win32::DomainName", w32_DomainName, file);
- newXS("Win32::FsType", w32_FsType, file);
- newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
- newXS("Win32::IsWinNT", w32_IsWinNT, file);
- newXS("Win32::IsWin95", w32_IsWin95, file);
- newXS("Win32::FormatMessage", w32_FormatMessage, file);
- newXS("Win32::Spawn", w32_Spawn, file);
- newXS("Win32::GetTickCount", w32_GetTickCount, file);
- newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
- newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
- newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
- newXS("Win32::CopyFile", w32_CopyFile, file);
- newXS("Win32::Sleep", w32_Sleep, file);
- newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
- /* XXX Bloat Alert! The following Activeware preloads really
- * ought to be part of Win32::Sys::*, so they're not included
- * here.
- */
- /* LookupAccountName
- * LookupAccountSID
- * InitiateSystemShutdown
- * AbortSystemShutdown
- * ExpandEnvrironmentStrings
- */
+ /* Initialize Win32CORE if it has been statically linked. */
+ void (*pfn_init)(pTHX);
+#if defined(__BORLANDC__)
+ /* makedef.pl seems to have given up on fixing this issue in the .def file */
+ pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "_init_Win32CORE");
+#else
+ pfn_init = (void (*)(pTHX))GetProcAddress((HMODULE)w32_perldll_handle, "init_Win32CORE");
+#endif
+ if (pfn_init)
+ pfn_init(aTHX);
+
+ newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
}
void *
}
+#ifdef SET_INVALID_PARAMETER_HANDLER
+# include <crtdbg.h>
+#endif
+
+static void
+ansify_path(void)
+{
+ size_t len;
+ char *ansi_path;
+ WCHAR *wide_path;
+ WCHAR *wide_dir;
+
+ /* win32_ansipath() requires Windows 2000 or later */
+ if (!IsWin2000())
+ return;
+
+ /* fetch Unicode version of PATH */
+ len = 2000;
+ wide_path = win32_malloc(len*sizeof(WCHAR));
+ while (wide_path) {
+ size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
+ if (newlen < len)
+ break;
+ len = newlen;
+ wide_path = win32_realloc(wide_path, len*sizeof(WCHAR));
+ }
+ if (!wide_path)
+ return;
+
+ /* convert to ANSI pathnames */
+ wide_dir = wide_path;
+ ansi_path = NULL;
+ while (wide_dir) {
+ WCHAR *sep = wcschr(wide_dir, ';');
+ char *ansi_dir;
+ size_t ansi_len;
+ size_t wide_len;
+
+ if (sep)
+ *sep++ = '\0';
+
+ /* remove quotes around pathname */
+ if (*wide_dir == '"')
+ ++wide_dir;
+ wide_len = wcslen(wide_dir);
+ if (wide_len && wide_dir[wide_len-1] == '"')
+ wide_dir[wide_len-1] = '\0';
+
+ /* append ansi_dir to ansi_path */
+ ansi_dir = win32_ansipath(wide_dir);
+ ansi_len = strlen(ansi_dir);
+ if (ansi_path) {
+ size_t newlen = len + 1 + ansi_len;
+ ansi_path = win32_realloc(ansi_path, newlen+1);
+ if (!ansi_path)
+ break;
+ ansi_path[len] = ';';
+ memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
+ len = newlen;
+ }
+ else {
+ len = ansi_len;
+ ansi_path = win32_malloc(5+len+1);
+ if (!ansi_path)
+ break;
+ memcpy(ansi_path, "PATH=", 5);
+ memcpy(ansi_path+5, ansi_dir, len+1);
+ len += 5;
+ }
+ win32_free(ansi_dir);
+ wide_dir = sep;
+ }
+
+ if (ansi_path) {
+ /* Update C RTL environ array. This will only have full effect if
+ * perl_parse() is later called with `environ` as the `env` argument.
+ * Otherwise S_init_postdump_symbols() will overwrite PATH again.
+ *
+ * We do have to ansify() the PATH before Perl has been fully
+ * initialized because S_find_script() uses the PATH when perl
+ * is being invoked with the -S option. This happens before %ENV
+ * is initialized in S_init_postdump_symbols().
+ *
+ * XXX Is this a bug? Should S_find_script() use the environment
+ * XXX passed in the `env` arg to parse_perl()?
+ */
+ putenv(ansi_path);
+ /* Keep system environment in sync because S_init_postdump_symbols()
+ * will not call mg_set() if it initializes %ENV from `environ`.
+ */
+ SetEnvironmentVariableA("PATH", ansi_path+5);
+ /* We are intentionally leaking the ansi_path string here because
+ * the Borland runtime library puts it directly into the environ
+ * array. The Microsoft runtime library seems to make a copy,
+ * but will leak the copy should it be replaced again later.
+ * Since this code is only called once during PERL_SYS_INIT this
+ * shouldn't really matter.
+ */
+ }
+ win32_free(wide_path);
+}
+
void
Perl_win32_init(int *argcp, char ***argvp)
{
+ HMODULE module;
+
+#ifdef SET_INVALID_PARAMETER_HANDLER
+ _invalid_parameter_handler oldHandler, newHandler;
+ newHandler = my_invalid_parameter_handler;
+ oldHandler = _set_invalid_parameter_handler(newHandler);
+ _CrtSetReportMode(_CRT_ASSERT, 0);
+#endif
/* Disable floating point errors, Perl will trap the ones we
* care about. VC++ RTL defaults to switching these off
* already, but the Borland RTL doesn't. Since we don't
_control87(MCW_EM, MCW_EM);
#endif
MALLOC_INIT;
+
+ module = GetModuleHandle("ntdll.dll");
+ if (module) {
+ *(FARPROC*)&pfnZwQuerySystemInformation = GetProcAddress(module, "ZwQuerySystemInformation");
+ }
+
+ module = GetModuleHandle("kernel32.dll");
+ if (module) {
+ *(FARPROC*)&pfnCreateToolhelp32Snapshot = GetProcAddress(module, "CreateToolhelp32Snapshot");
+ *(FARPROC*)&pfnProcess32First = GetProcAddress(module, "Process32First");
+ *(FARPROC*)&pfnProcess32Next = GetProcAddress(module, "Process32Next");
+ }
+
+ g_osver.dwOSVersionInfoSize = sizeof(g_osver);
+ GetVersionEx(&g_osver);
+
+ ansify_path();
}
void
Perl_win32_term(void)
{
+ dTHX;
+ HINTS_REFCNT_TERM;
OP_REFCNT_TERM;
+ PERLIO_TERM;
MALLOC_TERM;
}
}
}
+/* The PerlMessageWindowClass's WindowProc */
+LRESULT CALLBACK
+win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return win32_process_message(hwnd, msg, wParam, lParam) ?
+ 0 : DefWindowProc(hwnd, msg, wParam, lParam);
+}
-#ifdef HAVE_INTERP_INTERN
+/* we use a message filter hook to process thread messages, passing any
+ * messages that we don't process on to the rest of the hook chain
+ * Anyone else writing a message loop that wants to play nicely with perl
+ * should do
+ * CallMsgFilter(&msg, MSGF_***);
+ * between their GetMessage and DispatchMessage calls. */
+LRESULT CALLBACK
+win32_message_filter_proc(int code, WPARAM wParam, LPARAM lParam) {
+ LPMSG pmsg = (LPMSG)lParam;
+
+ /* we'll process it if code says we're allowed, and it's a thread message */
+ if (code >= 0 && pmsg->hwnd == NULL
+ && win32_process_message(pmsg->hwnd, pmsg->message,
+ pmsg->wParam, pmsg->lParam))
+ {
+ return TRUE;
+ }
+
+ /* XXX: MSDN says that hhk is ignored, but we should really use the
+ * return value from SetWindowsHookEx() in win32_create_message_window(). */
+ return CallNextHookEx(NULL, code, wParam, lParam);
+}
+
+/* The real message handler. Can be called with
+ * hwnd == NULL to process our thread messages. Returns TRUE for any messages
+ * that it processes */
+static LRESULT
+win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ /* BEWARE. The context retrieved using dTHX; is the context of the
+ * 'parent' thread during the CreateWindow() phase - i.e. for all messages
+ * up to and including WM_CREATE. If it ever happens that you need the
+ * 'child' context before this, then it needs to be passed into
+ * win32_create_message_window(), and passed to the WM_NCCREATE handler
+ * from the lparam of CreateWindow(). It could then be stored/retrieved
+ * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
+ * the dTHX calls here. */
+ /* XXX For now it is assumed that the overhead of the dTHX; for what
+ * are relativley infrequent code-paths, is better than the added
+ * complexity of getting the correct context passed into
+ * win32_create_message_window() */
+
+ switch(msg) {
+
+#ifdef USE_ITHREADS
+ case WM_USER_MESSAGE: {
+ long child = find_pseudo_pid((int)wParam);
+ if (child >= 0) {
+ dTHX;
+ w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
+ return 1;
+ }
+ break;
+ }
+#endif
+
+ case WM_USER_KILL: {
+ dTHX;
+ /* We use WM_USER_KILL to fake kill() with other signals */
+ int sig = (int)wParam;
+ if (do_raise(aTHX_ sig))
+ sig_terminate(aTHX_ sig);
+
+ return 1;
+ }
+
+ case WM_TIMER: {
+ dTHX;
+ /* alarm() is a one-shot but SetTimer() repeats so kill it */
+ if (w32_timerid && w32_timerid==(UINT)wParam) {
+ KillTimer(w32_message_hwnd, w32_timerid);
+ w32_timerid=0;
+
+ /* Now fake a call to signal handler */
+ if (do_raise(aTHX_ 14))
+ sig_terminate(aTHX_ 14);
+
+ return 1;
+ }
+ break;
+ }
+
+ default:
+ break;
+
+ } /* switch */
+
+ /* Above or other stuff may have set a signal flag, and we may not have
+ * been called from win32_async_check() (e.g. some other GUI's message
+ * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
+ * handler that die's, and the message loop that calls here is wrapped
+ * in an eval, then you may well end up with orphaned windows - signals
+ * are dispatched by win32_async_check() */
+
+ return 0;
+}
+
+void
+win32_create_message_window_class(void)
+{
+ /* create the window class for "message only" windows */
+ WNDCLASS wc;
+
+ Zero(&wc, 1, wc);
+ wc.lpfnWndProc = win32_message_window_proc;
+ wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
+ wc.lpszClassName = "PerlMessageWindowClass";
+
+ /* second and subsequent calls will fail, but class
+ * will already be registered */
+ RegisterClass(&wc);
+}
+
+HWND
+win32_create_message_window(void)
+{
+ HWND hwnd = NULL;
+ /* "message-only" windows have been implemented in Windows 2000 and later.
+ * On earlier versions we'll continue to post messages to a specific
+ * thread and use hwnd==NULL. This is brittle when either an embedding
+ * application or an XS module is also posting messages to hwnd=NULL
+ * because once removed from the queue they cannot be delivered to the
+ * "right" place with DispatchMessage() anymore, as there is no WindowProc
+ * if there is no window handle.
+ */
+ /* Using HWND_MESSAGE appears to work under Win98, despite MSDN
+ * documentation to the contrary, however, there is some evidence that
+ * there may be problems with the implementation on Win98. As it is not
+ * officially supported we take the cautious route and stick with thread
+ * messages (hwnd == NULL) on platforms prior to Win2k.
+ */
+ if (IsWin2000()) {
+ win32_create_message_window_class();
+
+ hwnd = CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
+ 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
+ }
+
+ /* If we din't create a window for any reason, then we'll use thread
+ * messages for our signalling, so we install a hook which
+ * is called by CallMsgFilter in win32_async_check(), or any other
+ * modal loop (e.g. Win32::MsgBox or any other GUI extention, or anything
+ * that use OLE, etc. */
+ if(!hwnd) {
+ SetWindowsHookEx(WH_MSGFILTER, win32_message_filter_proc,
+ NULL, GetCurrentThreadId());
+ }
+
+ return hwnd;
+}
+
+#ifdef HAVE_INTERP_INTERN
static void
win32_csighandler(int sig)
/* Does nothing */
}
+#if defined(__MINGW32__) && defined(__cplusplus)
+#define CAST_HWND__(x) (HWND__*)(x)
+#else
+#define CAST_HWND__(x) x
+#endif
+
void
Perl_sys_intern_init(pTHX)
{
int i;
- w32_perlshell_tokens = Nullch;
+
+ w32_perlshell_tokens = NULL;
w32_perlshell_vec = (char**)NULL;
w32_perlshell_items = 0;
w32_fdpid = newAV();
- New(1313, w32_children, 1, child_tab);
+ Newx(w32_children, 1, child_tab);
w32_num_children = 0;
# ifdef USE_ITHREADS
w32_pseudo_id = 0;
- New(1313, w32_pseudo_children, 1, child_tab);
+ Newx(w32_pseudo_children, 1, pseudo_child_tab);
w32_num_pseudo_children = 0;
# endif
- w32_init_socktype = 0;
w32_timerid = 0;
+ w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
w32_poll_count = 0;
for (i=0; i < SIG_SIZE; i++) {
w32_sighandler[i] = SIG_DFL;
}
-# ifdef MULTIPLICTY
+# ifdef MULTIPLICITY
if (my_perl == PL_curinterp) {
# else
{
# endif
/* Force C runtime signal stuff to set its console handler */
- signal(SIGINT,&win32_csighandler);
- signal(SIGBREAK,&win32_csighandler);
+ signal(SIGINT,win32_csighandler);
+ signal(SIGBREAK,win32_csighandler);
+
+ /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
+ * flag. This has the side-effect of disabling Ctrl-C events in all
+ * processes in this group. At least on Windows NT and later we
+ * can re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
+ * with a NULL handler. This is not valid on Windows 9X.
+ */
+ if (IsWinNT())
+ SetConsoleCtrlHandler(NULL,FALSE);
+
/* Push our handler on top */
SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
}
/* NOTE: w32_fdpid is freed by sv_clean_all() */
Safefree(w32_children);
if (w32_timerid) {
- KillTimer(NULL,w32_timerid);
- w32_timerid=0;
+ KillTimer(w32_message_hwnd, w32_timerid);
+ w32_timerid = 0;
}
+ if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
+ DestroyWindow(w32_message_hwnd);
# ifdef MULTIPLICITY
if (my_perl == PL_curinterp) {
# else
void
Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
{
- dst->perlshell_tokens = Nullch;
+ PERL_ARGS_ASSERT_SYS_INTERN_DUP;
+
+ dst->perlshell_tokens = NULL;
dst->perlshell_vec = (char**)NULL;
dst->perlshell_items = 0;
dst->fdpid = newAV();
- Newz(1313, dst->children, 1, child_tab);
+ Newxz(dst->children, 1, child_tab);
dst->pseudo_id = 0;
- Newz(1313, dst->pseudo_children, 1, child_tab);
- dst->thr_intern.Winit_socktype = 0;
- dst->timerid = 0;
- dst->poll_count = 0;
+ Newxz(dst->pseudo_children, 1, pseudo_child_tab);
+ dst->timerid = 0;
+ dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
+ dst->poll_count = 0;
Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
}
# endif /* USE_ITHREADS */
#endif /* HAVE_INTERP_INTERN */
-
-static void
-win32_free_argvw(pTHX_ void *ptr)
-{
- char** argv = (char**)ptr;
- while(*argv) {
- Safefree(*argv);
- *argv++ = Nullch;
- }
-}
-
-void
-win32_argv2utf8(int argc, char** argv)
-{
- dTHX;
- char* psz;
- int length, wargc;
- LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
- if (lpwStr && argc) {
- while (argc--) {
- length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
- Newz(0, psz, length, char);
- WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
- argv[argc] = psz;
- }
- call_atexit(win32_free_argvw, argv);
- }
- GlobalFree((HGLOBAL)lpwStr);
-}