Frage

Am i erlaubt eine DC außerhalb eines Farbzyklus zu benutzen? Ist mein Fenster des DC gültig ist garantiert für immer?

Ich versuche, herauszufinden, wie lange meine Kontrolle des Device Context (DC) gültig ist.

ich weiß, dass ich anrufen kann:

GetDC(hWnd);

den Gerätekontext meiner Kontrolle des Fensters zu bekommen, aber ist das erlaubt?

Wenn Windows mir eine WM_PAINT-Nachricht sendet, ich bin nennen soll Beginpaint / EndPaint richtig erkennen an, dass ich habe es gemalt, und intern den ungültigen Bereich löschen:

BeginPaint(hWnd, {out}paintStruct);
try
   //Do my painting
finally
   EndPaint(hWnd, paintStruct);
end;

Aber Aufruf Beginpaint auch gibt mir ein DC in der PAINTSTRUCT Struktur. Dies ist die DC, dass i sollte wird Malerei auf.

Ich kann nichts in der Dokumentation, die besagen, dass die DC von Beginpaint () zurück ist die gleiche DC, dass ich von GetDC bekommen würde ().

Gerade jetzt, in den Tagen der Desktop-Zusammensetzung ist es gültig auf einem DC zu malen, dass ich außerhalb von Beginpaint erhalten?

Es scheint zwei Möglichkeiten, um i ein DC bekommen kann während einer Farbe Zyklus malen auf:

  1. dc = GetDC (hWnd);

  2. Beginpaint (& PAINTSTRUCT);

Es gibt einen dritten Weg, aber es scheint ein Fehler mit dem Borland Delphi zu sein, dass ich mit zu entwickeln.

Während WM_PAINT Verarbeitung, Delphi glaubt dass der wParam ist ein DC und geht auf sie zu malen. Während die MSDN sagt, dass der WParam einer WM_PAINT-Nachricht nicht verwendet wird.

Das Warum

Mein eigentliches Ziel ist zu versuchen, eine persistente GDI + zu halten Graphics-Objekt gegen einen HDC, so dass ich einige bessere Durchführung Features von GDI + verwenden kann, die ein persistenten DC auf, die abhängig ist.

Während der WM_PAINT Nachrichtenverarbeitung i ein GDI + Bild auf die Leinwand zeichnen möchten. Die folgende nieve Version ist sehr langsam:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);
   Graphics g = new Graphics(ps.hdc);
   g.DrawImage(m_someBitmap, 0, 0);
   g.Destroy();
   EndPaint(h_hwnd, ps);
}

GDI enthält eine schnellere Durchführung von Bitmap, eine CachedBitmap. Aber es verwenden, ohne zu denken gibt keinen Performance-Vorteil:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);

   Graphics g = new Graphics(ps.hdc);
   CachedBitmap bm = new CachedBitmap(m_someBitmap, g);
   g.DrawCachedBitmap(m_bm, 0, 0);
   bm.Destroy();
   g.Destroy();
   EndPaint(h_hwnd, ps);
}

Die Leistungssteigerung kommt aus der CachedBitmap einmal erstellen, so auf Programminitialisierung:

m_graphics = new Graphics(GetDC(m_hwnd));
m_cachedBitmap = new CachedBitmap(b_someBitmap, m_graphcis);

Und nun auf dem Lack-Zyklus:

WM_PAINT:
{
   PAINTSTRUCT ps;
   BeginPaint(m_hwnd, ps);
   m_graphics.DrawCachedBitmap(m_cachedBitmap, 0, 0);
   EndPaint(h_hwnd, ps);
}        

Außer jetzt bin ich darauf vertrauen, dass die DC-i nach dem Programm initializtion erhalten die gleiche DC für mein Fenster sein, solange die Anwendung läuft. Dies bedeutet, dass es überlebt durch:

  • schnelle Benutzerschalter
  • Zusammensetzung aktiviert / deaktiviert
  • Thema Schalt
  • Thema deaktivieren

ich finde nichts in MSDN, dass garantiert, dass die gleichen DC wird für ein bestimmtes Fenster verwendet werden, solange das Fenster vorhanden ist.

Hinweis: Ich bin kein Double-Buffering verwenden, , weil ich ein guter Entwickler sein will, und das richtige tun . Manchmal ist das Mittel Sie Double-Buffering ist schlecht.

War es hilfreich?

Lösung

Es gibt Ausnahmen, aber im Allgemeinen, können Sie eine andere DC jedes Mal, wenn Sie anrufen GetDC oder BeginPaint bekommen. Daher sollten Sie nicht versuchen Zustand im DC zu speichern. (Wenn Sie dies für die Leistung tun müssen, gibt es spezielle DCs Sie für eine Klasse von Fenstern oder einem bestimmten Fenster-Instanz erstellen können, aber es klingt nicht wie das ist, was Sie wirklich brauchen oder wollen.)

Die meiste Zeit jedoch werden diese DCs kompatibel sein. Sie werden den gleichen Grafikmodus darstellen, so kompatiblen Bitmap funktionieren sollte, auch wenn Sie eine andere DC erhalten.

Es gibt Windows-Nachrichten, die Ihnen sagen, wenn der Grafikmodus ändert, wie WM_DISPLAYCHANGE und WM_PALETTECHANGED. Sie können für diese hören und Ihre zwischengespeicherte Bitmap neu erstellen. Da diese seltene Ereignisse sind, werden Sie nicht über die Auswirkungen auf die Leistung zu kümmern Ihre zwischengespeicherte Bitmap an diesem Punkt neu zu erstellen.

Sie können auch Benachrichtigungen für Dinge wie Themenänderungen erhalten. Diejenigen, nicht den Grafikmodus ändern - sie sind ein höheres Level-Konzept - so zwischengespeicherten Bitmap immer noch mit jedem DC kompatibel sein sollte, die Sie erhalten. Aber wenn Sie möchten Bitmap ändern, wenn die Themen ändert, können Sie für WM_THEMECHANGED hören auch.

Andere Tipps

Die einzige Möglichkeit, die ich kenne, kann (oder auch nicht) tun, was Sie suchen, ist das Fenster mit dem CS_OWNDC Klassenstil.

Was das tut, ist ordnet einen einzigartigen Gerätekontext für jedes Fenster in der Klasse.

Bearbeiten

Von dem verknüpften MSDN-Artikel:

  

Ein Gerätekontext ist ein spezieller Satz von   Werte, die Anwendungen für   Zeichnung im Client-Bereich ihrer   Fenster. Das System erfordert eine Einrichtung   Kontext für jedes Fenster auf dem Display   sondern erlaubt eine gewisse Flexibilität bei der   System speichert und behandelt, dass die Vorrichtung   Kontext.

     

Wenn kein Gerät-Kontext Stil   explizit angegeben, nimmt das System an   Jedes Fenster verwendet eine Gerätekontext   aus einem Pool von Kontexten abgerufen   durch das System aufrechterhalten. In solch   Fällen muss jedes Fenster abrufen und   den Gerätekontext initialisieren, bevor   Malerei und befreit es nach dem Lackieren.

     

Um zu vermeiden, einen Gerätekontext Abrufen   jedes Mal, es muss innerhalb einer malen   Fenster kann eine Anwendung angeben, die   CS_OWNDC Stil für die Fensterklasse.   Diese Klasse Stil leitet das System   Einen privaten Gerätekontext erstellen - das   wird, eine eindeutige Geräte zuzuteilen   Kontext für jedes Fenster in der Klasse.   Die Anwendung muss nur abrufen, die   Kontext einmal und es dann für alle verwenden   anschließende Lackierung.

     

Windows 95/98 / Me: Obwohl die   CS_OWNDC Stil bequem ist, verwenden Sie es   sorgfältig durch, da jeder Gerätekontext   verwendet einen wesentlichen Teil der 64K GDI   Heap.

Vielleicht ist dieses Beispiel wird die Verwendung von CS_OWNDC besser darzustellen:

#include <windows.h>

static TCHAR ClassName[] = TEXT("BitmapWindow");
static TCHAR WindowTitle[] = TEXT("Bitmap Window");

HDC m_hDC;
HWND m_hWnd;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static PAINTSTRUCT ps;

    switch (msg)
    {
    case WM_PAINT:
        {
            BeginPaint(hWnd, &ps);

            if (ps.hdc == m_hDC)
                MessageBox(NULL, L"ps.hdc == m_hDC", WindowTitle, MB_OK);
            else
                MessageBox(NULL, L"ps.hdc != m_hDC", WindowTitle, MB_OK);

            if (ps.hdc == GetDC(hWnd))
                MessageBox(NULL, L"ps.hdc == GetDC(hWnd)", WindowTitle, MB_OK);
            else
                MessageBox(NULL, L"ps.hdc != GetDC(hWnd)", WindowTitle, MB_OK);

            RECT r;
            SetRect(&r, 10, 10, 50, 50);
            FillRect(m_hDC, &r, (HBRUSH) GetStockObject( BLACK_BRUSH ));

            EndPaint(hWnd, &ps);
            return 0;
        }
    case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{   
    WNDCLASSEX wcex;

    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );
    wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
    wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wcex.hIconSm = NULL;
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = ClassName;
    wcex.lpszMenuName = NULL;
    wcex.style = CS_OWNDC;

    if (!RegisterClassEx(&wcex))
        return 0;

    DWORD dwExStyle = 0;
    DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;

    m_hWnd = CreateWindowEx(dwExStyle, ClassName, WindowTitle, dwStyle, 0, 0, 300, 300, NULL, NULL, hInstance, NULL);

    if (!m_hWnd)
        return 0;

    m_hDC = GetDC(m_hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

Die CS_OWNDC Flag nicht mit der CS_CLASSDC Flagge verwechselt werden, die:

  
    

Ordnet einen Gerätekontext von allen Fenstern in der Klasse geteilt werden. Da Fensterklassen prozessspezifisch sind, ist es möglich, dass mehrere Threads einer Anwendung ein Fenster der gleichen Klasse zu erstellen. Es ist auch möglich, dass die Threads gleichzeitig den Gerätekontext zu verwenden, um zu versuchen. Wenn dies geschieht, kann das System nur ein Thread, um erfolgreich seinen Ziehvorgang zu beenden.

  

Wenn alle Stricke reißen nur reconstruct die CachedBitmap.

  
    

Wenn Sie ein CachedBitmap Objekt erstellen, müssen Sie die Adresse eines Graphics-Objekt an den Konstruktor übergeben. Wenn der Bildschirm mit dem Graphics zugehörige Objekt hat seine Bit-Tiefe geändert, nachdem die zwischengespeicherte Bitmap aufgebaut ist, dann wird die DrawCachedBitmap Methode fehlschlagen, und Sie sollten die zwischengespeicherte Bitmap rekonstruieren. Alternativ können Sie die Anzeige ändern Benachrichtigung Haken und die zwischengespeicherte Bitmap zu dieser Zeit rekonstruieren.

  

Ich sage nicht, dass CS_OWNDC die perfekte Lösung, aber es is einen Schritt in Richtung einer besseren Lösung.

Bearbeiten

Das Beispielprogramm schien die gleichen DC während Bildschirmauflösung / Bittiefe ändern Tests mit dem CS_OWNDC Flagge zu behalten, jedoch, wenn die Flagge entfernt wurde, waren die DCs verschiedenes (Windows 7 64-Bit Ultimate) ( sollten das gleiche über differn OS-Versionen ... obwohl es nicht zu Test schaden würde).

EDIT2

In diesem Beispiel nennt GetUpdateRect nicht zu prüfen, ob das Fenster während der WM_PAINT gemalt werden muss. Das ist ein Fehler.

Sie können zeichnen auf, je nachdem, welche Fenster dc gefällt Ihnen. Sie sind beide gültig. Ein Fenster muss nicht nur ein dc, dass es zu einem Zeitpunkt darstellen kann. Also jedes Mal, wenn Sie GetDC nennen - und Beginpaint intern so ist, werden Sie eine neue, einzigartige dc bekommen, stellt dar, dass dennoch den gleichen Anzeigebereich. Nur ReleaseDC (oder EndPaint), wenn Sie mit ihnen fertig sind. In den Tagen von Windows 3.1 Gerätekontexten wurden eine begrenzt oder sehr teuere Systemressourcen, so wurden Anwendungen ermutigt, nie auf sie halten, aber sie aus dem GetDC Cache abzuzurufen. heute seine vollkommen akzeptabel, ein DC bei Fenstererstellung und Cache es für das Leben des Fensters zu schaffen.

Das einzige „Problem“ ist, wenn WM_PAINT Handhabung, die dc von Beginpaint zurückgegeben wird den ungültigen rect abgeschnitten werden, und die gespeicherten man nicht.


Ich weiß nicht aber verstehen, was Sie mit GDIPlus zu erreichen versuchen. Normalerweise, wenn ein Objekt ... ausgewählt in eine Gleich für eine lange Zeit, dass dc ist ein Speicher, dc, kein Fenster dc.


Jedes Mal, GetDC genannt wird Sie eine neue HDC bekommen einen eigenen Gerätekontext mit einem eigenen Stand vertreten. Also, Objekte, Hintergrundfarben, Textmodus usw. Satz auf einer DC nicht wirksam, dass Zustand eines anderen DC durch einen anderen Anruf zu GetDC oder Beginpaint abgerufen werden.

Das System kann nicht zufällig Invalidier HDCs vom Client abgerufen wird, und tatsächlich tut eine Menge Arbeit im Hintergrund, um sicherzustellen, dass vor einem Anzeigemodus-Schalter abgerufen HDCs, weiterhin funktionieren. Auch die Änderung der Bittiefe, dass technisch nicht kompatibel DCs macht, wird nicht in irgendeiner Weise verhindern, dass eine Anwendung von fort eine hdc zu blit verwenden.

sagte, ist es ratsam, zumindest für WM_DISPLAYCHANGE zu sehen, lassen Sie alle zwischengespeicherten DCs und Geräte Bitmaps und sie neu erstellen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top