Move Win32 from win32/ext/Win32 to ext/Win32
[p5sagit/p5-mst-13.2.git] / ext / Win32 / Win32.xs
1 #include <windows.h>
2
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6
7 #define SE_SHUTDOWN_NAMEA   "SeShutdownPrivilege"
8
9 typedef BOOL (WINAPI *PFNSHGetSpecialFolderPath)(HWND, char*, int, BOOL);
10 typedef HRESULT (WINAPI *PFNSHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR);
11 typedef int (__stdcall *PFNDllRegisterServer)(void);
12 typedef int (__stdcall *PFNDllUnregisterServer)(void);
13 #ifndef CSIDL_FLAG_CREATE
14 #   define CSIDL_FLAG_CREATE               0x8000
15 #endif
16
17 XS(w32_ExpandEnvironmentStrings)
18 {
19     dXSARGS;
20     BYTE buffer[4096];
21
22     if (items != 1)
23         croak("usage: Win32::ExpandEnvironmentStrings($String);\n");
24
25     ExpandEnvironmentStringsA(SvPV_nolen(ST(0)), (char*)buffer, sizeof(buffer));
26     XSRETURN_PV((char*)buffer);
27 }
28
29 XS(w32_IsAdminUser)
30 {
31     dXSARGS;
32     HINSTANCE                   hAdvApi32;
33     BOOL (__stdcall *pfnOpenThreadToken)(HANDLE hThr, DWORD dwDesiredAccess,
34                                 BOOL bOpenAsSelf, PHANDLE phTok);
35     BOOL (__stdcall *pfnOpenProcessToken)(HANDLE hProc, DWORD dwDesiredAccess,
36                                 PHANDLE phTok);
37     BOOL (__stdcall *pfnGetTokenInformation)(HANDLE hTok,
38                                 TOKEN_INFORMATION_CLASS TokenInformationClass,
39                                 LPVOID lpTokInfo, DWORD dwTokInfoLen,
40                                 PDWORD pdwRetLen);
41     BOOL (__stdcall *pfnAllocateAndInitializeSid)(
42                                 PSID_IDENTIFIER_AUTHORITY pIdAuth,
43                                 BYTE nSubAuthCount, DWORD dwSubAuth0,
44                                 DWORD dwSubAuth1, DWORD dwSubAuth2,
45                                 DWORD dwSubAuth3, DWORD dwSubAuth4,
46                                 DWORD dwSubAuth5, DWORD dwSubAuth6,
47                                 DWORD dwSubAuth7, PSID pSid);
48     BOOL (__stdcall *pfnEqualSid)(PSID pSid1, PSID pSid2);
49     PVOID (__stdcall *pfnFreeSid)(PSID pSid);
50     HANDLE                      hTok;
51     DWORD                       dwTokInfoLen;
52     TOKEN_GROUPS                *lpTokInfo;
53     SID_IDENTIFIER_AUTHORITY    NtAuth = SECURITY_NT_AUTHORITY;
54     PSID                        pAdminSid;
55     int                         iRetVal;
56     unsigned int                i;
57     OSVERSIONINFO               osver;
58
59     if (items)
60         croak("usage: Win32::IsAdminUser()");
61
62     /* There is no concept of "Administrator" user accounts on Win9x systems,
63        so just return true. */
64     memset(&osver, 0, sizeof(OSVERSIONINFO));
65     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
66     GetVersionEx(&osver);
67     if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
68         XSRETURN_YES;
69
70     hAdvApi32 = LoadLibrary("advapi32.dll");
71     if (!hAdvApi32) {
72         warn("Cannot load advapi32.dll library");
73         XSRETURN_UNDEF;
74     }
75
76     pfnOpenThreadToken = (BOOL (__stdcall *)(HANDLE, DWORD, BOOL, PHANDLE))
77         GetProcAddress(hAdvApi32, "OpenThreadToken");
78     pfnOpenProcessToken = (BOOL (__stdcall *)(HANDLE, DWORD, PHANDLE))
79         GetProcAddress(hAdvApi32, "OpenProcessToken");
80     pfnGetTokenInformation = (BOOL (__stdcall *)(HANDLE,
81         TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD))
82         GetProcAddress(hAdvApi32, "GetTokenInformation");
83     pfnAllocateAndInitializeSid = (BOOL (__stdcall *)(
84         PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD,
85         DWORD, DWORD, DWORD, PSID))
86         GetProcAddress(hAdvApi32, "AllocateAndInitializeSid");
87     pfnEqualSid = (BOOL (__stdcall *)(PSID, PSID))
88         GetProcAddress(hAdvApi32, "EqualSid");
89     pfnFreeSid = (PVOID (__stdcall *)(PSID))
90         GetProcAddress(hAdvApi32, "FreeSid");
91
92     if (!(pfnOpenThreadToken && pfnOpenProcessToken &&
93           pfnGetTokenInformation && pfnAllocateAndInitializeSid &&
94           pfnEqualSid && pfnFreeSid))
95     {
96         warn("Cannot load functions from advapi32.dll library");
97         FreeLibrary(hAdvApi32);
98         XSRETURN_UNDEF;
99     }
100
101     if (!pfnOpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hTok)) {
102         if (!pfnOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hTok)) {
103             warn("Cannot open thread token or process token");
104             FreeLibrary(hAdvApi32);
105             XSRETURN_UNDEF;
106         }
107     }
108
109     pfnGetTokenInformation(hTok, TokenGroups, NULL, 0, &dwTokInfoLen);
110     if (!New(1, lpTokInfo, dwTokInfoLen, TOKEN_GROUPS)) {
111         warn("Cannot allocate token information structure");
112         CloseHandle(hTok);
113         FreeLibrary(hAdvApi32);
114         XSRETURN_UNDEF;
115     }
116
117     if (!pfnGetTokenInformation(hTok, TokenGroups, lpTokInfo, dwTokInfoLen,
118             &dwTokInfoLen))
119     {
120         warn("Cannot get token information");
121         Safefree(lpTokInfo);
122         CloseHandle(hTok);
123         FreeLibrary(hAdvApi32);
124         XSRETURN_UNDEF;
125     }
126
127     if (!pfnAllocateAndInitializeSid(&NtAuth, 2, SECURITY_BUILTIN_DOMAIN_RID,
128             DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSid))
129     {
130         warn("Cannot allocate administrators' SID");
131         Safefree(lpTokInfo);
132         CloseHandle(hTok);
133         FreeLibrary(hAdvApi32);
134         XSRETURN_UNDEF;
135     }
136
137     iRetVal = 0;
138     for (i = 0; i < lpTokInfo->GroupCount; ++i) {
139         if (pfnEqualSid(lpTokInfo->Groups[i].Sid, pAdminSid)) {
140             iRetVal = 1;
141             break;
142         }
143     }
144
145     pfnFreeSid(pAdminSid);
146     Safefree(lpTokInfo);
147     CloseHandle(hTok);
148     FreeLibrary(hAdvApi32);
149
150     EXTEND(SP, 1);
151     ST(0) = sv_2mortal(newSViv(iRetVal));
152     XSRETURN(1);
153 }
154
155 XS(w32_LookupAccountName)
156 {
157     dXSARGS;
158     char SID[400];
159     DWORD SIDLen;
160     SID_NAME_USE snu;
161     char Domain[256];
162     DWORD DomLen;
163     BOOL bResult;
164
165     if (items != 5)
166         croak("usage: Win32::LookupAccountName($system, $account, $domain, "
167               "$sid, $sidtype);\n");
168
169     SIDLen = sizeof(SID);
170     DomLen = sizeof(Domain);
171
172     bResult = LookupAccountNameA(SvPV_nolen(ST(0)),     /* System */
173                                  SvPV_nolen(ST(1)),     /* Account name */
174                                  &SID,                  /* SID structure */
175                                  &SIDLen,               /* Size of SID buffer */
176                                  Domain,                /* Domain buffer */
177                                  &DomLen,               /* Domain buffer size */
178                                  &snu);                 /* SID name type */
179     if (bResult) {
180         sv_setpv(ST(2), Domain);
181         sv_setpvn(ST(3), SID, SIDLen);
182         sv_setiv(ST(4), snu);
183         XSRETURN_YES;
184     }
185     XSRETURN_NO;
186 }
187
188
189 XS(w32_LookupAccountSID)
190 {
191     dXSARGS;
192     PSID sid;
193     char Account[256];
194     DWORD AcctLen = sizeof(Account);
195     char Domain[256];
196     DWORD DomLen = sizeof(Domain);
197     SID_NAME_USE snu;
198     BOOL bResult;
199
200     if (items != 5)
201         croak("usage: Win32::LookupAccountSID($system, $sid, $account, $domain, $sidtype);\n");
202
203     sid = SvPV_nolen(ST(1));
204     if (IsValidSid(sid)) {
205         bResult = LookupAccountSidA(SvPV_nolen(ST(0)),  /* System */
206                                     sid,                /* SID structure */
207                                     Account,            /* Account name buffer */
208                                     &AcctLen,           /* name buffer length */
209                                     Domain,             /* Domain buffer */
210                                     &DomLen,            /* Domain buffer length */
211                                     &snu);              /* SID name type */
212         if (bResult) {
213             sv_setpv(ST(2), Account);
214             sv_setpv(ST(3), Domain);
215             sv_setiv(ST(4), (IV)snu);
216             XSRETURN_YES;
217         }
218     }
219     XSRETURN_NO;
220 }
221
222 XS(w32_InitiateSystemShutdown)
223 {
224     dXSARGS;
225     HANDLE hToken;              /* handle to process token   */
226     TOKEN_PRIVILEGES tkp;       /* pointer to token structure  */
227     BOOL bRet;
228     char *machineName, *message;
229
230     if (items != 5)
231         croak("usage: Win32::InitiateSystemShutdown($machineName, $message, "
232               "$timeOut, $forceClose, $reboot);\n");
233
234     machineName = SvPV_nolen(ST(0));
235
236     if (OpenProcessToken(GetCurrentProcess(),
237                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
238                          &hToken))
239     {
240         LookupPrivilegeValueA(machineName,
241                               SE_SHUTDOWN_NAMEA,
242                               &tkp.Privileges[0].Luid);
243
244         tkp.PrivilegeCount = 1; /* only setting one */
245         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
246
247         /* Get shutdown privilege for this process. */
248         AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
249                               (PTOKEN_PRIVILEGES)NULL, 0);
250     }
251
252     message = SvPV_nolen(ST(1));
253     bRet = InitiateSystemShutdownA(machineName, message,
254                                    SvIV(ST(2)), SvIV(ST(3)), SvIV(ST(4)));
255
256     /* Disable shutdown privilege. */
257     tkp.Privileges[0].Attributes = 0; 
258     AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
259                           (PTOKEN_PRIVILEGES)NULL, 0); 
260     CloseHandle(hToken);
261     XSRETURN_IV(bRet);
262 }
263
264 XS(w32_AbortSystemShutdown)
265 {
266     dXSARGS;
267     HANDLE hToken;              /* handle to process token   */
268     TOKEN_PRIVILEGES tkp;       /* pointer to token structure  */
269     BOOL bRet;
270     char *machineName;
271
272     if (items != 1)
273         croak("usage: Win32::AbortSystemShutdown($machineName);\n");
274
275     machineName = SvPV_nolen(ST(0));
276
277     if (OpenProcessToken(GetCurrentProcess(),
278                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
279                          &hToken))
280     {
281         LookupPrivilegeValueA(machineName,
282                               SE_SHUTDOWN_NAMEA,
283                               &tkp.Privileges[0].Luid);
284
285         tkp.PrivilegeCount = 1; /* only setting one */
286         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
287
288         /* Get shutdown privilege for this process. */
289         AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
290                               (PTOKEN_PRIVILEGES)NULL, 0);
291     }
292
293     bRet = AbortSystemShutdownA(machineName);
294
295     /* Disable shutdown privilege. */
296     tkp.Privileges[0].Attributes = 0;
297     AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
298                           (PTOKEN_PRIVILEGES)NULL, 0);
299     CloseHandle(hToken);
300     XSRETURN_IV(bRet);
301 }
302
303
304 XS(w32_MsgBox)
305 {
306     dXSARGS;
307     char *msg;
308     char *title = "Perl";
309     DWORD flags = MB_ICONEXCLAMATION;
310     I32 result;
311
312     if (items < 1 || items > 3)
313         croak("usage: Win32::MsgBox($message [, $flags [, $title]]);\n");
314
315     msg = SvPV_nolen(ST(0));
316     if (items > 1) {
317         flags = SvIV(ST(1));
318         if (items > 2)
319             title = SvPV_nolen(ST(2));
320     }
321     result = MessageBoxA(GetActiveWindow(), msg, title, flags);
322     XSRETURN_IV(result);
323 }
324
325 XS(w32_LoadLibrary)
326 {
327     dXSARGS;
328     HANDLE hHandle;
329
330     if (items != 1)
331         croak("usage: Win32::LoadLibrary($libname)\n");
332     hHandle = LoadLibraryA(SvPV_nolen(ST(0)));
333     XSRETURN_IV((long)hHandle);
334 }
335
336 XS(w32_FreeLibrary)
337 {
338     dXSARGS;
339
340     if (items != 1)
341         croak("usage: Win32::FreeLibrary($handle)\n");
342     if (FreeLibrary(INT2PTR(HINSTANCE, SvIV(ST(0))))) {
343         XSRETURN_YES;
344     }
345     XSRETURN_NO;
346 }
347
348 XS(w32_GetProcAddress)
349 {
350     dXSARGS;
351
352     if (items != 2)
353         croak("usage: Win32::GetProcAddress($hinstance, $procname)\n");
354     XSRETURN_IV(PTR2IV(GetProcAddress(INT2PTR(HINSTANCE, SvIV(ST(0))), SvPV_nolen(ST(1)))));
355 }
356
357 XS(w32_RegisterServer)
358 {
359     dXSARGS;
360     BOOL result = FALSE;
361     HINSTANCE hnd;
362
363     if (items != 1)
364         croak("usage: Win32::RegisterServer($libname)\n");
365
366     hnd = LoadLibraryA(SvPV_nolen(ST(0)));
367     if (hnd) {
368         PFNDllRegisterServer func;
369         func = (PFNDllRegisterServer)GetProcAddress(hnd, "DllRegisterServer");
370         if (func && func() == 0)
371             result = TRUE;
372         FreeLibrary(hnd);
373     }
374     ST(0) = boolSV(result);
375     XSRETURN(1);
376 }
377
378 XS(w32_UnregisterServer)
379 {
380     dXSARGS;
381     BOOL result = FALSE;
382     HINSTANCE hnd;
383
384     if (items != 1)
385         croak("usage: Win32::UnregisterServer($libname)\n");
386
387     hnd = LoadLibraryA(SvPV_nolen(ST(0)));
388     if (hnd) {
389         PFNDllUnregisterServer func;
390         func = (PFNDllUnregisterServer)GetProcAddress(hnd, "DllUnregisterServer");
391         if (func && func() == 0)
392             result = TRUE;
393         FreeLibrary(hnd);
394     }
395     ST(0) = boolSV(result);
396     XSRETURN(1);
397 }
398
399 /* XXX rather bogus */
400 XS(w32_GetArchName)
401 {
402     dXSARGS;
403     XSRETURN_PV(getenv("PROCESSOR_ARCHITECTURE"));
404 }
405
406 XS(w32_GetChipName)
407 {
408     dXSARGS;
409     SYSTEM_INFO sysinfo;
410
411     Zero(&sysinfo,1,SYSTEM_INFO);
412     GetSystemInfo(&sysinfo);
413     /* XXX docs say dwProcessorType is deprecated on NT */
414     XSRETURN_IV(sysinfo.dwProcessorType);
415 }
416
417 XS(w32_GuidGen)
418 {
419     dXSARGS;
420     GUID guid;
421     char szGUID[50] = {'\0'};
422     HRESULT  hr     = CoCreateGuid(&guid);
423
424     if (SUCCEEDED(hr)) {
425         LPOLESTR pStr = NULL;
426         if (SUCCEEDED(StringFromCLSID(&guid, &pStr))) {
427             WideCharToMultiByte(CP_ACP, 0, pStr, wcslen(pStr), szGUID,
428                                 sizeof(szGUID), NULL, NULL);
429             CoTaskMemFree(pStr);
430             XSRETURN_PV(szGUID);
431         }
432     }
433     XSRETURN_UNDEF;
434 }
435
436 XS(w32_GetFolderPath)
437 {
438     dXSARGS;
439     char path[MAX_PATH+1];
440     int folder;
441     int create = 0;
442     HMODULE module;
443
444     if (items != 1 && items != 2)
445         croak("usage: Win32::GetFolderPath($csidl [, $create])\n");
446
447     folder = SvIV(ST(0));
448     if (items == 2)
449         create = SvTRUE(ST(1)) ? CSIDL_FLAG_CREATE : 0;
450
451     module = LoadLibrary("shfolder.dll");
452     if (module) {
453         PFNSHGetFolderPath pfn;
454         pfn = (PFNSHGetFolderPath)GetProcAddress(module, "SHGetFolderPathA");
455         if (pfn && SUCCEEDED(pfn(NULL, folder|create, NULL, 0, path))) {
456             FreeLibrary(module);
457             XSRETURN_PV(path);
458         }
459         FreeLibrary(module);
460     }
461
462     module = LoadLibrary("shell32.dll");
463     if (module) {
464         PFNSHGetSpecialFolderPath pfn;
465         pfn = (PFNSHGetSpecialFolderPath)
466             GetProcAddress(module, "SHGetSpecialFolderPathA");
467         if (pfn && pfn(NULL, path, folder, !!create)) {
468             FreeLibrary(module);
469             XSRETURN_PV(path);
470         }
471         FreeLibrary(module);
472     }
473     XSRETURN_UNDEF;
474 }
475
476 XS(w32_GetFileVersion)
477 {
478     dXSARGS;
479     DWORD size;
480     DWORD handle;
481     char *filename;
482     char *data;
483
484     if (items != 1)
485         croak("usage: Win32::GetFileVersion($filename)\n");
486
487     filename = SvPV_nolen(ST(0));
488     size = GetFileVersionInfoSize(filename, &handle);
489     if (!size)
490         XSRETURN_UNDEF;
491
492     New(0, data, size, char);
493     if (!data)
494         XSRETURN_UNDEF;
495
496     if (GetFileVersionInfo(filename, handle, size, data)) {
497         VS_FIXEDFILEINFO *info;
498         UINT len;
499         if (VerQueryValue(data, "\\", (void**)&info, &len)) {
500             int dwValueMS1 = (info->dwFileVersionMS>>16);
501             int dwValueMS2 = (info->dwFileVersionMS&0xffff);
502             int dwValueLS1 = (info->dwFileVersionLS>>16);
503             int dwValueLS2 = (info->dwFileVersionLS&0xffff);
504
505             if (GIMME_V == G_ARRAY) {
506                 EXTEND(SP, 4);
507                 XST_mIV(0, dwValueMS1);
508                 XST_mIV(1, dwValueMS2);
509                 XST_mIV(2, dwValueLS1);
510                 XST_mIV(3, dwValueLS2);
511                 items = 4;
512             }
513             else {
514                 char version[50];
515                 sprintf(version, "%d.%d.%d.%d", dwValueMS1, dwValueMS2, dwValueLS1, dwValueLS2);
516                 XST_mPV(0, version);
517             }
518         }
519     }
520     else
521         items = 0;
522
523     Safefree(data);
524     XSRETURN(items);
525 }
526
527 XS(boot_Win32)
528 {
529     dXSARGS;
530     char *file = __FILE__;
531
532     newXS("Win32::LookupAccountName", w32_LookupAccountName, file);
533     newXS("Win32::LookupAccountSID", w32_LookupAccountSID, file);
534     newXS("Win32::InitiateSystemShutdown", w32_InitiateSystemShutdown, file);
535     newXS("Win32::AbortSystemShutdown", w32_AbortSystemShutdown, file);
536     newXS("Win32::ExpandEnvironmentStrings", w32_ExpandEnvironmentStrings, file);
537     newXS("Win32::MsgBox", w32_MsgBox, file);
538     newXS("Win32::LoadLibrary", w32_LoadLibrary, file);
539     newXS("Win32::FreeLibrary", w32_FreeLibrary, file);
540     newXS("Win32::GetProcAddress", w32_GetProcAddress, file);
541     newXS("Win32::RegisterServer", w32_RegisterServer, file);
542     newXS("Win32::UnregisterServer", w32_UnregisterServer, file);
543     newXS("Win32::GetArchName", w32_GetArchName, file);
544     newXS("Win32::GetChipName", w32_GetChipName, file);
545     newXS("Win32::GuidGen", w32_GuidGen, file);
546     newXS("Win32::GetFolderPath", w32_GetFolderPath, file);
547     newXS("Win32::IsAdminUser", w32_IsAdminUser, file);
548     newXS("Win32::GetFileVersion", w32_GetFileVersion, file);
549
550     XSRETURN_YES;
551 }