1 /**
2  * Copyright: Copyright (c) 2011 Nick Sabalausky.
3  * Authors: Nick Sabalausky
4  * Version: Initial created: Jun 1, 2011
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dvm.util.Windows;
8 
9 version (Windows):
10 
11 import mambo.core..string;
12 import dvm.dvm.Exceptions;
13 import tango.sys.win32.Types;
14 import tango.sys.win32.UserGdi;
15 import tango.util.Convert;
16 
17 // If FORMAT_MESSAGE_ALLOCATE_BUFFER is used, then this is the correct
18 // signature. Otherwise, the signature in tango.sys.win32.UserGdi is corrent.
19 extern (Windows) DWORD FormatMessageW (DWORD, LPCVOID, DWORD, DWORD, LPWSTR*, DWORD, VA_LIST*);
20 
21 class WinAPIException : DvmException
22 {
23     LONG code;
24     string windowsMsg;
25 
26     this (LONG code, string msg = "", string file = __FILE__, size_t line = __LINE__)
27     {
28         this.code = code;
29 
30         if(windowsMsg == "")
31             windowsMsg = getMessage(code);
32 
33         super(msg == "" ? windowsMsg : msg, file, line);
34     }
35 
36     static string getMessage (DWORD errorCode)
37     {
38         wchar* pMsg;
39 
40         auto result = FormatMessageW(
41             FORMAT_MESSAGE_ALLOCATE_BUFFER |
42             FORMAT_MESSAGE_FROM_SYSTEM     |
43             FORMAT_MESSAGE_IGNORE_INSERTS,
44             null, errorCode, 0, &pMsg, 0, null
45         );
46 
47         if(result == 0)
48             return "Unknown WinAPI Error";
49 
50         scope (exit)
51             LocalFree(pMsg);
52 
53         auto msg = fromString16z(pMsg);
54         return to!(string)(msg);
55     }
56 }
57 
58 private alias mambo.core..string.toString16z toString16z;
59 
60 immutable(wchar)* toString16z (string str)
61 {
62     return to!(wstring)(str).toString16z();
63 }
64 
65 /// For more info, see: http://msdn.microsoft.com/en-us/library/ms725497(VS.85).aspx
66 void broadcastSettingChange (string settingName, uint timeout=1)
67 {
68     auto result = SendMessageTimeoutW(
69         HWND_BROADCAST, WM_SETTINGCHANGE,
70         0, cast(LPARAM)(settingName.toString16z()),
71         SMTO_ABORTIFHUNG, timeout, null
72     );
73 
74     if(result == 0)
75     {
76         auto errCode = GetLastError();
77 
78         if (errCode != ERROR_SUCCESS)
79             throw new WinAPIException(errCode, "Problem broadcasting WM_SETTINGCHANGE of '" ~ settingName ~ "'", __FILE__, __LINE__);
80     }
81 }
82 
83 string expandEnvironmentStrings(string str)
84 {
85     auto wstr = toString16z(str);
86 
87     wchar[] result;
88     result.length = 32_000 / wchar.sizeof;
89 
90     auto resultLength = ExpandEnvironmentStringsW(wstr, result.ptr, result.length);
91 
92     if(resultLength == 0)
93     {
94         auto errCode = GetLastError();
95 
96         if (errCode != ERROR_SUCCESS)
97             throw new WinAPIException(errCode, "Problem expanding environment variables", __FILE__, __LINE__);
98     }
99 
100     return to!(string)(result[0..resultLength-1]);
101 }