PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Samples/Chap22/WakeUp/WakeUp.d

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