loginCurtain.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. #include "./loginCurtain.h"
  2. #include "./loginPopup.h"
  3. #include "./common.h"
  4. #include "./graphics.h"
  5. #include "./imageLoader.h"
  6. #include "../resource.h"
  7. #include "../api.h"
  8. #define NWC_LOGINCURTAIN L"NullsoftLoginCurtain"
  9. typedef struct __LOGINCURTAINCREATEPARAM
  10. {
  11. HWND owner;
  12. } LOGINCURTAINCREATEPARAM;
  13. #define NLPF_IMAGEINVALID 0x00000001
  14. typedef struct __LOGINCURTAIN
  15. {
  16. HWND owner;
  17. HBITMAP bkImage;
  18. UINT flags;
  19. UINT childCount;
  20. } LOGINCURTAIN;
  21. typedef struct __DRAWBORDERPARAM
  22. {
  23. HWND hParent;
  24. RECT rect;
  25. HDC hdc;
  26. HDC hdcSrc;
  27. HBITMAP bitmapFrame;
  28. HBITMAP bitmapOrig;
  29. BLENDFUNCTION blendFunc;
  30. } DRAWBORDERPARAM;
  31. typedef struct __UPDATEPOSPARAM
  32. {
  33. HWND hParent;
  34. RECT clientRect;
  35. RECT childRect;
  36. HDWP hdwp;
  37. UINT childCount;
  38. } UPDATEPOSPARAM;
  39. typedef struct __EXCLUDERGNPARAM
  40. {
  41. HWND hParent;
  42. HRGN exclude;
  43. HRGN tmp;
  44. RECT rect;
  45. } EXCLUDERGNPARAM;
  46. #define BACKGROUND_ALPHA 200
  47. #define GetCurtain(__hwnd) ((LOGINCURTAIN*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
  48. static LRESULT WINAPI LoginCurtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  49. static BOOL LoginCurtain_RegisterClass(HINSTANCE hInstance)
  50. {
  51. WNDCLASSW wc;
  52. if (FALSE != GetClassInfo(hInstance, NWC_LOGINCURTAIN, &wc))
  53. return TRUE;
  54. ZeroMemory(&wc, sizeof(wc));
  55. wc.lpszClassName = NWC_LOGINCURTAIN;
  56. wc.lpfnWndProc = LoginCurtain_WindowProc;
  57. wc.style = CS_PARENTDC;
  58. wc.cbWndExtra = sizeof(LOGINCURTAIN*);
  59. wc.hInstance = hInstance;
  60. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  61. return ( 0 != RegisterClassW(&wc));
  62. }
  63. HWND LoginCurtain_CreateWindow(HWND hParent, HWND hOwner)
  64. {
  65. if (FALSE == LoginCurtain_RegisterClass(WASABI_API_ORIG_HINST))
  66. return NULL;
  67. RECT rect;
  68. if (FALSE == GetClientRect(hOwner, &rect))
  69. SetRectEmpty(&rect);
  70. else
  71. MapWindowPoints(hOwner, hParent, (POINT*)&rect, 2);
  72. LOGINCURTAINCREATEPARAM createParam;
  73. createParam.owner = hOwner;
  74. return CreateWindowEx(WS_EX_CONTROLPARENT, NWC_LOGINCURTAIN, NULL,
  75. WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | DS_CONTROL,
  76. rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  77. hParent, NULL, WASABI_API_ORIG_HINST, &createParam);
  78. }
  79. static BOOL CALLBACK LoginCurtain_ExcludeChildRgnCallback(HWND hwnd, LPARAM lParam)
  80. {
  81. EXCLUDERGNPARAM *param = (EXCLUDERGNPARAM*)lParam;
  82. if (NULL == param) return FALSE;
  83. RECT *r = &param->rect;
  84. if (0 == (WS_VISIBLE & GetWindowStyle(hwnd)) ||
  85. param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT) ||
  86. FALSE == GetWindowRect(hwnd, r))
  87. return TRUE;
  88. MapWindowPoints(HWND_DESKTOP, param->hParent, (POINT*)r, 2);
  89. if (NULL == param->tmp)
  90. {
  91. param->tmp = CreateRectRgn(0, 0, 0, 0);
  92. if (NULL == param->tmp) return FALSE;
  93. }
  94. if (NULL == param->exclude)
  95. {
  96. param->exclude = CreateRectRgn(0, 0, 0, 0);
  97. if (NULL == param->exclude) return FALSE;
  98. }
  99. INT regionType = GetWindowRgn(hwnd, param->tmp);
  100. switch(regionType)
  101. {
  102. case NULLREGION:
  103. SetRectRgn(param->tmp, r->left, r->top, r->right, r->bottom);
  104. CombineRgn(param->exclude, param->exclude, param->tmp, RGN_OR);
  105. break;
  106. case SIMPLEREGION:
  107. case COMPLEXREGION:
  108. OffsetRgn(param->tmp, r->left, r->top);
  109. CombineRgn(param->exclude, param->exclude, param->tmp, RGN_OR);
  110. break;
  111. }
  112. return TRUE;
  113. }
  114. static void LoginCurtain_ExcludeChildren(HWND hwnd, HDC hdc)
  115. {
  116. EXCLUDERGNPARAM param;
  117. param.hParent = hwnd;
  118. param.exclude = NULL;
  119. param.tmp = NULL;
  120. EnumChildWindows(hwnd, LoginCurtain_ExcludeChildRgnCallback, (LPARAM)&param);
  121. if (NULL != param.exclude)
  122. {
  123. ExtSelectClipRgn(hdc, param.exclude, RGN_DIFF);
  124. DeleteObject(param.exclude);
  125. }
  126. if (NULL != param.tmp)
  127. DeleteObject(param.tmp);
  128. }
  129. static BOOL CALLBACK LoginCurtain_DrawWindowBorderCallback(HWND hwnd, LPARAM lParam)
  130. {
  131. DRAWBORDERPARAM *param = (DRAWBORDERPARAM*)lParam;
  132. if (NULL == param) return FALSE;
  133. RECT *r = &param->rect;
  134. if (0 == (WS_VISIBLE & GetWindowStyle(hwnd)) ||
  135. param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT) ||
  136. FALSE == GetWindowRect(hwnd, r))
  137. return TRUE;
  138. MapWindowPoints(HWND_DESKTOP, param->hParent, (POINT*)r, 2);
  139. if (NULL == param->bitmapFrame)
  140. {
  141. INT frameHeight, frameWidth;
  142. param->bitmapFrame = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_POPUPBORDER_IMAGE),
  143. TRUE, &frameWidth, &frameHeight);
  144. if (NULL == param->bitmapFrame)
  145. return FALSE;
  146. param->hdcSrc = CreateCompatibleDC(param->hdc);
  147. if (NULL == param->hdcSrc) return FALSE;
  148. param->bitmapOrig = (HBITMAP)SelectObject(param->hdcSrc, param->bitmapFrame);
  149. param->blendFunc.AlphaFormat = AC_SRC_ALPHA;
  150. param->blendFunc.BlendFlags = 0;
  151. param->blendFunc.BlendOp = AC_SRC_OVER;
  152. param->blendFunc.SourceConstantAlpha = 255;
  153. }
  154. r->left -= 14;
  155. r->top -= 13;
  156. r->right += 17;
  157. r->bottom += 19;
  158. GdiAlphaBlend(param->hdc, r->left, r->top, 26, 26, param->hdcSrc, 0, 0, 26, 26, param->blendFunc);
  159. GdiAlphaBlend(param->hdc, r->right - 28, r->top, 28, 26, param->hdcSrc, 27, 0, 28, 26, param->blendFunc);
  160. GdiAlphaBlend(param->hdc, r->left, r->bottom - 31, 26, 31, param->hdcSrc, 0, 27, 26, 31, param->blendFunc);
  161. GdiAlphaBlend(param->hdc, r->right - 28, r->bottom - 31, 28, 31, param->hdcSrc, 27, 27, 28, 31, param->blendFunc);
  162. LONG l = (r->right - r->left - (26 + 28));
  163. GdiAlphaBlend(param->hdc, r->left + 26, r->top, l, 26, param->hdcSrc, 25, 0, 1, 26, param->blendFunc);
  164. GdiAlphaBlend(param->hdc, r->left + 26, r->bottom - 31, l, 31, param->hdcSrc, 25, 27, 1, 31, param->blendFunc);
  165. l = (r->bottom - r->top - (26 + 31));
  166. GdiAlphaBlend(param->hdc, r->left, r->top + 26, 26, l, param->hdcSrc, 0, 28, 26, 1, param->blendFunc);
  167. GdiAlphaBlend(param->hdc, r->right - 28, r->top + 26, 28, l, param->hdcSrc, 27, 28, 28, 1, param->blendFunc);
  168. return TRUE;
  169. }
  170. static void LoginCurtain_DrawChildBorders(HWND hwnd, HDC hdc)
  171. {
  172. DRAWBORDERPARAM param;
  173. ZeroMemory(&param, sizeof(param));
  174. param.hdc = hdc;
  175. param.hParent = hwnd;
  176. EnumChildWindows(hwnd, LoginCurtain_DrawWindowBorderCallback, (LPARAM)&param);
  177. if (NULL != param.hdcSrc)
  178. {
  179. SelectObject(param.hdcSrc, param.bitmapOrig);
  180. DeleteDC(param.hdcSrc);
  181. }
  182. if (NULL != param.bitmapFrame)
  183. DeleteObject(param.bitmapFrame);
  184. }
  185. static HBITMAP LoginCurtain_CreateBkImage(HWND hwnd, HDC hdc, HBITMAP hBitmap, HWND hOwner)
  186. {
  187. RECT rect;
  188. if (FALSE == GetClientRect(hwnd, &rect))
  189. return NULL;
  190. LONG width = rect.right - rect.left;
  191. LONG height = rect.bottom - rect.top;
  192. BITMAP bi;
  193. if (NULL == hBitmap ||
  194. sizeof(BITMAP) != GetObject(hBitmap, sizeof(BITMAP), &bi) ||
  195. bi.bmWidth < width || bi.bmHeight < height)
  196. {
  197. if (NULL != hBitmap)
  198. DeleteObject(hBitmap);
  199. BITMAPINFOHEADER header;
  200. ZeroMemory(&header, sizeof(BITMAPINFOHEADER));
  201. header.biSize = sizeof(BITMAPINFOHEADER);
  202. header.biCompression = BI_RGB;
  203. header.biBitCount = 32;
  204. header.biPlanes = 1;
  205. header.biWidth = (width + 32);
  206. header.biHeight = -(height + 32);
  207. bi.bmBitsPixel = header.biBitCount;
  208. bi.bmWidth = header.biWidth;
  209. bi.bmHeight = header.biHeight;
  210. bi.bmPlanes = header.biPlanes;
  211. hBitmap = CreateDIBSection(NULL, (LPBITMAPINFO)&header, DIB_RGB_COLORS, (void**)&bi.bmBits, NULL, 0);
  212. if (NULL == hBitmap) return NULL;
  213. }
  214. else
  215. {
  216. bi.bmHeight = -bi.bmHeight;
  217. }
  218. HBRUSH bkBrush = (HBRUSH)SendMessage(hOwner, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hwnd);
  219. HBITMAP hbo = (HBITMAP)SelectObject(hdc, hBitmap);
  220. if (NULL == hOwner)
  221. {
  222. if (NULL != bkBrush)
  223. FillRect(hdc, &rect, bkBrush);
  224. else
  225. ExtTextOut(hdc, 0, 0, OPAQUE, &rect, NULL, 0, NULL);
  226. }
  227. else
  228. {
  229. if (FALSE == LoginBox_PrintWindow(hOwner, hdc, 0))
  230. SendMessage(hOwner, WM_PRINT, (WPARAM)hdc, (LPARAM) (PRF_NONCLIENT | PRF_CLIENT | PRF_CHILDREN | PRF_ERASEBKGND));
  231. COLORREF rgbBlend = GetDCBrushColor(hdc);
  232. if (CLR_INVALID == rgbBlend)
  233. rgbBlend = GetBkColor(hdc);
  234. rgbBlend |= (BACKGROUND_ALPHA << 24);
  235. Image_ColorOverEx((BYTE*)bi.bmBits, bi.bmWidth, bi.bmHeight, 0, 0, width, height, bi.bmBitsPixel, FALSE, rgbBlend);
  236. }
  237. LoginCurtain_DrawChildBorders(hwnd, hdc);
  238. SelectObject(hdc, hbo);
  239. return hBitmap;
  240. }
  241. static void LoginCurtain_EraseBkGround(HWND hwnd, HDC hdc, const RECT *prcPaint)
  242. {
  243. LOGINCURTAIN *curtain = GetCurtain(hwnd);
  244. if (NULL == curtain) return;
  245. HDC hdcSrc = CreateCompatibleDC(hdc);
  246. if (NULL == hdcSrc) return;
  247. if (NULL == curtain->bkImage || 0 != (NLPF_IMAGEINVALID & curtain->flags))
  248. {
  249. HRGN clipRegion = CreateRectRgn(0,0,0,0);
  250. if (NULL != clipRegion)
  251. {
  252. INT regionType = GetClipRgn(hdc, clipRegion);
  253. if (1 == regionType)
  254. SelectClipRgn(hdcSrc, clipRegion);
  255. DeleteObject(clipRegion);
  256. }
  257. curtain->bkImage = LoginCurtain_CreateBkImage(hwnd, hdcSrc, curtain->bkImage, curtain->owner);
  258. curtain->flags &= ~NLPF_IMAGEINVALID;
  259. }
  260. if (NULL != curtain->bkImage)
  261. {
  262. HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcSrc, curtain->bkImage);
  263. BitBlt(hdc, prcPaint->left, prcPaint->top,
  264. prcPaint->right - prcPaint->left, prcPaint->bottom - prcPaint->top,
  265. hdcSrc, prcPaint->left, prcPaint->top, SRCCOPY);
  266. SelectObject(hdcSrc, hbmpOld);
  267. }
  268. DeleteDC(hdcSrc);
  269. }
  270. static void LoginCurtain_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
  271. {
  272. if (FALSE != fErase)
  273. {
  274. LoginCurtain_ExcludeChildren(hwnd, hdc);
  275. LoginCurtain_EraseBkGround(hwnd, hdc, prcPaint);
  276. }
  277. }
  278. static BOOL CALLBACK LoginCurtain_UpdateChildPosCallback(HWND hwnd, LPARAM lParam)
  279. {
  280. UPDATEPOSPARAM *param = (UPDATEPOSPARAM*)lParam;
  281. if (NULL == param) return FALSE;
  282. if (param->hParent != (HWND)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_HWNDPARENT))
  283. return TRUE;
  284. if (NULL == param->hdwp)
  285. {
  286. param->hdwp = BeginDeferWindowPos(param->childCount);
  287. param->childCount = 0;
  288. if (NULL == param->hdwp) return FALSE;
  289. }
  290. LONG prevWidth(0), prevHeight(0);
  291. if (FALSE != GetWindowRect(hwnd, &param->childRect))
  292. {
  293. prevWidth = param->childRect.right - param->childRect.left;
  294. prevHeight = param->childRect.bottom - param->childRect.top;
  295. }
  296. if (FALSE != LoginPopup_UpdateWindowPos(hwnd, &param->clientRect, &param->childRect))
  297. {
  298. param->hdwp = DeferWindowPos(param->hdwp, hwnd, NULL, param->childRect.left, param->childRect.top,
  299. param->childRect.right - param->childRect.left, param->childRect.bottom - param->childRect.top,
  300. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW);
  301. if (NULL == param->hdwp) return FALSE;
  302. LONG width = param->childRect.right - param->childRect.left;
  303. LONG height = param->childRect.bottom - param->childRect.top;
  304. if (width != prevWidth || height != prevHeight)
  305. {
  306. HRGN clipRgn = CreateRoundRectRgn(0, 0, width, height, 9, 9);
  307. SetWindowRgn(hwnd, clipRgn, FALSE);
  308. }
  309. }
  310. param->childCount++;
  311. return TRUE;
  312. }
  313. static void LoginCurtain_UpdateLayout(HWND hwnd, BOOL fRedraw)
  314. {
  315. LOGINCURTAIN *curtain = GetCurtain(hwnd);
  316. if (NULL == curtain) return;
  317. curtain->flags |= NLPF_IMAGEINVALID;
  318. RECT clientRect;
  319. GetClientRect(hwnd, &clientRect);
  320. UPDATEPOSPARAM param;
  321. param.hParent = hwnd;
  322. param.hdwp = 0;
  323. param.childCount = curtain->childCount;
  324. CopyRect(&param.clientRect, &clientRect);
  325. param.clientRect.left += 15;
  326. param.clientRect.top += 14;
  327. param.clientRect.right -= 18;
  328. param.clientRect.bottom -= 20;
  329. EnumChildWindows(hwnd, LoginCurtain_UpdateChildPosCallback, (LPARAM)&param);
  330. curtain->childCount = param.childCount;
  331. if (NULL != param.hdwp)
  332. EndDeferWindowPos(param.hdwp);
  333. if (FALSE != fRedraw)
  334. {
  335. RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW | RDW_ALLCHILDREN);
  336. }
  337. }
  338. static LRESULT LoginCurtain_OnCreate(HWND hwnd, CREATESTRUCT* pcs)
  339. {
  340. LOGINCURTAIN *curtain = (LOGINCURTAIN*)calloc(1, sizeof(LOGINCURTAIN));
  341. if (NULL != curtain)
  342. {
  343. SetLastError(ERROR_SUCCESS);
  344. if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)curtain) && ERROR_SUCCESS != GetLastError())
  345. {
  346. free(curtain);
  347. curtain = NULL;
  348. }
  349. }
  350. if (NULL == curtain)
  351. return -1;
  352. LOGINCURTAINCREATEPARAM *createParam = (LOGINCURTAINCREATEPARAM*)pcs->lpCreateParams;
  353. if (NULL != createParam)
  354. {
  355. curtain->owner = createParam->owner;
  356. }
  357. SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOREDRAW);
  358. return 0;
  359. }
  360. static void LoginCurtain_OnDestroy(HWND hwnd)
  361. {
  362. LOGINCURTAIN *curtain = GetCurtain(hwnd);
  363. SetWindowLongPtr(hwnd, 0, 0L);
  364. if (NULL == curtain) return;
  365. if (NULL != curtain->bkImage)
  366. DeleteObject(curtain->bkImage);
  367. free(curtain);
  368. }
  369. static void LoginCurtain_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
  370. {
  371. if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
  372. return;
  373. LoginCurtain_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
  374. }
  375. static void LoginCurtain_OnPaint(HWND hwnd)
  376. {
  377. PAINTSTRUCT ps;
  378. if (BeginPaint(hwnd, &ps))
  379. {
  380. if (ps.rcPaint.left != ps.rcPaint.right)
  381. LoginCurtain_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
  382. EndPaint(hwnd, &ps);
  383. }
  384. }
  385. static void LoginCurtain_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
  386. {
  387. RECT clientRect;
  388. if (GetClientRect(hwnd, &clientRect))
  389. LoginCurtain_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
  390. }
  391. static void LoginCurtain_OnParentNotify(HWND hwnd, INT eventId, INT childId, LPARAM eventParam)
  392. {
  393. switch(eventId)
  394. {
  395. case WM_CREATE:
  396. {
  397. HWND hChild = (HWND)eventParam;
  398. RECT rect;
  399. GetWindowRect(hChild, &rect);
  400. HRGN clipRgn = CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 9, 9);
  401. SetWindowRgn(hChild, clipRgn, FALSE);
  402. }
  403. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED );
  404. break;
  405. case WM_DESTROY:
  406. {
  407. HWND hChild = (HWND)eventParam;
  408. SetWindowLongPtr(hChild, GWLP_ID, 0);
  409. }
  410. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
  411. break;
  412. }
  413. }
  414. static LRESULT LoginCurtain_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
  415. {
  416. HWND hAncestor = GetAncestor(hwnd, GA_PARENT);
  417. if (NULL != hAncestor)
  418. return SendMessage(hAncestor, WM_NOTIFY, (WPARAM)controlId, (LPARAM)pnmh);
  419. return 0;
  420. }
  421. static LRESULT WINAPI LoginCurtain_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  422. {
  423. switch(uMsg)
  424. {
  425. case WM_CREATE: return LoginCurtain_OnCreate(hwnd, (CREATESTRUCT*)lParam);
  426. case WM_DESTROY: LoginCurtain_OnDestroy(hwnd); return 0;
  427. case WM_ERASEBKGND: return 0;
  428. case WM_PAINT: LoginCurtain_OnPaint(hwnd); return 0;
  429. case WM_PRINTCLIENT: LoginCurtain_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
  430. case WM_WINDOWPOSCHANGED: LoginCurtain_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
  431. case WM_SIZE: return 0;
  432. case WM_PARENTNOTIFY: LoginCurtain_OnParentNotify(hwnd, LOWORD(wParam), HIWORD(wParam), lParam); return 0;
  433. case WM_NOTIFY: return LoginCurtain_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
  434. }
  435. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  436. }