WinAPI Window with Skins



  • Hallo.

    Folgender code geht nicht. Ich weiß nicht woran es liegt. Der Compiler meldet nichts. Jedenfalls wird ein window erstellt, aber wenn man die Leertaste oder 'Test' drückt, kein Skin.
    Könnt ihr mir helfen?

    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <iostream.h>
    #include "resource.h"
    
    HINSTANCE hInst;
    HDC     dcSkin;
    HWND hWnd=NULL;
    HBITMAP hSkinBmp, hOldBmp;
    
    void SkinMe(HDC dc) { BitBlt(dc, 0,0,333,333, dcSkin, 0,0, SRCCOPY); }
    void RegionMe();
    void UnRegionMe();
    bool MakeWindow(int iWidth, int iHeight);
    
    BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
        switch(uMsg)
        {
            case WM_INITDIALOG:
                /*
                 * TODO: Add code to initialize the dialog.
                 */
                return TRUE;
    
            case WM_CLOSE:
                EndDialog(hWnd, 0);
                return TRUE;
    
            case WM_COMMAND:
                switch(LOWORD(wParam))
                {
                    case IDC_BTN_QUIT:
                        EndDialog(hWnd, 0);
                        return TRUE;
    
                    case IDC_BTN_TEST:
                       // MessageBox(hWnd, "You clicked!", "Information", MB_ICONINFORMATION);
                        SkinMe(GetDC(0));
                        return TRUE;
                }
              case WM_KEYDOWN:
              {
    
          switch (wParam)
          {
            case VK_ESCAPE:
              PostQuitMessage(0);
              break;
    
            case VK_SPACE:
    
                SkinMe(GetDC(0));
                break;
    
          }
          break;
        }
    
        case WM_PAINT:
        {
          // -------------------------------------------------
          // tell user to press SPACE to toggle region.
          // -------------------------------------------------
    
          PAINTSTRUCT ps;
          BeginPaint(hWnd,&ps);
    
          SkinMe(ps.hdc);
          SetBkMode(ps.hdc,TRANSPARENT);
          SetTextColor(ps.hdc,RGB(255,0,0));
          TextOut(ps.hdc, 115,90, "Press SPACE", 11);
    
          EndPaint(hWnd,&ps);
    
          break;
        }
        }
    
        return DefWindowProc (hWnd, uMsg, wParam, lParam) ;
    }
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    
      hInst = hInstance;
    
      // load the skin bitmap from resource
      hSkinBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SKIN));
      if (!hSkinBmp) {
          cout << "cant load bitmap" << endl;
          return -1;
      }
      // create a device context for the skin
      dcSkin = GetDC(0);
    
      // select the skin bitmap
      hOldBmp = (HBITMAP)SelectObject(dcSkin, hSkinBmp);
    
      // -------------------------------------------------
      // create the application window.
      // -------------------------------------------------
    
      if ( !MakeWindow(320, 240) )  {
          cout << "cant makewindow" <<endl;
      //    return -1;
      }
      // show window
      ShowWindow(hWnd, SW_SHOW);
    
      MSG mMsg;
    /*
      while (1)
      {
    
        if(PeekMessage(&mMsg, 0, 0, 0, PM_REMOVE))
        {
          if(mMsg.message == WM_QUIT) {
              break;
          }
          TranslateMessage(&mMsg);
          DispatchMessage(&mMsg);
        }
    
      }
      */
      SelectObject(dcSkin, hOldBmp);
      DeleteObject(hSkinBmp);
      DeleteDC(dcSkin);
      DestroyWindow(hWnd);
    
      return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, DialogProc);
    }
    
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    
    void RegionMe() {
      DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
      dwStyle &= ~(WS_CAPTION|WS_SIZEBOX);
      SetWindowLong(hWnd, GWL_STYLE, dwStyle);
    
      InvalidateRect(hWnd, NULL, TRUE);
      SetWindowPos(hWnd, NULL, 0,0,444,444, SWP_NOMOVE|SWP_NOZORDER);
    }
    
    void UnRegionMe() {
      SetWindowRgn(hWnd, NULL, true);
      DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
      dwStyle |= WS_CAPTION|WS_SIZEBOX;
      SetWindowLong(hWnd, GWL_STYLE, dwStyle);
      InvalidateRect(hWnd, NULL, TRUE);
      SetWindowPos(hWnd, NULL, 0,0,320,240, SWP_NOMOVE|SWP_NOZORDER);
    }
    
    bool MakeWindow(int iWidth, int iHeight)
    {
      // our window class
      WNDCLASS wndWc;
    
      wndWc.style = CS_OWNDC;
      wndWc.lpfnWndProc = (WNDPROC) DialogProc;
      wndWc.cbClsExtra = 0;
      wndWc.cbWndExtra = 0;
      wndWc.hInstance = GetModuleHandle(NULL);
      wndWc.hIcon = NULL;
      wndWc.hCursor = LoadCursor(0, IDC_ARROW);
      wndWc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wndWc.lpszMenuName = NULL;
      wndWc.lpszClassName = "w32skin";
    
      if (!RegisterClass(&wndWc)) {
          std::cout <<"error reg" << std::endl;
          return false;
      }
    
      hWnd = CreateWindow("w32skin", "       w32skin",
                          WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                          100,100, iWidth,iHeight,
                          NULL, NULL, GetModuleHandle(NULL), NULL
             );
             cout << hWnd << endl;
      GetLastError();
      return (hWnd);
    
    }
    


  • Schlägt SelectObject() da nicht fehl?

    // create a device context for the skin
      dcSkin = GetDC(0);
    
      // select the skin bitmap
      hOldBmp = (HBITMAP)SelectObject(dcSkin, hSkinBmp);
    

    Gemeint ist wohl eher:

    // create a device context for the skin
      dcSkin = CreateCompatibleDC(NULL);
    
      // select the skin bitmap
      hOldBmp = (HBITMAP)SelectObject(dcSkin, hSkinBmp);
    


  • blödsinn, wie wärs mit GetDC(hwnd)?



  • Gut,
    ich habe mal zudem jedes GetDC(0) zu GetDC(hWnd) geändert.
    Dennoch geht es nicht.

    Das Problem ist immernoch das gleiche.

    Was wir aufgefallen ist:
    MakeWindow wird ausgeführt, aber das Fenster verschwindet direkt wieder und ein neues, mit einer anderen größe tritten in Erscheinung. Das verwundert mich, weil ich doch eigentlich nur MakeWindow aufgerufen habe.

    Das aktuelle Komplette Projekt:
    main.cpp:

    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <iostream.h>
    #include "resource.h"
    
    HINSTANCE hInst;
    HDC     dcSkin;
    HWND hWnd;
    HBITMAP hSkinBmp, hOldBmp;
    
    void SkinMe(HDC dc) { BitBlt(dc, 0,0,333,333, dcSkin, 0,0, SRCCOPY); }
    bool MakeWindow(int iWidth, int iHeight);
    
    BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    
        switch(uMsg) {
            case WM_INITDIALOG:
                SkinMe(GetDC(hWnd));
                return TRUE;
    
            case WM_CLOSE:
                EndDialog(hWnd, 0);
                return TRUE;
    
            case WM_COMMAND:
                switch(LOWORD(wParam))
                {
                    case IDC_BTN_QUIT:
                        EndDialog(hWnd, 0);
                        return TRUE;
    
                    case IDC_BTN_TEST:
                        MessageBox(hWnd, "You clicked!", "Information", MB_ICONINFORMATION);
                        SkinMe(GetDC(hWnd));
                        return TRUE;
                }
              case WM_KEYDOWN: {
    
                switch (wParam) {
                    case VK_ESCAPE:
                        PostQuitMessage(0);
                        break;
                    case VK_SPACE:
                        SkinMe(GetDC(hWnd));
                        break;
                }
                break;
              }
    
        case WM_PAINT:
          {
          PAINTSTRUCT ps;
          BeginPaint(hWnd,&ps);
    
          SkinMe(ps.hdc);
          SetBkMode(ps.hdc,TRANSPARENT);
          SetTextColor(ps.hdc,RGB(255,0,0));
          TextOut(ps.hdc, 115,90, "Press SPACE", 11);
    
          EndPaint(hWnd,&ps);
          break;
          }
        }
    
        return DefWindowProc (hWnd, uMsg, wParam, lParam) ;
    }
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
      hInst = hInstance;
    
      // load the skin bitmap from resource
      hSkinBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SKIN));
      if (!hSkinBmp) {
          cout << "cant load bitmap" << endl;
          return -1;
      }
      // create a device context for the skin
      dcSkin = GetDC(hWnd);
    
      // select the skin bitmap
      hOldBmp = (HBITMAP)SelectObject(dcSkin, hSkinBmp);
    
      if ( !MakeWindow(320, 840) )  {
          cout << "cant makewindow" <<endl;
          return -1;
      }
      // show window
      ShowWindow(hWnd, SW_SHOW);
    
      SkinMe(dcSkin);
      SelectObject(dcSkin, hOldBmp);
      DeleteObject(hSkinBmp);
      DeleteDC(dcSkin);
      DestroyWindow(hWnd);
    
      return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, DialogProc);
    }
    
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    
    bool MakeWindow(int iWidth, int iHeight)
    {
      // our window class
      WNDCLASS wndWc;
    
      wndWc.style = CS_OWNDC;
      wndWc.lpfnWndProc = (WNDPROC) DialogProc;
      wndWc.cbClsExtra = 0;
      wndWc.cbWndExtra = 0;
      wndWc.hInstance = GetModuleHandle(NULL);
      wndWc.hIcon = NULL;
      wndWc.hCursor = LoadCursor(0, IDC_ARROW);
      wndWc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wndWc.lpszMenuName = NULL;
      wndWc.lpszClassName = "w32skin";
    
      if (!RegisterClass(&wndWc)) {
          std::cout <<"error reg" << std::endl;
          return false;
      }
    
      hWnd = CreateWindow("w32skin", "       w32skin",
                          WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                          100,100, iWidth,iHeight,
                          NULL, NULL, GetModuleHandle(NULL), NULL
             );
             cout << hWnd << endl;
      GetLastError();
      return (hWnd);
    
    }
    

    resource.h:

    #include <windows.h>
    
    // ID of Main Dialog
    #define DLG_MAIN 102
    
    #define IDB_BITMAP1                     101
    #define IDB_SKIN                        101
    
    // ID of Button Controls
    #define IDC_BTN_TEST 1001
    #define IDC_BTN_QUIT 1002
    

    resource.rc:

    #include "resource.h"
    
    IDB_SKIN BITMAP DISCARDABLE  "skin.bmp"
    DLG_MAIN DIALOGEX 6, 5, 194, 106
    
    CAPTION "Tofino GamerzTalk"
    
    FONT 8, "MS Sans Serif", 0, 0, 1
    
    STYLE 0x10CE0804
    
    BEGIN
      CONTROL "&Test", IDC_BTN_TEST, "Button", 0x10010000, 138,  5, 46, 15
      CONTROL "&Quit", IDC_BTN_QUIT, "Button", 0x10010000, 138, 29, 46, 15
    END
    


  • Du rufst ja auch direkt DestroyWindow auf 😉



  • Du hast recht 😃

    Dennoch erscheint in dem Window der Skin nicht. Nur ein ganz großer fehler: Ein Teil des Desktops wird im wondow eingeblendet. Wie man es kennt wenn der rechner nicht ganz mitkommt 😉



  • So wie ich den Code verstehe soll in dcSkin die Skin-Bitmap selektiert werden und mit SkinMe (bzw. BitBlt) dann ins Fenster gezeichnet werden.

    Wenn du da noch dcSkin=GetDC(hWnd) stehen hast wird das darauffolgende SelectObject() fehlschlagen - Man kann meines Wissens Bitmaps nur in Memory-DCs selektieren, welche man z.B. mit CreateCompatibleDC() erzeugen kann.

    Im Moment ist bei SkinMe() Ziel- und Quelle identisch (In WM_PAINT bekommst du einen DC deines Fensters und GetDC() liefert auch einen DC deines Fensters).
    GetDC(0) würde den DC des Desktops liefern.



  • Danke geeky,
    erst dachte ich es wäre ein 'nicht-meine-schuld'-Aufreger.

    Na gut. Um ganz erlich zu sein, verstehe ich dein letzten Post nicht komplett 😕

    So wie ich den Code verstehe soll in dcSkin die Skin-Bitmap selektiert werden und mit SkinMe (bzw. BitBlt) dann ins Fenster gezeichnet werden.

    Korrekt.

    Wenn du da noch dcSkin=GetDC(hWnd) stehen hast wird das darauffolgende SelectObject() fehlschlagen - Man kann meines Wissens Bitmaps nur in Memory-DCs selektieren, welche man z.B. mit CreateCompatibleDC() erzeugen kann.

    Ich habe mal alle dcSkin=GeDC(hWnd) rausgenommen, da es ja anscheinbar komplett falsch ist. Den zweiten Teil des Satzes verstehe ich nicht. GetDC funktioniert. Warum dann CreateCompatibleDC?
    Geladen wir die BITMAP hier:

    hSkinBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SKIN));
    

    Im Moment ist bei SkinMe() Ziel- und Quelle identisch (In WM_PAINT bekommst du einen DC deines Fensters und GetDC() liefert auch einen DC deines Fensters).
    GetDC(0) würde den DC des Desktops liefern.

    WM_PAINT hab ich mal komplett gelöscht. Es soll da eh nicht drinn stehen und das was da zZ dirnn steht ist eh falsch. Wo das Ziel und die Quelle identisch sein soll, sehe ich leider nicht.

    SkinMe(HDC dc) { BitBlt(dc, 0,0,333,333, dcSkin, 0,0, SRCCOPY);
    

    Der Parameter den ich übergebe ist ja der DC des Window (hWnd) - darein wird mit BitBlt dcSkin geklatscht.
    Get(0) ist auf jeden fall falsch - kapiere ich nun. Das mit dem desktop wusste ich nicht.

    Ich frag mich 2 Dinge:
    Warum werden 2 Fenster angezeigt. Warum wird das bild skin.bmp nicht reingeladen. Kann es sein, dass es so direkt garnicht möglich ist den SKin in eine DialogBox zu laden?



  • dcSkin = GetDC(hWnd);
    hOldBmp = (HBITMAP)SelectObject(dcSkin, hSkinBmp);
    

    ...würde bedeuten du selektierst die Bitmap hSkinBmp in den DeviceContext der zu hWnd gehört, die Bitmap quasi in dein Fenster selektieren.
    Würde sowas funktionieren wäre BitBlt() überflüssig.

    Für gewöhnlich lädt man eine Bitmap in einen Memory-DC um sie dann mittels BitBlt() auf einen Display-DC zu kopieren.
    GetDC(FensterHandle) liefert für gewöhnlich einen Display-DC.
    CreateCompatibleDC(DeviceContextHandle) liefert einen Memory-DC mit denselben Farbeinstellungen, etc. wie der DeviceContextHandle-DC.
    CreateCompatibleDC(NULL) erzeugt quasi einen zum aktuellen Desktop kompatiblen Memory-DC. Dort kann dann eine Bitmap rein-selektiert werden, welche dann mit BitBlt() auf x-beliebige andere DCs (wie z.B. dem deines Fensters) kopiert werden kann.

    Das zweite Fenster kommt durch return DialogBox(...), welches einen irgendwo in den Resourcen definierte Dialog-Box anzeigt und dafür die MessageLoop übernimmt. Ansonsten hat dein Programm bislang auch keine Message-Loop.



  • Der Code, den DieSeenDerHerrlichkeit gepostet hat, ist komplett falsch, hier gibt es nichts zu diskutieren. Habe nämlich aus Neugier versucht, zum Laufen zu bekommen...
    Dann musste ich es wenig bearbeiten und das ist bei mir rausgekommen (wobei ich nicht weiss, ob das Ergebnis genau das, was DieSeenDerHerrlichkeit habe möchte):
    Das ist main.c:

    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include "resource.h"
    
    HBITMAP hSkinBmp;
    
    BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        HDC hdcMem;
    
        switch (uMsg)
        {
            case WM_INITDIALOG:
                {
                    return TRUE;
                }
    
            case WM_CLOSE:
                {
                    EndDialog(hWnd, 0);
                    return TRUE;
                }
    
            case WM_PAINT:
                {
                    hdc = BeginPaint(hWnd, &ps);
                    hdcMem = CreateCompatibleDC(hdc);
                    SelectObject(hdcMem, hSkinBmp);
    
                    BitBlt(hdc, 0, 0, 200, 100, hdcMem, 0, 0, SRCCOPY);
    
                    DeleteDC(hdcMem);
                    EndPaint(hWnd,&ps);
                    break;
                }
    
            default:
                {
                    break;
                }
        }
    
        return FALSE;
    }
    
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
        hSkinBmp = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SKIN));
    
        if (NULL == hSkinBmp)
        {
            MessageBox(NULL, TEXT("cant load bitmap"), TEXT("Error"), MB_OK);
            return -1;
        }
    
        return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, DialogProc);
    }
    

    Das ist main.rc:

    #include "resource.h" 
    
    IDB_SKIN BITMAP DISCARDABLE  "skin.bmp" 
    
    DLG_MAIN DIALOG DISCARDABLE 100, 100, 200, 100
    STYLE WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU 
    CAPTION "abc.w" 
    FONT 8, "MS Sans Serif"
    BEGIN 
    END
    

    Das ist resource.h:

    #include <windows.h> 
    
    // ID of Main Dialog 
    #define DLG_MAIN 102 
    
    #define IDB_BITMAP1                     101 
    #define IDB_SKIN                        101
    

    Und hier mein Makefile:

    all:
    	mingw32-gcc -c main.c -o main.o -mwindows
    	windres main.rc -o main_Rc.o
    	mingw32-gcc main_Rc.o main.o -o main.exe -mwindows
    

    Wie gesagt, der Code läuft, ist aber sicherlich nicht "das Gelbe vom Ei"...


Anmelden zum Antworten