Advertisement
ahmd0

GetWindowTheme looses HTHEME after SetWindowLongPtr call

Mar 23rd, 2019
440
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.40 KB | None | 0 0
  1. // TestGetWindowTheme.cpp : Defines the entry point for the application.
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "TestGetWindowTheme.h"
  6.  
  7. #include <assert.h>
  8. #include <uxtheme.h>
  9. #pragma comment(lib, "UxTheme.lib")
  10.  
  11.  
  12.  
  13. #define MAX_LOADSTRING 100
  14.  
  15. // Global Variables:
  16. HINSTANCE hInst;                                // current instance
  17. WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
  18. WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
  19.  
  20. // Forward declarations of functions included in this code module:
  21. ATOM                MyRegisterClass(HINSTANCE hInstance);
  22. BOOL                InitInstance(HINSTANCE, int);
  23. LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
  24. INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
  25. LRESULT CALLBACK OriginalWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  26.  
  27.  
  28. int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
  29.                      _In_opt_ HINSTANCE hPrevInstance,
  30.                      _In_ LPWSTR    lpCmdLine,
  31.                      _In_ int       nCmdShow)
  32. {
  33.     UNREFERENCED_PARAMETER(hPrevInstance);
  34.     UNREFERENCED_PARAMETER(lpCmdLine);
  35.  
  36.     // TODO: Place code here.
  37.  
  38.     // Initialize global strings
  39.     LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  40.     LoadStringW(hInstance, IDC_TESTGETWINDOWTHEME, szWindowClass, MAX_LOADSTRING);
  41.     if(!MyRegisterClass(hInstance))
  42.     {
  43.         return -1;
  44.     }
  45.  
  46.     // Perform application initialization:
  47.     if (!InitInstance (hInstance, nCmdShow))
  48.     {
  49.         return FALSE;
  50.     }
  51.  
  52.     HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTGETWINDOWTHEME));
  53.  
  54.     MSG msg;
  55.  
  56.     // Main message loop:
  57.     while (GetMessage(&msg, nullptr, 0, 0))
  58.     {
  59.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  60.         {
  61.             TranslateMessage(&msg);
  62.             DispatchMessage(&msg);
  63.         }
  64.     }
  65.  
  66.     return (int) msg.wParam;
  67. }
  68.  
  69.  
  70.  
  71. //
  72. //  FUNCTION: MyRegisterClass()
  73. //
  74. //  PURPOSE: Registers the window class.
  75. //
  76. ATOM MyRegisterClass(HINSTANCE hInstance)
  77. {
  78.     WNDCLASSEXW wcex;
  79.  
  80.     wcex.cbSize = sizeof(WNDCLASSEX);
  81.  
  82.     wcex.style          = CS_HREDRAW | CS_VREDRAW;
  83.     wcex.lpfnWndProc    = WndProc;
  84.     wcex.cbClsExtra     = 0;
  85.     wcex.cbWndExtra     = sizeof(HWND);
  86.     wcex.hInstance      = hInstance;
  87.     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTGETWINDOWTHEME));
  88.     wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
  89.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  90.     wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TESTGETWINDOWTHEME);
  91.     wcex.lpszClassName  = szWindowClass;
  92.     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
  93.  
  94.     BOOL bRes = RegisterClassExW(&wcex);
  95.  
  96.  
  97.  
  98.     WNDCLASSEXW wc = {0};
  99.  
  100.     wc.cbSize = sizeof(wc);
  101.     wc.lpszClassName = L"myclassname";
  102.     wc.style = CS_DBLCLKS | CS_PARENTDC;
  103.     wc.lpfnWndProc = (WNDPROC)OriginalWindowProc;
  104.     wc.hInstance = hInstance;
  105.  
  106.     if(!::RegisterClassExW(&wc))
  107.     {
  108.         int Err = ::GetLastError();
  109.         bRes = FALSE;
  110.         assert(NULL);
  111.     }
  112.  
  113.     return bRes;
  114. }
  115.  
  116. //
  117. //   FUNCTION: InitInstance(HINSTANCE, int)
  118. //
  119. //   PURPOSE: Saves instance handle and creates main window
  120. //
  121. //   COMMENTS:
  122. //
  123. //        In this function, we save the instance handle in a global variable and
  124. //        create and display the main program window.
  125. //
  126. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  127. {
  128.    hInst = hInstance; // Store instance handle in our global variable
  129.  
  130.    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  131.       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, hInstance);
  132.  
  133.    if (!hWnd)
  134.    {
  135.       return FALSE;
  136.    }
  137.  
  138.    ShowWindow(hWnd, nCmdShow);
  139.    UpdateWindow(hWnd);
  140.  
  141.    return TRUE;
  142. }
  143.  
  144. //
  145. //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
  146. //
  147. //  PURPOSE: Processes messages for the main window.
  148. //
  149. //  WM_COMMAND  - process the application menu
  150. //  WM_PAINT    - Paint the main window
  151. //  WM_DESTROY  - post a quit message and return
  152. //
  153. //
  154. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  155. {
  156.     switch (message)
  157.     {
  158.         case WM_CREATE:
  159.         {  
  160.             int nErr;
  161.  
  162.             HWND hChWnd = ::CreateWindowEx(0,
  163.                 L"myclassname",
  164.                 L"",
  165.                 WS_VISIBLE | WS_CHILD,
  166.                 50, 20, 100, 100, hWnd, NULL, hInst, NULL);
  167.             if(!hChWnd)
  168.             {
  169.                 nErr = ::GetLastError();
  170.                 assert(NULL);
  171.             }
  172.  
  173.             ::SetLastError(0);
  174.             ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)hChWnd);
  175.             assert(!(nErr = ::GetLastError()));
  176.         }
  177.         break;
  178.  
  179.     case WM_COMMAND:
  180.         {
  181.             int wmId = LOWORD(wParam);
  182.             // Parse the menu selections:
  183.             switch (wmId)
  184.             {
  185.             case IDM_ABOUT:
  186.                 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
  187.                 break;
  188.             case IDM_EXIT:
  189.                 DestroyWindow(hWnd);
  190.                 break;
  191.             default:
  192.                 return DefWindowProc(hWnd, message, wParam, lParam);
  193.             }
  194.         }
  195.         break;
  196.  
  197.     case WM_PAINT:
  198.         {
  199.             PAINTSTRUCT ps;
  200.             HDC hdc = BeginPaint(hWnd, &ps);
  201.             // TODO: Add any drawing code that uses hdc here...
  202.  
  203.             HWND hChildWnd = (HWND)::GetWindowLongPtr(hWnd, 0);
  204.             assert(hChildWnd != 0);
  205.  
  206.             WCHAR buff[256];
  207.             wsprintfW(buff, L"Click here to illustrate the bug ... hTheme: 0x%p", ::GetWindowTheme(hChildWnd));
  208.             ::TextOut(hdc, 20, 130, buff, (int)wcslen(buff));
  209.  
  210.             EndPaint(hWnd, &ps);
  211.         }
  212.         break;
  213.  
  214.     case WM_LBUTTONDOWN:
  215.     {
  216.         HWND hChildWnd = (HWND)::GetWindowLongPtr(hWnd, 0);
  217.         assert(hChildWnd != 0);
  218.  
  219.         DWORD_PTR dwStyle = ::GetWindowLongPtr(hChildWnd, GWL_STYLE);
  220.     //  dwStyle ^= WS_BORDER;
  221.         ::SetWindowLongPtr(hChildWnd, GWL_STYLE, dwStyle);      //Calling this causes 'hChildWnd' wnd to loose its theme. Why???
  222.  
  223.         //Redraw self
  224.         ::InvalidateRect(hWnd, NULL, TRUE);
  225.     }
  226.     break;
  227.  
  228.     case WM_DESTROY:
  229.     {
  230.         HWND hChildWnd = (HWND)::GetWindowLongPtr(hWnd, 0);
  231.         assert(hChildWnd != 0);
  232.         assert(::DestroyWindow(hChildWnd));
  233.  
  234.         PostQuitMessage(0);
  235.     }
  236.     break;
  237.  
  238.     default:
  239.         return DefWindowProc(hWnd, message, wParam, lParam);
  240.     }
  241.     return 0;
  242. }
  243.  
  244. // Message handler for about box.
  245. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  246. {
  247.     UNREFERENCED_PARAMETER(lParam);
  248.     switch (message)
  249.     {
  250.     case WM_INITDIALOG:
  251.         return (INT_PTR)TRUE;
  252.  
  253.     case WM_COMMAND:
  254.         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  255.         {
  256.             EndDialog(hDlg, LOWORD(wParam));
  257.             return (INT_PTR)TRUE;
  258.         }
  259.         break;
  260.     }
  261.     return (INT_PTR)FALSE;
  262. }
  263.  
  264.  
  265.  
  266.  
  267. LRESULT CALLBACK OriginalWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  268. {
  269.     switch (message)
  270.     {
  271.         case WM_NCCREATE:
  272.         {
  273.             HTHEME hTheme = ::OpenThemeData(hWnd, L"EDIT");
  274.             assert(hTheme);
  275.             assert(::GetWindowTheme(hWnd) != 0);
  276.  
  277.             return 1;
  278.         }
  279.         break;
  280.  
  281.         case WM_ERASEBKGND:
  282.         {
  283.             HDC hDc = (HDC)wParam;
  284.             RECT rc;
  285.             ::GetClientRect(hWnd, &rc);
  286.             ::FillRect(hDc, &rc, (HBRUSH)::GetStockObject(LTGRAY_BRUSH));
  287.         }
  288.         return 1;
  289.  
  290.         case WM_DESTROY:
  291.         {
  292.             HTHEME hTheme = ::GetWindowTheme(hWnd);
  293.             assert(hTheme);
  294.             assert(::CloseThemeData(hTheme) == S_OK);
  295.         }
  296.         break;
  297.  
  298.         default:
  299.             return DefWindowProc(hWnd, message, wParam, lParam);
  300.     }
  301.  
  302.     return 0;
  303. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement