LearningMFC

From HerzbubeWiki
Jump to navigation Jump to search

This page contains notes on MFC.

A lot of the content of this page is in German - I never got around to translate this.


References

General

Window management


Overview

  • MFC = Microsoft Foundation Classes
  • MFC is a C++ class library that provides an object-oriented wrapper around parts of the Win32 API.
    • When you start working with MFC you'll soon realize that the layer is very thin.
    • Sometimes the question arises: Is this object orientation at all?
    • The reason is historical: At the time when MFC was created (1992) C++ was practically in its infancy when it came to commercial application development.
  • MFC is not just a library, it's also an application framework.
  • The prefix "Afx" means "Application Framework Extensions". This was MFC's name while it was developed.


MFC macros and functions

AfxGetStaticModuleState()
AFX_MANAGE_STATE(AfxGetStaticModuleState());
  • The current module state temporarily is changed until end of scope.
  • The new state is the state of the module to which the code currently executing belongs.
  • This construct is used, for instance, to change the module state before a resource is loaded.
AfxGetInstanceHandle()
  • http://msdn.microsoft.com/en-us/library/36z3tfsb.aspx
  • Returns an HINSTANCE module handle.
  • This is either the handle of the application (.exe), or the handle of the DLL to which the function belongs that is currently executing.
  • Important: The latter only works for DLLs that are linked against the USRDLL version of MFC.
AfxFindResourceHandle()
  • http://msdn.microsoft.com/en-us/library/zf0f9ezz.aspx
  • Searches through the "resource chain" for the specified resource (resource ID and type)
  • Returns an HINSTANCE module handle of the module (.exe or .dll) that contains the resource.
  • Searches through all DLLs that are currently loaded.
  • TODO: It is currently not clear in which order the resource chain is searched.
AfxGetResourceHandle()
  • http://msdn.microsoft.com/en-us/library/zaewt3xs.aspx
  • Returns an HINSTANCE module handle.
  • This is the handle of the module (.exe oder .dll) that contains the default resources of the application.
  • The return value can be used, for instance, for invoking FindResource() or LoadString()
  • When the application starts the handle refers to the .exe, but it can be changed - see the next entry.
AfxSetResourceHandle()
  • http://msdn.microsoft.com/en-us/library/d8ws31ff.aspx
  • Requires an HINSTANCE module handle parameter
  • Sets the module (.exe or .dll) that contains the default resources of the application.
  • This is the handle that AfxGetResourceHandle() returns.
  • Purpose: Load a dedicated resource DLL with LoadLibrary(), then "point" MFC to it.


Window Management

CWnd

  • GUI windows are identified by an HWND handle
  • A CWnd object exists separately from the actual GUI window object, but is coupled with it via the HWND reference
    • The HWND reference is available via the public member variable m_hWnd
    • Many global API functions, which require an HWND parameter, are accessible as CWnd member functions
    • The member functions invoke the corresponding global API functions and simply pass the HWND reference contained by the CWnd object
  • Lifecycle of CWnd and the GUI window object
    • Create
      • Someone creates the CWnd object
      • Someone invokes CWnd::Create()
      • As a side effect CWnd::Create() stores the HWND reference in the CWnd object
      • Before CWnd::Create() returns control to the caller the following things happen in the listed order:
        • WM_NCCREATE is sent, which causes CWnd::OnNcCreate() to be called, after the non-client area of the windows is created
        • WM_CREATE is sent, which causes CWnd::OnCreate() to be called, after the client area of the window is created
    • Destruction
      • Someone invokes CWnd::DestroyWindow()
        • If the function is not explicitly called, the GUI window object is destroyed in ~CWnd() at the latest; CWnd::DestroyWindow() in this case is not called.
        • The function sends WM_DESTROY and WM_NCDESTROY
        • The function is invoked by the default implementation of CWnd::OnClose()
        • Apparently there are CWnd subclasses in MFC that never invoke CWnd::DestroyWindow() (e.g. CFramwWnd subclasses)
        • For those cases some user code must explicitly invoke CWnd::DestroyWindow()
      • CWnd::OnNcDestroy()
        • Is automatically invoked as part of the window destruction cycle - it's the last function that is called in the cycle
        • The default implementation of CWnd::OnNcDestroy() performs cleanup and then invokes CWnd::PostNcDestroy()
        • The function should not be overridden; if an override is created it must invoke the default implementation.
      • CWnd::PostNcDestroy()
        • The function should be overridden to perform user code cleanup
        • One possible application is delete this
      • Someone destroys the CWnd object
  • CWnd and HWND reference
    • HWND CWnd::Detach()
      • Removes the reference to the window object from the CWnd
    • BOOL CWnd::Attach(HWND)
      • Adds a reference to a window object to a CWnd


Window hierarchy

  • Ein Window kann Child Windows haben
    • Der Begriff "Child Window" ist in diesem Kontext unabh‰ngig davon, ob das Window mit dem Style WS_CHILD erzeugt wurde oder nicht
  • Beim Erzeugen des Child Windows mit CWnd::Create() wird ein Handle auf das Parent Window angegeben
    • Wird kein Handle angegeben (null), so ist das Window ein Child des Desktop Window
  • Es wird WM_PARENTNOTIFY an den Parent gesendet, nachdem das Child Window erzeugt wurde (*nach* WM_NCCREATE und WM_CREATE auf dem Child)
  • Wird das Child Window mit CWnd::DestroyWindow() oder ~CWnd() zerstˆrt, so wird es automatisch vom Parent entfernt
    • Es wird WM_PARENTNOTIFY an den Parent gesendet, bevor die eigentliche Zerstˆrung stattfindet
  • Hat ein Parent Window noch Child Windows, so werden diese von CWnd::DestroyWindow() automatisch zerstˆrt, und zwar vor dem Parent Window
    • Die Message WM_DESTROY wird zuerst an das Parent Window gesendet und erst danach an alle Child Windows
  • Ein Fenster kann mit SetParent() einem neuen Parent zugeteilt werden (http://msdn.microsoft.com/en-us/library/ms633541.aspx)
    • Scheinbar ist das nicht mˆglich f¸r "Owned Windows", sondern nur f¸r WS_CHILD Windows (siehe "Window Features" Artikel)
    • SetParent() passt die Style Flags des Window nicht an, deshalb m¸ssen die folgenden Operationen bei Bedarf manuell vorgenommen werden
    • Parent HWND war non-null, ist neu aber null = Der Style muss *nach* dem Aufruf von SetParent() angepasst werden
      • WS_CHILD lˆschen
      • WS_POPUP setzen
    • Parent HWND war null, ist neu aber non-null = Der Style muss *vor* dem Aufruf von SetParent() angepasst werden
      • WS_CHILD setzen
      • WS_POPUP lˆschen
    • Zus‰tzlich muss der UISTATE sowohl des neuen Parents als auch des Childs angepasst werden (siehe Doku von SetParent())
  • IsChild() pr¸ft, ob ein Window das direkte oder indirekte Child des angegebenen Parents ist
    • Child Window = Direktes Child
    • Descendant Window = Indirektes Child


Messages

  • CWnd und Message Maps sorgen daf¸r, dass OnFoo() Handler Methoden automatisch aufgerufen werden


Window styles

  • Overlapped Window (WS_OVERLAPPED) = Top-level Window, typischerweise das Hauptfenster der Applikation mit Title Bar, Border, Client Area, etc.
  • Pop-up Window (WS_POPUP) = Spezieller Typ eines Overlapped Window; Fenster dieses Typs erscheinen ausserhalb des Main Window
  • Child Window (WS_CHILD) = Ein Fenster, das innerhalb der Client Area des Parent Window gezeichnet wird
    • In diesem Kontext hat "Child Window" eine andere Bedeutung als die reine Parent/Child Beziehung zwischen Windows
    • Wird beim Erzeugen des Window WS_CHILD angegeben, so muss *zwingend* auch ein Parent Window angegeben werden


Window roles

  • Foreground/Background
    • Ein Window ist mit dem Thread assoziiert, der es erzeugt hat (d.h. auch andere Threads als der Main Thread kˆnnen Windows erzeugen)
    • Foreground Window = Dasjenige Window, mit dem der Benutzer zur Zeit arbeitet
    • Foreground Thread = Derjenige Thread, der das Foreground Window erzeugt hat
    • Background Window = Alle Fenster, die nicht das Foreground Window sind
    • Background Thread = Alle Threads, die nicht der Foreground Thread sind
    • Der Foreground Thread hat per Default eine leicht hˆhere Priorit‰t als die anderen Threads
    • GetForegroundWindow() gibt das HWND des Foreground Window zur¸ck (http://msdn.microsoft.com/en-us/library/ms633505.aspx)
  • Owned Windows
    • Ein "Owned Window" ist ein WS_OVERLAPPED oder WS_POPUP Window, dessen Parent ein anderes WS_OVERLAPPED oder WS_POPUP Window ist
    • Weder das Owned Window noch dessen Parent wurden also mit WS_CHILD erzeugt
    • Mit anderen Worten: Beim Erzeugen eines Owned Window wird ein Parent HWND angegeben, ohne dass WS_CHILD gesetzt wird
    • Owned Windows kˆnnen nach ihrem Erzeugen nicht einem neuen Parent zugeteilt werden
    • Typische F‰lle f¸r Owned Windows sind Dialog Boxes und Message Boxes
  • Active Window
    • Dasjenige Window, mit dem der Benutzer zur Zeit arbeitet
    • Im gesamten System kann immer nur ein Window das Active Window sein
    • Nur top-level Windows kˆnnen zum Active Window werden
      • Wird ein Child Window aktiv, so macht das System automatisch dessen top-level Parent zum Active Window
    • GetActiveWindow() gibt das HWND des Active Window zur¸ck (http://msdn.microsoft.com/en-us/library/ms646292.aspx)
    • *Unklar* ist zur Zeit, was der Unterschied zwischen Active Window und Foreground Window ist
      • Ein Unterschied scheint zu sein, dass GetActiveWindow() null zur¸ckgibt, falls das Active Window nicht zum aktiven Thread gehˆrt


Z order

  • Zus‰tzlich zu ihrer x/y-Position auf dem Bildschirm sind Windows zus‰tzlich entlang einer imagin‰ren Z-Achse angeordnet
  • Diese Z-Achse hat ihren Null-Punkt im Bildschirm und zeigt von ihm weg zum Benutzer
  • Das System hat eine einfache Liste mit allen Windows gem‰ss ihrer Position auf der Z-Achse
  • Ein Window, das weiter vorne auf der Z-Achse liegt ¸berdeckt Windows, die weiter hinten liegen
  • F¸r Details siehe den entsprechenden Abschnitt im Artikel "Window Features"