X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=win32%2Fwin32.c;h=7c0af0f11d71e929e22a14d0473ff9537b0de523;hb=f3c90b3644a4d1b01ee1a6fe678bc1357e85a56a;hp=3740e7054d86c6eed1a87af895f4d80eb2c3690a;hpb=08039b818b7a6e623279d03df2f71c92137e1052;p=p5sagit%2Fp5-mst-13.2.git diff --git a/win32/win32.c b/win32/win32.c index 3740e70..7c0af0f 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -15,6 +15,9 @@ #define Win32_Winsock #endif #include +#ifndef HWND_MESSAGE +# define HWND_MESSAGE ((HWND)-3) +#endif /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */ #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1) # include @@ -113,7 +116,7 @@ HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE; 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, ""}; #define ONE_K_BUFSIZE 1024 @@ -130,13 +133,13 @@ _matherr(struct _exception *a) 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); } EXTERN_C void @@ -426,15 +429,7 @@ Perl_my_pclose(pTHX_ PerlIO *fp) 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 @@ -741,11 +736,6 @@ win32_opendir(const char *filename) char scanname[MAX_PATH+3]; Stat_t sbuf; WIN32_FIND_DATAA aFindData; - WIN32_FIND_DATAW wFindData; - HANDLE fh; - char buffer[MAX_PATH*2]; - WCHAR wbuffer[MAX_PATH+1]; - char* ptr; len = strlen(filename); if (len > MAX_PATH) @@ -773,15 +763,8 @@ win32_opendir(const char *filename) scanname[len] = '\0'; /* do the FindFirstFile call */ - if (USING_WIDE()) { - A2WHELPER(scanname, wbuffer, sizeof(wbuffer)); - fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData); - } - else { - fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData); - } - dirp->handle = fh; - if (fh == INVALID_HANDLE_VALUE) { + dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData); + if (dirp->handle == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); /* FindFirstFile() fails on empty drives! */ switch (err) { @@ -805,20 +788,13 @@ win32_opendir(const char *filename) /* 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; - } - else { - ptr = aFindData.cFileName; - } - idx = strlen(ptr)+1; + idx = strlen(aFindData.cFileName)+1; if (idx < 256) dirp->size = 128; else dirp->size = idx; Newx(dirp->start, dirp->size, char); - strcpy(dirp->start, ptr); + strcpy(dirp->start, aFindData.cFileName); dirp->nfiles++; dirp->end = dirp->curr = dirp->start; dirp->end += idx; @@ -847,30 +823,16 @@ win32_readdir(DIR *dirp) 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]; /* finding the next file that matches the wildcard * (which should be all of them in this directory!). */ - if (USING_WIDE()) { - 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; - } + res = FindNextFileA(dirp->handle, &aFindData); if (res) { long endpos = dirp->end - dirp->start; - long newsize = endpos + strlen(ptr) + 1; + long newsize = endpos + strlen(aFindData.cFileName) + 1; /* bump the string table size by enough for the * new name and its null terminator */ while (newsize > dirp->size) { @@ -879,7 +841,7 @@ win32_readdir(DIR *dirp) Renew(dirp->start, dirp->size, char); dirp->curr = dirp->start + curpos; } - strcpy(dirp->start + endpos, ptr); + strcpy(dirp->start + endpos, aFindData.cFileName); dirp->end = dirp->start + newsize; dirp->nfiles++; } @@ -1071,6 +1033,8 @@ remove_dead_pseudo_process(long child) (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--; } } @@ -1088,11 +1052,13 @@ win32_kill(int pid, int sig) /* it is a pseudo-forked child */ child = find_pseudo_pid(-pid); if (child >= 0) { + HWND hwnd = w32_pseudo_child_message_hwnds[child]; 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)) { @@ -1100,16 +1066,30 @@ win32_kill(int pid, int 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); + ++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; @@ -1187,25 +1167,36 @@ win32_stat(const char *path, Stat_t *sbuf) 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])) { @@ -1220,41 +1211,28 @@ win32_stat(const char *path, Stat_t *sbuf) } } - /* 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) { @@ -1262,13 +1240,7 @@ win32_stat(const char *path, Stat_t *sbuf) * 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); @@ -1284,13 +1256,15 @@ win32_stat(const char *path, Stat_t *sbuf) && (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; + } #ifdef __BORLANDC__ if (S_ISDIR(sbuf->st_mode)) sbuf->st_mode |= S_IWRITE | S_IEXEC; @@ -1423,38 +1397,18 @@ DllExport char * win32_getenv(const char *name) { dTHX; - WCHAR wBuffer[MAX_PATH+1]; DWORD needlen; SV *curitem = Nullsv; - 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' @@ -1474,48 +1428,32 @@ win32_putenv(const char *name) 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; - Newx(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 { - 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. - * * 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. + * * 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); } return relval; } @@ -1583,42 +1521,21 @@ win32_unlink(const char *filename) 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 @@ -1630,19 +1547,11 @@ win32_utime(const char *filename, struct utimbuf *times) 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; @@ -1654,16 +1563,9 @@ win32_utime(const char *filename, struct utimbuf *times) } /* 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; @@ -1716,44 +1618,34 @@ win32_uname(struct utsname *name) { 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 */ @@ -1888,65 +1780,71 @@ DllExport int win32_async_check(pTHX) { MSG msg; - int ours = 1; + HWND hwnd = w32_message_hwnd; + + w32_poll_count = 0; + + if (hwnd == INVALID_HANDLE_VALUE) { + /* 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); + if (PL_sig_pending) + despatch_signals(); + return 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 (hwnd == NULL) + hwnd = (HWND)-1; -#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; + 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)) + { + switch (msg.message) { +#ifdef USE_ITHREADS + case WM_USER_MESSAGE: { + int child = find_pseudo_pid(msg.wParam); + if (child >= 0) + w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam; + break; + } #endif - /* 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); - } + case WM_USER_KILL: { + /* We use WM_USER to fake kill() with other signals */ + int sig = msg.wParam; + if (do_raise(aTHX_ sig)) + sig_terminate(aTHX_ sig); break; } 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); + KillTimer(w32_message_hwnd, 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; - } - /* Otherwise do normal Win32 thing - in case it is useful */ - default: - FallThrough: - TranslateMessage(&msg); - DispatchMessage(&msg); - ours = 0; + /* Now fake a call to signal handler */ + if (do_raise(aTHX_ 14)) + sig_terminate(aTHX_ 14); + } break; } + } /* switch */ } - w32_poll_count = 0; /* Above or other stuff may have set a signal flag */ if (PL_sig_pending) { despatch_signals(); } - return ours; + return 1; } /* This function will not return until the timeout has elapsed, or until @@ -2159,13 +2057,22 @@ win32_alarm(unsigned int sec) * one of the supported codes in */ 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; @@ -2483,7 +2390,6 @@ DllExport FILE * win32_fopen(const char *filename, const char *mode) { dTHX; - WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1]; FILE *f; if (!*filename) @@ -2492,13 +2398,7 @@ win32_fopen(const char *filename, const char *mode) 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); @@ -2514,14 +2414,8 @@ DllExport FILE * 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); @@ -2532,15 +2426,9 @@ DllExport FILE * 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); } @@ -2734,9 +2622,31 @@ win32_fstat(int fd, Stat_t *sbufptr) * 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 = (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)); @@ -2910,6 +2820,7 @@ win32_pclose(PerlIO *pf) childpid = 0; if (!childpid) { + UNLOCK_FDPID_MUTEX; errno = EBADF; return -1; } @@ -3005,10 +2916,10 @@ win32_link(const char *oldname, const char *newname) 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; } @@ -3019,8 +2930,6 @@ win32_link(const char *oldname, const char *newname) 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; @@ -3031,20 +2940,10 @@ win32_rename(const char *oname, const char *newname) */ 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) { @@ -3255,7 +3154,6 @@ win32_open(const char *path, int flag, ...) dTHX; va_list ap; int pmode; - WCHAR wBuffer[MAX_PATH+1]; va_start(ap, flag); pmode = va_arg(ap, int); @@ -3264,10 +3162,6 @@ win32_open(const char *path, int flag, ...) 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); } @@ -3514,11 +3408,6 @@ DllExport int 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 */ } @@ -3526,11 +3415,6 @@ DllExport int 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)); } @@ -3542,11 +3426,6 @@ win32_chdir(const char *dir) errno = ENOENT; return -1; } - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(dir, wBuffer, sizeof(wBuffer)); - return _wchdir(wBuffer); - } return chdir(dir); } @@ -3554,11 +3433,6 @@ DllExport int 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); } @@ -3566,11 +3440,6 @@ DllExport int 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); } @@ -3860,16 +3729,9 @@ win32_get_childdir(void) { 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]; + GetCurrentDirectoryA(MAX_PATH+1, szfilename); Newx(ptr, strlen(szfilename)+1, char); strcpy(ptr, szfilename); return ptr; @@ -4368,7 +4230,6 @@ DllExport void* win32_dynaload(const char* filename) { dTHX; - HMODULE hModule; char buf[MAX_PATH+1]; char *first; @@ -4388,15 +4249,7 @@ win32_dynaload(const char* filename) 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); } /* @@ -4645,57 +4498,19 @@ XS(w32_GetOSVersion) } 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; + osver.dwOSVersionInfoSize = sizeof(osver); + if (!GetVersionExA((OSVERSIONINFOA*)&osver)) { + bEx = FALSE; + osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA((OSVERSIONINFOA*)&osver)) { + XSRETURN_EMPTY; + } } - 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))); + 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)); @@ -4735,21 +4550,11 @@ XS(w32_FormatMessage) 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); + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, + &source, SvIV(ST(0)), 0, + msgbuf, sizeof(msgbuf)-1, NULL)) + { + XSRETURN_PV(msgbuf); } XSRETURN_UNDEF; @@ -4929,22 +4734,12 @@ XS(w32_CopyFile) { dXSARGS; BOOL bResult; + char szSourceFile[MAX_PATH+1]; + 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))); - } - + 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; @@ -5079,6 +4874,7 @@ Perl_win32_init(int *argcp, char ***argvp) void Perl_win32_term(void) { + HINTS_REFCNT_TERM; OP_REFCNT_TERM; MALLOC_TERM; } @@ -5125,10 +4921,33 @@ win32_csighandler(int sig) /* Does nothing */ } +HWND +win32_create_message_window() +{ + /* "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. + */ + if (g_osver.dwMajorVersion < 5) + return NULL; + + return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL); +} + void Perl_sys_intern_init(pTHX) { int i; + + if (g_osver.dwOSVersionInfoSize == 0) { + g_osver.dwOSVersionInfoSize = sizeof(g_osver); + GetVersionEx(&g_osver); + } + w32_perlshell_tokens = Nullch; w32_perlshell_vec = (char**)NULL; w32_perlshell_items = 0; @@ -5137,10 +4956,11 @@ Perl_sys_intern_init(pTHX) w32_num_children = 0; # ifdef USE_ITHREADS w32_pseudo_id = 0; - Newx(w32_pseudo_children, 1, child_tab); + Newx(w32_pseudo_children, 1, pseudo_child_tab); w32_num_pseudo_children = 0; # endif w32_timerid = 0; + w32_message_hwnd = INVALID_HANDLE_VALUE; w32_poll_count = 0; for (i=0; i < SIG_SIZE; i++) { w32_sighandler[i] = SIG_DFL; @@ -5166,9 +4986,11 @@ Perl_sys_intern_clear(pTHX) /* 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 @@ -5192,9 +5014,10 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst) dst->fdpid = newAV(); Newxz(dst->children, 1, child_tab); dst->pseudo_id = 0; - Newxz(dst->pseudo_children, 1, child_tab); - dst->timerid = 0; - dst->poll_count = 0; + Newxz(dst->pseudo_children, 1, pseudo_child_tab); + dst->timerid = 0; + dst->message_hwnd = INVALID_HANDLE_VALUE; + dst->poll_count = 0; Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t); } # endif /* USE_ITHREADS */