Avatar billede coldplay Nybegynder
28. januar 2004 - 13:46 Der er 3 kommentarer og
1 løsning

Subclassing af windows procedure

Er der nogen, som har erfaring med at "subclasse" windows proceduren "MainWndProc" i WinMain, så det er muligt at checke flowet af messages inden det sendes videre til den defaulte procedure?

Gerne noget simplificeret kode, som viser princippet, eller nogle links.

Kun API kode, ikke MFC eller lign.

På forhånd tak.
Avatar billede narrr Nybegynder
28. januar 2004 - 16:29 #1
Forstår jeg dig ret, hvis det du vil er at tjekke hvilke beskeder der bliver sendt videre til DefWindowProc?
Avatar billede coldplay Nybegynder
29. januar 2004 - 13:03 #2
Tak for kommentaren.

DefWindowsProc tager sig af alle andre messages end dem, som den subclassed windows procedure er kodet til at håndtere. Med andre ord er jeg interesseret i at fange bestemte messages før de resterende videresendes via DefWindowsProc i den nye procedure. De resterende messages sendes via DefWindowsProc til den gamle procedure.

Hvis man f.eks er interesseret i at fange WM_NCHITTEST messages, så er det i CBuilder (Borland) muligt at oprette en såkaldt "message handler" på formen:

BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_NCHITTEST, TMessage, WMNCHITTEST)
END_MESSAGE_MAP(TForm1)

Det er efter min bedste overbevisning Borlands måde at implementere en subclassing af MainWndProc i WinMain. Jeg er imidlertid interesseret i at håndtere messages i udelukkende API kode, så jeg ikke er afhængig af massage handlers og andre finurlige implementeringsformer.
Avatar billede borrisholt Novice
30. januar 2004 - 11:39 #3
///// MAIN.H ////

#ifndef __MAINWINDOW_H
#define __MAINWINDOW_H

#include <windows.h>
#include  <stdio.h>

#define clBackGroundColor RGB(255,255,255)

#define WINDOW_NAME "___BORRISHOLT_MainWindow__"

#define BORRISHOLTWINDOW  FindWindow(WINDOW_NAME,NULL)

#define SHOWWINDOW(INSTANCE, TEXT)\
    CMainWindow *MainWindow = new CMainWindow(INSTANCE, TEXT);

#define SHOWWINDOW_XY(INSTANCE, TEXT, X,Y)\
    CMainWindow *MainWindow = new CMainWindow(INSTANCE, TEXT, X,Y);

#define HIDE_MAIN_WINDOW()\
    ::ShowWindow(BORRISHOLTWINDOW, SW_HIDE);

#define CLOSE_MAIN_WINDOW()\
    ::SendMessage(BORRISHOLTWINDOW,WM_CLOSE,0,0);

#define TIMER_ID_0 0x0000
#define TIMER_ID_1 0x0001


enum TDriveType  {dtUnknown, dtNoDrive, dtFloppy, dtFixed, dtNetwork, dtCDROM, dtRAM};

class CMainWindow
{
  private:
    HWND handle;
    HWND ListBox_handle;
    HINSTANCE hInst;
    int nWidth;
    int nHeight;
    char * cWindowText;
    int DriveCount;
    HICON Icons[25];
    int Current;   
    WNDPROC oldListBoxWndProc;
  protected:
    int TextHeight(char *text = NULL);
    int TextWidth(char *text = NULL);
    SIZE TextExtent(char *text = NULL);
    int ShowWindow(int nCmdShow);
    bool CreateMainWindow(HINSTANCE hPrevInstance);
    static LRESULT CALLBACK WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static LRESULT CALLBACK WndProcListBoxA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK WndProcListBox(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    void SetPos(int xPos = 0 , int yPos = 0);
    void SetText(const char * WindowText);
    void SetBounds(int ALeft, int ATop, int AWidth, int AHeight);
    void CreateListBox();
    void AddDrive(const char *VolName);
  public:
    CMainWindow(HINSTANCE hInstance, const char * WindowText = NULL, int xPos = 0, int yPos = 0);
    LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    int ShowWindow(const char * WindowText, int xPos = 0, int yPos = 0);
    int HideWindow();
    HWND Handle(){return handle;}
};

#endif // __MAINWINDOW_H


//// MAIN.CPP ////
#include "Main.h"
#include <commctrl.h>
#include <math.h>
#include <shellAPi.h>

#define XBITMAP 20
#define YBITMAP 20

bool CMainWindow::CreateMainWindow(HINSTANCE hPrevInstance)
{
    WNDCLASS WinClass;

    if (hPrevInstance == NULL)
    {
        memset(&WinClass, 0, sizeof(WinClass));
        WinClass.style                = CS_CLASSDC | CS_PARENTDC | CS_SAVEBITS;
        WinClass.lpfnWndProc        = &WndProcA;
        WinClass.hInstance          = hInst;
        WinClass.hbrBackground      = CreateSolidBrush(clBackGroundColor);
        WinClass.lpszClassName      = WINDOW_NAME;
        WinClass.hCursor            = LoadCursor(0, IDC_ARROW);
        RegisterClass(&WinClass);
    }

    handle  = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_RTLREADING, WINDOW_NAME, "",  WS_SYSMENU |WS_BORDER, 363, 278, 50, 50, 0, 0, hInst, 0);
    nWidth  = 0;
    nHeight = 0;

    UpdateWindow(handle);
    return true;
}

void CMainWindow::AddDrive(const char *VolName)
{
  TDriveType DriveType = TDriveType(GetDriveType(VolName));
  char Buf[200];
  GetSystemDirectory(Buf,200);
  strcat(Buf, "\\Shell32.dll");

  switch (DriveType)
  {
    case dtFloppy:
    {
      Icons[Current++] = ExtractIcon(hInst, Buf, 6 + int(Current > 3));
      break;
    }
    case dtFixed:
    {
      Icons[Current++] = ExtractIcon(hInst, Buf, 8);
      break;
    }
    case dtNetwork:
    {
      Icons[Current++] = ExtractIcon(hInst, Buf, 9);
      break;
    }
    case dtCDROM:
    {
      Icons[Current++] = ExtractIcon(hInst, Buf, 11);
      break;
    }
    case dtRAM:
    {
      Icons[Current++] = ExtractIcon(hInst, Buf, 12);
      break;
    }
  }

  int nItem = SendMessage(ListBox_handle, LB_ADDSTRING, 0, (int)VolName);
  SendMessage(ListBox_handle, LB_SETITEMDATA, nItem, (int)Icons[Current-1]);
}

void CMainWindow::CreateListBox()
{
  ListBox_handle = CreateWindow("LISTBOX", "test", WS_CHILD| WS_VISIBLE|WS_BORDER | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS , 10, 10, 400, 400, handle, NULL, hInst, NULL);

  oldListBoxWndProc = (WNDPROC)SetWindowLong(ListBox_handle,GWL_WNDPROC, (LONG)WndProcListBoxA);
  if (oldListBoxWndProc == 0 )
    MessageBox(0,0,0,0);
}

CMainWindow::CMainWindow(HINSTANCE hInstance, const char * WindowText, int xPos , int yPos)
{
  if (!FindWindow(WINDOW_NAME,NULL))
  {
    hInst = hInstance;
    CreateMainWindow(NULL);
    cWindowText = NULL;
    SetWindowLong(handle,GWL_USERDATA, (long)this);
  }

  if(WindowText)
    ShowWindow(WindowText,xPos,yPos);

  CreateListBox();

  char drive[4] = "A:\\";
  unsigned long BitMask,Bits;
  Bits = GetLogicalDrives();
  Current = 0;
  int i;
  for(i=0; i<26 ;i++)
  {
    BitMask = 1L<<i;
    if((Bits & BitMask) != 0)
      ++DriveCount;
  }

  for(i=0; i<26 ;i++)
  {
    BitMask = 1L<<i;
    if((Bits & BitMask) != 0)
    {
    drive[0] = (char)(65+i);
    AddDrive(drive);
    }
  }
}


LRESULT CMainWindow::WndProcListBoxA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  CMainWindow *tmp =  (CMainWindow *)GetWindowLong(GetParent(hwnd),GWL_USERDATA);
  return  tmp->WndProcListBox(hwnd,uMsg,wParam,lParam);
}

LRESULT CMainWindow::WndProcListBox(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  return oldListBoxWndProc(hwnd,uMsg,wParam, lParam);
}

LRESULT CMainWindow::WndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  CMainWindow *tmp =  (CMainWindow *)GetWindowLong(hwnd,GWL_USERDATA);
  return  tmp->WndProc(hwnd,uMsg,wParam,lParam);
}

LRESULT CMainWindow::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
      case WM_DESTROY:
      {
        PostQuitMessage(0);
        break;
      }

      case WM_DRAWITEM:
      {
        DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;

          // If there are no list box items, skip this message.
        if (dis->itemID == -1)
          break;


        switch (dis->itemAction)
        {
          case ODA_SELECT:
          case ODA_DRAWENTIRE:                    {
          // Display the bitmap associated with the item.
          if (dis->itemState & ODS_SELECTED)
              FillRect(dis->hDC, &dis->rcItem, (HBRUSH) (COLOR_HIGHLIGHT+15));
          else
              FillRect(dis->hDC, &dis->rcItem, (HBRUSH) (COLOR_WINDOW+1));

          HICON h = (HICON)SendMessage(dis->hwndItem,  LB_GETITEMDATA, dis->itemID, (LPARAM) 0);
          DrawIconEx(dis->hDC,dis->rcItem.left+1,dis->rcItem.top+1,h,16,16,0,0,DI_NORMAL);

          // Display the text associated with the item.
          char tchBuffer[200];

          SendMessage(dis->hwndItem, LB_GETTEXT, dis->itemID, (LPARAM) tchBuffer);

          TEXTMETRIC tm;
          GetTextMetrics(dis->hDC, &tm);

          int y = (dis->rcItem.bottom + dis->rcItem.top - tm.tmHeight) / 2;
          SetBkMode(dis->hDC, TRANSPARENT);
          TextOut(dis->hDC, XBITMAP + 6, y, tchBuffer, strlen(tchBuffer));
          break;
        }
        case ODA_FOCUS:
        // Do not process focus changes. The focus caret
        // (outline rectangle) indicates the selection.
        // The IDOK button indicates the final
        // selection.

        break;
      }
      return TRUE;
    }

    default:
      return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int CMainWindow::ShowWindow(int nCmdShow)
{
  return ::ShowWindow(handle,nCmdShow);
}

void CMainWindow::SetPos(int xPos, int yPos)
{
  POINT p;
  GetCursorPos(&p);

  if (xPos * yPos == 0)
  {
    xPos = p.x +10;
    yPos = p.y +20;
  }

  SetBounds(xPos,yPos,nWidth,nHeight);
}


SIZE CMainWindow::TextExtent(char *text)
{
  SIZE Result;
  Result.cx = 0;
  Result.cy = 0;
  if (text == 0)
    GetTextExtentPoint32(GetDC(handle), cWindowText, strlen(cWindowText), &Result);
  else
    GetTextExtentPoint32(GetDC(handle), text, strlen(text), &Result);

  return Result;
}

int CMainWindow::ShowWindow(const char * WindowText, int xPos, int yPos)
{
  ::SetWindowText(handle, WindowText);
  SetBounds(110, 110,500,500);
  return ::ShowWindow(handle, SW_SHOW);
}

int CMainWindow::TextWidth(char *text)
{
  return TextExtent(text).cx;
}

int CMainWindow::TextHeight(char *text)
{
  return TextExtent(text).cy;
}

void CMainWindow::SetBounds(int ALeft, int ATop, int AWidth, int AHeight)
{
  if (handle && !IsIconic(handle))
    SetWindowPos(handle, 0, ALeft, ATop, AWidth+6, AHeight+4, SWP_NOZORDER + SWP_NOACTIVATE);
}

int CMainWindow::HideWindow()
{
  return ::ShowWindow(handle,SW_HIDE);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR d3, int nCmdShow)
{
  SHOWWINDOW(hInstance,"Borrisholt - WIN32 Example");
  MSG msg;

  while (GetMessage(&msg, NULL, 0, 0))
    DispatchMessage(&msg);

  delete (MainWindow);
  return 0;
}


Jens B
Avatar billede coldplay Nybegynder
30. januar 2004 - 14:04 #4
Ganske overvældende og bestemt 100 point værd.

Tak!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester