1 /** DGui project file.
2
3 Copyright: Trogu Antonio Davide 2011-2013
4
5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6
7 Authors: Trogu Antonio Davide
8 */
9 module dgui.application;
10
11 pragma(lib, "gdi32.lib");
12 pragma(lib, "comdlg32.lib");
13
14 import std.path;
15 private import dgui.core.winapi;
16 private import dgui.core.utils;
17 private import dgui.richtextbox;
18 private import dgui.form;
19 private import dgui.button;
20 private import dgui.label;
21 private import std.utf: toUTFz;
22 private import std.file;
23 private import std.conv;
24 public import dgui.resources;
25
26 private enum
27 {
28 info = "Exception Information:",
29 xpManifestFile = "dgui.xml.manifest",
30 errMsg = "An application exception has occured.\n1) Click \"Ignore\" to continue (The program can be unstable).\n2) Click \"Quit\" to exit.\n",
31 xpManifest = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
32 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
33 <assemblyIdentity
34 version="1.0.0.0"
35 processorArchitecture="X86"
36 name="client"
37 type="win32"
38 />
39 <description></description>
40
41 <!-- Enable Windows XP and higher themes with common controls -->
42 <dependency>
43 <dependentAssembly>
44 <assemblyIdentity
45 type="win32"
46 name="Microsoft.Windows.Common-Controls"
47 version="6.0.0.0"
48 processorArchitecture="X86"
49 publicKeyToken="6595b64144ccf1df"
50 language="*"
51 />
52 </dependentAssembly>
53 </dependency>
54
55 <!-- Disable Windows Vista UAC compatibility heuristics -->
56 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
57 <security>
58 <requestedPrivileges>
59 <requestedExecutionLevel level="asInvoker"/>
60 </requestedPrivileges>
61 </security>
62 </trustInfo>
63
64 <!-- Enable Windows Vista-style font scaling on Vista -->
65 <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
66 <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
67 <dpiAware>true</dpiAware>
68 </asmv3:windowsSettings>
69 </asmv3:application>
70 </assembly>`
71 }
72 private alias extern(Windows) BOOL function(HANDLE hActCtx, ULONG_PTR* lpCookie) ActivateActCtxProc;
73 private alias extern(Windows) HANDLE function(ACTCTXW* pActCtx) CreateActCtxWProc;
74 private alias extern(Windows) bool function(INITCOMMONCONTROLSEX*) InitCommonControlsExProc;
75
76 /**
77 The _Application class manage the whole program, it can be used for load embedded resources,
78 close the program, get the current path and so on.
79 Internally in initialize manifest (if available), DLLs, and it handle exceptions showing a window with exception information.
80 */
81 class Application
82 {
83 private static class ExceptionForm: Form
84 {
85 public this(Throwable e)
86 {
87 this.text = "An Exception was thrown...";
88 this.size = Size(400, 220);
89 this.controlBox = false;
90 this.startPosition = FormStartPosition.centerParent;
91 this.formBorderStyle = FormBorderStyle.fixedDialog;
92
93 this._lblHead = new Label();
94 this._lblHead.alignment = TextAlignment.middle | TextAlignment.left;
95 this._lblHead.foreColor = Color(0xB4, 0x00, 0x00);
96 this._lblHead.dock = DockStyle.top;
97 this._lblHead.height = 50;
98 this._lblHead.text = errMsg;
99 this._lblHead.parent = this;
100
101 this._lblInfo = new Label();
102 this._lblInfo.alignment = TextAlignment.middle | TextAlignment.left;
103 this._lblInfo.dock = DockStyle.top;
104 this._lblInfo.height = 20;
105 this._lblInfo.text = info;
106 this._lblInfo.parent = this;
107
108 this._rtfText = new RichTextBox();
109 this._rtfText.borderStyle = BorderStyle.fixed3d;
110 this._rtfText.dock = DockStyle.top;
111 this._rtfText.height = 90;
112 this._rtfText.backColor = SystemColors.colorButtonFace;
113 this._rtfText.scrollBars = true;
114 this._rtfText.readOnly = true;
115 this._rtfText.text = e.msg;
116 this._rtfText.parent = this;
117
118 this._btnQuit = new Button();
119 this._btnQuit.bounds = Rect(310, 164, 80, 23);
120 this._btnQuit.dialogResult = DialogResult.abort;
121 this._btnQuit.text = "Quit";
122 this._btnQuit.parent = this;
123
124 this._btnIgnore = new Button();
125 this._btnIgnore.bounds = Rect(225, 164, 80, 23);
126 this._btnIgnore.dialogResult = DialogResult.ignore;
127 this._btnIgnore.text = "Ignore";
128 this._btnIgnore.parent = this;
129 }
130
131 private RichTextBox _rtfText;
132 private Label _lblHead;
133 private Label _lblInfo;
134 private Button _btnIgnore;
135 private Button _btnQuit;
136 }
137
138 /// Static constructor (it enable the manifest, if available)
139 public static this()
140 {
141 Application.enableManifest(); //Enable Manifest (if available)
142 }
143
144 /**
145 This method calls GetModuleHandle() API
146
147 Returns:
148 HINSTANCE of the program
149 */
150 @property public static HINSTANCE instance()
151 {
152 return getHInstance();
153 }
154
155 /**
156 Returns:
157 String value of the executable path ($(B including) the executable name)
158 */
159 @property public static string executablePath()
160 {
161 return getExecutablePath();
162 }
163
164 /**
165 This method calls GetTempPath() API
166
167 Returns:
168 String value of the system's TEMP directory
169 */
170 @property public static string tempPath()
171 {
172 return dgui.core.utils.getTempPath();
173 }
174
175 /**
176 Returns:
177 String value of the executable path ($(B without) the executable name)
178 */
179 @property public static string startupPath()
180 {
181 return getStartupPath();
182 }
183
184 /**
185 This property allows to load embedded _resources.
186
187 Returns:
188 The Instance of reource object
189
190 See_Also:
191 Resources Class
192 */
193 @property public static Resources resources()
194 {
195 return Resources.instance;
196 }
197
198 /**
199 Internal method that enable XP Manifest (if available)
200 */
201 private static void enableManifest()
202 {
203 HMODULE hKernel32 = getModuleHandle("kernel32.dll");
204
205 if(hKernel32)
206 {
207 CreateActCtxWProc createActCtx = cast(CreateActCtxWProc)GetProcAddress(hKernel32, "CreateActCtxW");
208
209 if(createActCtx) // Don't break Win2k compatibility
210 {
211 string temp = dgui.core.utils.getTempPath();
212 ActivateActCtxProc activateActCtx = cast(ActivateActCtxProc)GetProcAddress(hKernel32, "ActivateActCtx");
213 temp = std.path.buildPath(temp, xpManifestFile);
214 std.file.write(temp, xpManifest);
215
216 ACTCTXW actx;
217
218 actx.cbSize = ACTCTXW.sizeof;
219 actx.dwFlags = 0;
220 actx.lpSource = toUTFz!(wchar*)(temp);
221
222 HANDLE hActx = createActCtx(&actx);
223
224 if(hActx != INVALID_HANDLE_VALUE)
225 {
226 ULONG_PTR cookie;
227 activateActCtx(hActx, &cookie);
228 }
229
230 if(std.file.exists(temp))
231 {
232 std.file.remove(temp);
233 }
234 }
235 }
236
237 initCommonControls();
238 }
239
240 /**
241 Internal method that loads ComCtl32 DLL
242 */
243 private static void initCommonControls()
244 {
245 INITCOMMONCONTROLSEX icc = void;
246
247 icc.dwSize = INITCOMMONCONTROLSEX.sizeof;
248 icc.dwICC = 0xFFFFFFFF;
249
250 HMODULE hComCtl32 = loadLibrary("comctl32.dll");
251
252 if(hComCtl32)
253 {
254 InitCommonControlsExProc iccex = cast(InitCommonControlsExProc)GetProcAddress(hComCtl32, "InitCommonControlsEx");
255
256 if(iccex)
257 {
258 iccex(&icc);
259 }
260 }
261 }
262
263 /**
264 Start the program and handles handles Exception
265 Params:
266 mainForm = The Application's main form
267
268 Returns:
269 Zero
270 */
271
272 private static int doRun(Form mainForm)
273 {
274 //try
275 //{
276 mainForm.show();
277 /*}
278 catch(Throwable e)
279 {
280 switch(Application.showExceptionForm(e))
281 {
282 case DialogResult.abort:
283 TerminateProcess(GetCurrentProcess(), -1);
284 break;
285
286 case DialogResult.ignore:
287 Application.doRun(mainForm);
288 break;
289
290 default:
291 break;
292 }
293 }*/
294
295 return 0;
296 }
297
298 /**
299 Start the program and adds onClose() event at the MainForm
300 Params:
301 mainForm = The Application's main form
302
303 Returns:
304 Zero
305 */
306 public static int run(Form mainForm)
307 {
308 mainForm.close.attach(&onMainFormClose);
309 return Application.doRun(mainForm);
310 }
311
312 /**
313 Close the program.
314 Params:
315 exitCode = Exit code of the program (usually is 0)
316 */
317 public static void exit(int exitCode = 0)
318 {
319 ExitProcess(exitCode);
320 }
321
322 /**
323 When an exception was thrown, the _Application class call this method
324 showing the exception information, the user has the choice to continue the
325 application or terminate it.
326
327 Returns:
328 A DialogResult enum that contains the button clicked by the user (ignore or abort)
329 */
330 package static DialogResult showExceptionForm(Throwable e)
331 {
332 ExceptionForm ef = new ExceptionForm(e);
333 return ef.showDialog();
334 }
335
336 /**
337 Close _Application event attached (internally) at the main form
338 */
339 private static void onMainFormClose(Control sender, EventArgs e)
340 {
341 Application.exit();
342 }
343 }