/Samples/Extra/ThemedSimpleWakeUp/ThemedSimpleWakeUp.d

http://github.com/AndrejMitrovic/DWinProgramming · D · 400 lines · 278 code · 82 blank · 40 comment · 20 complexity · f5d05f7237109dc0393041433b4a04c8 MD5 · raw file

  1. module ThemedSimpleWakeUp;
  2. // Same as ThemedWakeUp, except it uses a precompiled manifest file.
  3. import core.memory;
  4. import core.runtime;
  5. import core.thread;
  6. import std.conv;
  7. import std.math;
  8. import std.range;
  9. import std.string;
  10. import std.utf;
  11. auto toUTF16z(S)(S s)
  12. {
  13. return toUTFz!(const(wchar)*)(s);
  14. }
  15. pragma(lib, "gdi32.lib");
  16. pragma(lib, "comdlg32.lib");
  17. pragma(lib, "winmm.lib");
  18. pragma(lib, "comctl32.lib");
  19. import core.sys.windows.windef;
  20. import core.sys.windows.winuser;
  21. import core.sys.windows.wingdi;
  22. import core.sys.windows.winbase;
  23. import core.sys.windows.commdlg;
  24. import core.sys.windows.mmsystem;
  25. import core.sys.windows.commctrl;
  26. string appName = "WakeUp";
  27. string description = "WakeUp";
  28. HINSTANCE hinst;
  29. extern (Windows)
  30. int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  31. {
  32. int result;
  33. try
  34. {
  35. Runtime.initialize();
  36. result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
  37. Runtime.terminate();
  38. }
  39. catch (Throwable o)
  40. {
  41. MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
  42. result = 0;
  43. }
  44. return result;
  45. }
  46. int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
  47. {
  48. hinst = hInstance;
  49. HACCEL hAccel;
  50. HWND hwnd;
  51. MSG msg;
  52. WNDCLASS wndclass;
  53. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  54. wndclass.lpfnWndProc = &WndProc;
  55. wndclass.cbClsExtra = 0;
  56. wndclass.cbWndExtra = 0;
  57. wndclass.hInstance = hInstance;
  58. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  59. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  60. wndclass.hbrBackground = cast(HBRUSH) GetStockObject(WHITE_BRUSH);
  61. wndclass.lpszMenuName = appName.toUTF16z;
  62. wndclass.lpszClassName = appName.toUTF16z;
  63. if (!RegisterClass(&wndclass))
  64. {
  65. MessageBox(NULL, "This program requires Windows NT!", appName.toUTF16z, MB_ICONERROR);
  66. return 0;
  67. }
  68. hwnd = CreateWindow(appName.toUTF16z, // window class name
  69. description.toUTF16z, // window caption
  70. WS_OVERLAPPEDWINDOW, // window style
  71. CW_USEDEFAULT, // initial x position
  72. CW_USEDEFAULT, // initial y position
  73. CW_USEDEFAULT, // initial x size
  74. CW_USEDEFAULT, // initial y size
  75. NULL, // parent window handle
  76. NULL, // window menu handle
  77. hInstance, // program instance handle
  78. NULL); // creation parameters
  79. ShowWindow(hwnd, iCmdShow);
  80. UpdateWindow(hwnd);
  81. while (GetMessage(&msg, NULL, 0, 0))
  82. {
  83. TranslateMessage(&msg);
  84. DispatchMessage(&msg);
  85. }
  86. return msg.wParam;
  87. }
  88. // ID values for 3 child windows
  89. enum ID_TIMEPICK = 0;
  90. enum ID_CHECKBOX = 1;
  91. enum ID_PUSHBTN = 2;
  92. // Timer ID
  93. enum ID_TIMER = 1;
  94. // Number of 100-nanosecond increments (ie FILETIME ticks) in an hour
  95. enum FTTICKSPERHOUR = (60 * 60 * cast(LONGLONG)10000000);
  96. // Defines and structure for waveform "file"
  97. enum SAMPRATE = 11025;
  98. enum NUMSAMPS = (3 * SAMPRATE);
  99. enum HALFSAMPS = (NUMSAMPS / 2);
  100. struct WAVEFORM
  101. {
  102. char[4] chRiff;
  103. DWORD dwRiffSize;
  104. char[4] chWave;
  105. char[4] chFmt;
  106. DWORD dwFmtSize;
  107. PCMWAVEFORMAT pwf;
  108. char[4] chData;
  109. DWORD dwDataSize;
  110. BYTE[HALFSAMPS] byData;
  111. }
  112. // Original window procedure addresses for the subclassed windows
  113. WNDPROC[3] SubbedProc;
  114. // The current child window with the input focus
  115. HWND hwndFocus;
  116. extern (Windows)
  117. LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) nothrow
  118. {
  119. scope (failure) assert(0);
  120. static HWND hwndDTP, hwndCheck, hwndPush;
  121. static WAVEFORM waveform = WAVEFORM("RIFF", NUMSAMPS + 0x24, "WAVE", "fmt ",
  122. PCMWAVEFORMAT.sizeof, PCMWAVEFORMAT(WAVEFORMAT(1, 1, SAMPRATE,
  123. SAMPRATE, 1), 8), "data", NUMSAMPS);
  124. FILETIME ft;
  125. HINSTANCE hInstance;
  126. INITCOMMONCONTROLSEX icex;
  127. int i, cxChar, cyChar;
  128. LARGE_INTEGER li;
  129. SYSTEMTIME st;
  130. switch (message)
  131. {
  132. case WM_CREATE:
  133. // Some initialization stuff
  134. hInstance = cast(HINSTANCE)GetWindowLongPtr(hwnd, GWL_HINSTANCE);
  135. icex.dwSize = icex.sizeof;
  136. icex.dwICC = ICC_DATE_CLASSES;
  137. InitCommonControlsEx(&icex);
  138. // Create the waveform file with alternating square waves
  139. //~ waveform = cast(typeof(waveform))GC.malloc(WAVEFORM.sizeof + NUMSAMPS);
  140. //~ *waveform = waveform;
  141. for (i = 0; i < HALFSAMPS; i++)
  142. {
  143. if (i % 600 < 300)
  144. {
  145. if (i % 16 < 8)
  146. waveform.byData[i] = 25;
  147. else
  148. waveform.byData[i] = 230;
  149. }
  150. else if (i % 8 < 4)
  151. waveform.byData[i] = 25;
  152. else
  153. waveform.byData[i] = 230;
  154. }
  155. // Get character size and set a fixed window size.
  156. cxChar = LOWORD(GetDialogBaseUnits());
  157. cyChar = HIWORD(GetDialogBaseUnits());
  158. SetWindowPos(hwnd, NULL, 0, 0,
  159. 42 * cxChar,
  160. 10 * cyChar / 3 + 2 * GetSystemMetrics(SM_CYBORDER) +
  161. GetSystemMetrics(SM_CYCAPTION),
  162. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  163. // Create the three child windows
  164. hwndDTP = CreateWindow((DATETIMEPICK_CLASS ~ 0).ptr, "",
  165. WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_TIMEFORMAT,
  166. 2 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
  167. hwnd, cast(HMENU)ID_TIMEPICK, hInstance, NULL);
  168. hwndCheck = CreateWindow("Button", "Set Alarm",
  169. WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
  170. 16 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
  171. hwnd, cast(HMENU)ID_CHECKBOX, hInstance, NULL);
  172. hwndPush = CreateWindow("Button", "Turn Off",
  173. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
  174. 28 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
  175. hwnd, cast(HMENU)ID_PUSHBTN, hInstance, NULL);
  176. hwndFocus = hwndDTP;
  177. // Subclass the three child windows
  178. SubbedProc[ID_TIMEPICK] = cast(WNDPROC)SetWindowLongPtr(hwndDTP, GWL_WNDPROC, cast(LONG)&SubProc);
  179. SubbedProc[ID_CHECKBOX] = cast(WNDPROC)SetWindowLongPtr(hwndCheck, GWL_WNDPROC, cast(LONG)&SubProc);
  180. SubbedProc[ID_PUSHBTN] = cast(WNDPROC)SetWindowLongPtr(hwndPush, GWL_WNDPROC, cast(LONG)&SubProc);
  181. // Set the date and time picker control to the current time
  182. // plus 9 hours, rounded down to next lowest hour
  183. GetLocalTime(&st);
  184. SystemTimeToFileTime(&st, &ft);
  185. li = *cast(LARGE_INTEGER*) & ft;
  186. li.QuadPart += 9 * FTTICKSPERHOUR;
  187. ft = *cast(FILETIME*) & li;
  188. FileTimeToSystemTime(&ft, &st);
  189. st.wMinute = st.wSecond = st.wMilliseconds = 0;
  190. SendMessage(hwndDTP, DTM_SETSYSTEMTIME, 0, cast(LPARAM)&st);
  191. return 0;
  192. case WM_SETFOCUS:
  193. SetFocus(hwndFocus);
  194. return 0;
  195. case WM_COMMAND:
  196. switch (LOWORD(wParam)) // control ID
  197. {
  198. case ID_CHECKBOX:
  199. // When the user checks the "Set Alarm" button, get the
  200. // time in the date and time control and subtract from
  201. // it the current PC time.
  202. if (SendMessage(hwndCheck, BM_GETCHECK, 0, 0))
  203. {
  204. SendMessage(hwndDTP, DTM_GETSYSTEMTIME, 0, cast(LPARAM)&st);
  205. SystemTimeToFileTime(&st, &ft);
  206. li = *cast(LARGE_INTEGER*)&ft;
  207. GetLocalTime(&st);
  208. SystemTimeToFileTime(&st, &ft);
  209. li.QuadPart -= (cast(LARGE_INTEGER*)&ft).QuadPart;
  210. // Make sure the time is between 0 and 24 hours!
  211. // These little adjustments let us completely ignore
  212. // the date part of the SYSTEMTIME structures.
  213. while (li.QuadPart < 0)
  214. li.QuadPart += 24 * FTTICKSPERHOUR;
  215. li.QuadPart %= 24 * FTTICKSPERHOUR;
  216. // Set a one-shot timer! (See you in the morning.)
  217. SetTimer(hwnd, ID_TIMER, cast(int)(li.QuadPart / 10000), null);
  218. }
  219. else
  220. {
  221. // If button is being unchecked, kill the timer.
  222. KillTimer(hwnd, ID_TIMER);
  223. }
  224. return 0;
  225. // The "Turn Off" button turns off the ringing alarm, and also
  226. // unchecks the "Set Alarm" button and disables itself.
  227. case ID_PUSHBTN:
  228. PlaySound(NULL, NULL, 0);
  229. SendMessage(hwndCheck, BM_SETCHECK, 0, 0);
  230. EnableWindow(hwndDTP, TRUE);
  231. EnableWindow(hwndCheck, TRUE);
  232. EnableWindow(hwndPush, FALSE);
  233. SetFocus(hwndDTP);
  234. return 0;
  235. default:
  236. }
  237. return 0;
  238. // The WM_NOTIFY message comes from the date and time picker.
  239. // If the user has checked "Set Alarm" and then gone back to
  240. // change the alarm time, there might be a discrepancy between
  241. // the displayed time and the one-shot timer. So the program
  242. // unchecks "Set Alarm" and kills any outstanding timer.
  243. case WM_NOTIFY:
  244. switch (wParam) // control ID
  245. {
  246. case ID_TIMEPICK:
  247. switch ((cast(NMHDR*)lParam).code) // notification code
  248. {
  249. case DTN_DATETIMECHANGE:
  250. if (SendMessage(hwndCheck, BM_GETCHECK, 0, 0))
  251. {
  252. KillTimer(hwnd, ID_TIMER);
  253. SendMessage(hwndCheck, BM_SETCHECK, 0, 0);
  254. }
  255. return 0;
  256. default:
  257. }
  258. break;
  259. default:
  260. }
  261. return 0;
  262. // The WM_COMMAND message comes from the two buttons.
  263. case WM_TIMER:
  264. // When the timer message comes, kill the timer (because we only
  265. // want a one-shot) and start the annoying alarm noise going.
  266. KillTimer(hwnd, ID_TIMER);
  267. PlaySound(cast(PTSTR)&waveform, NULL,
  268. SND_MEMORY | SND_LOOP | SND_ASYNC);
  269. // Let the sleepy user turn off the timer by slapping the
  270. // space bar. If the window is minimized, it's restored; then it's
  271. // brought to the forefront; then the pushbutton is enabled and
  272. // given the input focus.
  273. EnableWindow(hwndDTP, FALSE);
  274. EnableWindow(hwndCheck, FALSE);
  275. EnableWindow(hwndPush, TRUE);
  276. hwndFocus = hwndPush;
  277. ShowWindow(hwnd, SW_RESTORE);
  278. SetForegroundWindow(hwnd);
  279. return 0;
  280. // Clean up if the alarm is ringing or the timer is still set.
  281. case WM_DESTROY:
  282. //~ GC.free(waveform);
  283. if (IsWindowEnabled(hwndPush))
  284. PlaySound(NULL, NULL, 0);
  285. if (SendMessage(hwndCheck, BM_GETCHECK, 0, 0))
  286. KillTimer(hwnd, ID_TIMER);
  287. PostQuitMessage(0);
  288. return 0;
  289. default:
  290. }
  291. return DefWindowProc(hwnd, message, wParam, lParam);
  292. }
  293. extern (Windows)
  294. LRESULT SubProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  295. {
  296. int idNext, id = GetWindowLongPtr(hwnd, GWL_ID);
  297. switch (message)
  298. {
  299. case WM_CHAR:
  300. if (wParam == '\t')
  301. {
  302. idNext = id;
  303. do
  304. {
  305. idNext = (idNext + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3;
  306. }
  307. while (!IsWindowEnabled(GetDlgItem(GetParent(hwnd), idNext)));
  308. SetFocus(GetDlgItem(GetParent(hwnd), idNext));
  309. return 0;
  310. }
  311. break;
  312. case WM_SETFOCUS:
  313. hwndFocus = hwnd;
  314. break;
  315. default:
  316. }
  317. return CallWindowProc(SubbedProc[id], hwnd, message, wParam, lParam);
  318. }