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.\r\n1) Click \"Ignore\" to continue (The program can be unstable).\r\n2) Click \"Quit\" to exit.\r\n", 31 xpManifest = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` "\r\n" 32 `<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">` "\r\n" 33 `<assemblyIdentity` "\r\n" 34 `version="1.0.0.0"` "\r\n" 35 `processorArchitecture="X86"` "\r\n" 36 `name="client"` "\r\n" 37 `type="win32"` "\r\n" 38 `/>` "\r\n" 39 `<description></description>` "\r\n" 40 "\r\n" 41 `<!-- Enable Windows XP and higher themes with common controls -->` "\r\n" 42 `<dependency>` "\r\n" 43 `<dependentAssembly>` "\r\n" 44 `<assemblyIdentity` "\r\n" 45 `type="win32"` "\r\n" 46 `name="Microsoft.Windows.Common-Controls"` "\r\n" 47 `version="6.0.0.0"` "\r\n" 48 `processorArchitecture="X86"` "\r\n" 49 `publicKeyToken="6595b64144ccf1df"` "\r\n" 50 `language="*"` "\r\n" 51 `/>` "\r\n" 52 `</dependentAssembly>` "\r\n" 53 `</dependency>` "\r\n" 54 "\r\n" 55 `<!-- Disable Windows Vista UAC compatibility heuristics -->` "\r\n" 56 `<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">` "\r\n" 57 `<security>` "\r\n" 58 `<requestedPrivileges>` "\r\n" 59 `<requestedExecutionLevel level="asInvoker"/>` "\r\n" 60 `</requestedPrivileges>` "\r\n" 61 `</security>` "\r\n" 62 `</trustInfo> ` "\r\n" 63 "\r\n" 64 `<!-- Enable Windows Vista-style font scaling on Vista -->` "\r\n" 65 `<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">` "\r\n" 66 `<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">` "\r\n" 67 `<dpiAware>true</dpiAware>` "\r\n" 68 `</asmv3:windowsSettings>` "\r\n" 69 `</asmv3:application>` "\r\n" 70 `</assembly>` "\r\n", 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 }