Domanda

Sto scrivendo una DLL di hook globale che deve eseguire alcuni disegni utilizzando GDI+ su una finestra in risposta a un evento.Il mio problema è che la finestra che viene disegnata continua a ridipingersi, quindi ciò che disegno viene cancellato prima che lo voglia.C'è un modo per evitare che la finestra dipinga qualcosa per tutto il tempo necessario?

Il mio gancio attualmente è a WH_CALLWNDPROC gancio.Il disegno viene eseguito utilizzando GDI+ in risposta al messaggio WM_SIZING.Disegno utilizzando GDI+ sui file window DC (cioè. GetWindowDC).Ciò che sto disegnando viene disegnato correttamente, ma viene cancellato quasi istantaneamente quando l'area client della finestra viene ridipinta.Il programma che ha creato la finestra su cui sto disegnando è Blocco note.Mentre il cursore lampeggia, ciò che ho disegnato viene cancellato.

Qualcuno conosce un modo per sospendere temporaneamente la verniciatura della finestra?

Grazie!

È stato utile?

Soluzione

Vorrei suggerire mettere le immagini in una finestra a più livelli sovrapposti la finestra di destinazione. Che sembra essere il modo più pulito. Dopo tutto, a un certo livello del concepimento, questo è lo scopo del window manager:)

Altri suggerimenti

la risposta di tenfour è migliore secondo me, ma lui/lei Anche dovevo spiegare Come farlo, no Appena dire Che cosa fare, quindi adesso IO spieghero Come:

NOTA: Se vuoi il idea principale nella mia soluzione, puoi passare al file ultimo passaggio 9 molto qui sotto (inizia a cercarlo dal basso verso l'alto finché non lo trovi).

Scusa se ho esagerato con la risposta e ho spiegato e dettagliato troppo, ma ti prometto che se leggerai bene, capirai e sarai soddisfatto.

Passo 1: Creare nuovo WNDCLASSEX struttura, quindi impostarla cbSize membro alla dimensione di questa struttura, in byte, utilizzando il metodo sizeof parola chiave e impostare lpszClassName membro di quello che vuoi.Imposta anche il membro hbrBackground sul valore restituito di O GetStockObject funzione da ottenere O il nero, O bianco O pennello grigio, O CreateSolidBrush funzione per ottenere un pennello del colore che desideri.È molto importante per scegliere il colore che fanno tutti i tuoi disegni non usalo affatto!!!E non solo per il tuo piacere!

Per esempio:

WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = "myNewClassName";
HBRUSH background_brush = GetStockObject(BLACK_BRUSH);
wcex.hbrBackground = background_brush;

Passo 2: Definire una nuova funzione che è una procedura finestra e quindi creare un nuovo puntatore a funzione di essa.Quindi impostare il lpfnWndProc membro di wcex a quel puntatore a funzione.

Passaggio 3: Nella definizione della funzione della nuova procedura finestra, aggiungere return 0; qual è scorso riga di codice.

Sopra cambia il parametro uMsg e almeno aggiungi il file WM_PAINT caso.In tal caso, definire la nuova variabile di PAINTSTRUCT, e chiama il BeginPaint E EndPaint funzioni.In entrambe le funzioni, fai riferimento alla variabile like &ps, Se ps è il nome del PAINTSTRUCT variabile.

Dopo chiami BeginPaint funzione, aggiungi tutte le funzioni di disegno che desideri nella finestra di destinazione, ma assicurati che il file HDC in tutte le funzioni di disegno sono non appartengono alla finestra di destinazione, ma alla finestra in cui hai il relativo handle Primo parametro della procedura finestra, cioè hWnd!!!Chiamata O GetDC O GetWindowDC funzione per recuperare l'hDC di hWnd Primo di tutti.

NOTA: Non è necessario recuperare l'hDc della finestra di destinazione!

Non dimenticare di aggiungere la seguente riga di codice: default: return DefWindowProc(hWnd, uMsg, wParam, lParam); all'interno del blocco del switch dichiarazione.

Passaggio 4: Registra la lezione utilizzando il file RegisterClassEx funzione.

Per esempio: RegisterClassEx(&wcex);

Passaggio 5: Nella tua applicazione, crea new stratificato finestra utilizzando il file CreateWindowEx funzione.È molto importante che hai impostato il Primo parametro di questa funzione a WS_EX_LAYERED per dichiarare che la nuova finestra creata è stratificato.

Impostare il secondo parametro al nome della nuova classe registrata, ad esempio "myNewClassName", ignora il terzo parametro (impostatelo su NULL), e nel il quarto parametro, impostare i seguenti flag: WS_POPUP | WS_VISIBLE

NOTA: WS_POPUP creerà la nuova finestra senza confine.Questo è il motivo per cui ho ignorato il hIcon membro di wcex e anche il terzo parametro impostato su NULLPuoi sostituire WS_POPUP con WS_POPUPWINDOW Invece.Il risultato sarà lo stesso, ma WS_POPUPWINDOW anche disegna delineato rettangolo grigio, sottile con solo 1 pixel di spessore su tutta l'area client. WS_POPUP fa non disegnare qualcosa in contrasto con WS_POPUPWINDOW, Appena rimuove il bordo in questo modo.

Ho impostato anche il WS_VISIBLE flag per mostrare la finestra.Se non imposti questo flag, dovrai chiamare ShowWindow funzione dopo CreateWindowEx, per mostrare la finestra a più livelli.

Passaggio 6: Chiamata SetLayeredWindowAttributes funzione dopo CreateWindowEx.Impostare il Primo parametro all'handle della nuova finestra a più livelli creata restituita dal file CreateWindowEx funzione.

Impostare il secondo parametro per il colore di sfondo del client della tua finestra, ad es.al colore del pennello solido conservato nel background_brush variabile dell'esempio, utilizzata per impostare il membro hbrBackground del wcex il cui tipo è WNDCLASSEX.

Nota che è il tipo di dati di questo parametro COLORREF, e non HBRUSH, cioè.lo fa non accetta un pennello solido, ma semplicemente un colore!

Se conosci il colore del pennello solido che hai scelto nel file GetStockObject funzione, allora sai come crearla COLORREF struttura.

Se hai chiamato CreateSolidBrush funzione invece, quindi prima di chiamarla, definisci la nuova variabile of COLORREF struttura che memorizzerà il colore del pennello solido e il crKey in futuro.Successivamente puoi utilizzare la variabile in entrambe le funzioni: CreateSolidBrush E SetLayeredWindowAttributes (nel secondo parametro, cioè crKey).

Se hai seguito il mio esempio sopra, e tu soltanto avere il background_brush variabile il cui tipo è HBRUSH che memorizza il pennello solido per il membro hbrBackground di wcex, e tu lo fai non avere un COLORREF appropriato per il crKey parametro, quindi:

Per ottenere il colore del pennello solido di cui è il tipo HBRUSH A COLORREF struttura quindi:

È possibile utilizzare la funzione getObject per ottenere le informazioni di logbrush del Brush, il cui componente LBColor fornirà il valore del colore in colorf.Puoi usare le funzioni getRValue, getGValue e getBValue per ottenere anche i singoli componenti del colore.

La risposta di Pravin a qualcuno che doveva sapere come arrivare COLORREF Di HBRUSH come pennello solido.

Ecco il link per maggiori informazioni:

http://forums.codeguru.com/showthread.php?423605-Color-of-HBRUSH

Se desideri un altro modo per recuperare il file corretto COLORREF struttura per il crKey parametro di SetLayeredWindowAttributes funzione, allora puoi provare la funzione GetBkColor funzione dopo aver recuperato il file hDc prima della nuova finestra a più livelli creata.O chiamata SelectObject funzione invece.Impostato Primo parametro sul dc della nuova finestra a più livelli e impostare secondo parametro al hbrBackground membro del wcex o bakcground_brush dell'esempio sopra.

Allora basta chiamare il GetDCBrushColor funzione per ottenere il COLORREF struttura per il crKey parametro del SetLayeredWindowAttributes funzione.

Ignora il terzo parametro (impostaz bAlpha A NULL), e nel il quarto il parametro imposta solo il LWA_COLORKEY bandiera.crKey è il colore di hbrBackground, l'intero client della finestra a livelli non verrà disegnato, ad eccezione degli altri pixel il cui colore non è crKey.Ora tutto ciò che devi fare è delimitare la finestra a più livelli sul client della finestra di destinazione.

Passaggio 7: Chiamata O FindWindow O FindWindowEx funzione per recuperare l'handle della finestra di destinazione, se non lo hai ancora.

Passaggio 8: Scrivi il loop del messaggio (o seleziona e copia il pezzo di codice qui sotto e incollalo nel tuo):

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

Passaggio 9 (ultimo): Nel ciclo di messaggi (all'interno del blocco del ciclo while) non importa dove (prima di TranslateMessage o dopo DispatchMessage o tra di loro), scrivi un altro pezzo di codice che ogni momento ha associato la finestra a più livelli al client della finestra di destinazione:

Prima di tutto creare nuova struttura POINT e imposta le sue coordinate su (0;0) (Imposta il suo x E y membri a 0).

Allora chiama ClientToScreen funzione.Impostare il Primo parametro all'handle della finestra di destinazione (restituito dal file FindWindow O FindWindowEx funzione) e nel secondo il parametro fa riferimento alla struttura POINT creata in precedenza.

Dopo la chiamata a ClientToScreen funzione, la struttura POINT memorizza le coordinate del bordo SUPERIORE più SINISTRO della finestra di destinazione (nelle coordinate dello schermo, misurate in unità di pixel).

Ora devi recuperare il file misurare del client della finestra di destinazione.Per farlo dopo definire nuova variabile il cui tipo è the RECT struttura.

Allora chiama GetClientRect funzione.Impostare il Primo parametro all'handle della finestra di destinazione e nel file secondo Il parametro fa riferimento alla variabile il cui tipo è il RECT struttura.

Dopo la chiamata a GetClientRect funzione, il RECT La variabile memorizza la larghezza e l'altezza del client della finestra di destinazione, misurata in unità di pixel.IL right il membro memorizza il larghezza, e il bottom il membro memorizza il altezza.Ignora il left E topmembri della variabile il cui tipo è the RECT struttura.Non vengono utilizzati né impostati e avranno sempre il loro valore predefinito, ad es.0 solo in questo caso.

Dopo aver ottenuto la posizione del client della finestra di destinazione (la posizione e la dimensione), ora puoi associare la finestra a più livelli al client della finestra di destinazione chiamando O MoveWindow O SetWindowPos funzione, in questo modo:

MoveWindow(hWnd, point.x, point.y, rect.right, rect.bottom, TRUE);
//If you want, you can set the last parameter to FALSE.
//OR
SetWindowPos(hWnd, hTargetWnd, point.x, point.y, rect.right, rect.bottom, NULL);
//If you want, you can specify some flags in the last parameter.
//Where hWnd is the handle of the layered window returned from CreateWindowEx function, and hTargetWnd is the handle of the target window returned from either FindWindow or FindWindowEx function.

Se hai deciso di utilizzare il file MoveWindow funzione, e hai problemi a non vedere i tuoi dipinti nella finestra di destinazione, perché la finestra a più livelli lo è sotto la finestra di destinazione.Dovrai cambiare la chiamata in SetWindowPos funzione invece per risolvere questo problema allora.Nel secondo parametro ho invocato il sistema in cui voglio posizionare la finestra a strati delimitata Sopra la finestra di destinazione.Se il problema persiste, puoi modificare questo parametro e impostarlo su O HWND_TOP O HWND_TOPMOST bandiera.

Sono sicuro che dopo dovrebbe funzionare bene.Non dimenticare a volte di invalidare, ridisegnare o aggiornare la finestra a più livelli per aggiornare i tuoi disegni sulla finestra di destinazione.Puoi chiamare O InvalidateRect O RedrawWindow O UpdateWindow funzione per farlo.

Per esempio:

POINT point;
ClientToScreen(hTargetWnd, &point);

RECT rect;
GetClientRect(hTargetWnd, &rect);

MoveWindow(hWnd, point.x, point.y, rect.right, rect.bottom, TRUE);
//OR
SetWindowPos(hWnd, hTargetWnd, point.x, point.y, rect.right, rect.bottom, NULL);

InvalidateRect(hWnd, NULL, TRUE);
//If you want, you can set the third parameter to FALSE.

(Puoi selezionare e copiare il codice di esempio qui sopra e incollarlo anche nel tuo):

Il codice di esempio può trovarsi nel loop di messaggi, significa che la finestra a più livelli verrà associata e aggiornata ogni momento, ma se lo fai non vuoi ogni momento, ma ogni volta che fai qualcosa, o ogni volta che succede qualcosa, con la finestra di destinazione, che non appartiene alla tua applicazione, come Blocco note, allora dovrai chiamare il SetWindowsHookEx funzione.È possibile ottenere ulteriori informazioni su tale funzione sul sito MSDN e su altri siti sul Web.

Se vuoi che ciò accada in ogni momento, ma non nel ciclo dei messaggi, puoi farlo in un altro ciclo while di un altro thread, ma dovrai creare una funzione per questo e chiamare CreateThread funzione.Ancora una volta, puoi anche ottenere informazioni su tale funzione sul sito MSDN e su altri siti sul Web

Assicurati che il ciclo while del thread termini quando termina il processo della tua applicazione O uscito O terminato.

Puoi anche provare entrambi IsWindow O IsWindowVisible funzione nella condizione del ciclo while per determinare se fermarsi quando la finestra a più livelli e/o la finestra di destinazione vengono attivate O distrutto O chiuso (finito, non sarà minimizzato o iconico).

No.

Invece, perché non gancio WM_PAINT, quindi si disegna quando disegnano?

Si può provare l'invio di messaggi WM_SETREDRAW alla finestra, con wParam set per FALSE di sospendere la pittura, quindi impostare a TRUE per ripristinare un comportamento normale.

Questo è piuttosto un soluzione invadente, però.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top