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