Hallo,
in meinem Programm werden in der WM_PAINT Bearbeitung über Gdiplus Bitmaps aus Dateien geladen und angezeigt. Im Fehlerfall wird eine Meldung mit einer MessageBox gemeldet. Sobald die MessageBox ein Bitmap überdeckt, wird eine neue WM_PAINT Message generiert und nach dem Quittieren der MessageBox wird eine neue MessageBox ausgegeben und das Ganze beginnt wieder von vorne. Den deadlock habe ich gelöst indem ich ich mir die Fehlermeldung als ausgegeben markiere. Aber 2 MessageBoxen für einen Fehler habe ich trotzdem. Das komische dabei ist, bei graphischen Elementen wie Rectangle kann ich dieses Verhalten nicht feststellen. Weiß jemand Rat? Das Programm wurde mit Visual Studio 2008 geschrieben, alles Einstellungen sind Standard mit Ausnahme von Multibyte Zeichensatz.
Gruß
Klaus
Hier ist ein kleines Programm zum Ausprobieren.:
#include "stdafx.h"
#include "messagebox.h"
#include "commctrl.h"
#include <atlimage.h>
#define MAX_LOADSTRING 100
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "comctl32.lib")
using namespace Gdiplus;
// Globale Variablen:
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
ULONG_PTR gdiplusToken;
BOOL Do;
int iCnt;
// Vorwärtsdeklarationen der in diesem Codemodul enthaltenen Funktionen:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int paint(HDC hdc);
int get_image_data(HDC hdc,WCHAR *fname);
HANDLE hImage;
HWND hWndMain;
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
// Globale Zeichenfolgen initialisieren
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MESSAGEBOX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// Anwendungsinitialisierung ausführen:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MESSAGEBOX));
// Hauptnachrichtenschleife:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Gdiplus::GdiplusShutdown(gdiplusToken);
return (int) msg.wParam;
}
//
// FUNKTION: MyRegisterClass()
//
// ZWECK: Registriert die Fensterklasse.
//
// KOMMENTARE:
//
// Sie müssen die Funktion verwenden, wenn Sie möchten, dass der Code
// mit Win32-Systemen kompatibel ist, bevor die RegisterClassEx-Funktion
// zu Windows 95 hinzugefügt wurde. Der Aufruf der Funktion ist wichtig,
// damit die kleinen Symbole, die mit der Anwendung verknüpft sind,
// richtig formatiert werden.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MESSAGEBOX));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MESSAGEBOX);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNKTION: InitInstance(HINSTANCE, int)
//
// ZWECK: Speichert das Instanzenhandle und erstellt das Hauptfenster.
//
// KOMMENTARE:
//
// In dieser Funktion wird das Instanzenhandle in einer globalen Variablen gespeichert, und das
// Hauptprogrammfenster wird erstellt und angezeigt.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HDC hdc;
hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern
hWndMain = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL, NULL,hInstance,NULL);
if (!hWndMain)
{
return FALSE;
}
ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&InitCtrlEx);
hdc = GetDC(hWndMain);
get_image_data(hdc,L"C:\\Test\\Bitmap.jpg");
ReleaseDC(hWndMain,hdc);
return TRUE;
}
//
// FUNKTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// ZWECK: Verarbeitet Meldungen vom Hauptfenster.
//
// WM_COMMAND - Verarbeiten des Anwendungsmenüs
// WM_PAINT - Zeichnen des Hauptfensters
// WM_DESTROY - Beenden-Meldung anzeigen und zurückgeben
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Menüauswahl bearbeiten:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
iCnt++;
get_image_data(hdc,L"C:\\Test\\Bitmap.jpg"); // diese Datei existiert
get_image_data(hdc,L"C:\\Test\\Bitmap.111"); // diese Datei existiert nicht
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Meldungshandler für Infofeld.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
int get_image_data(HDC hdc,WCHAR *fname)
{
TCHAR string[MAX_LOADSTRING+1];
int flag;
Bitmap *pBitmap = Bitmap::FromFile(fname);
flag = pBitmap->GetLastStatus();
if (flag)
{
sprintf_s(string,MAX_LOADSTRING,_T("Aufgerufen %d mal"),iCnt);
MessageBox(NULL,string,_T("Anzahl der durchlaufenen WM_PAINT"),MB_ICONHAND | MB_TASKMODAL);
}
Rect rect(1,1,650,600);
Graphics g(hdc);
g.DrawImage(pBitmap,rect);
delete pBitmap;
return TRUE;
}
in meinem Programm werden in der WM_PAINT Bearbeitung über Gdiplus Bitmaps aus Dateien geladen und angezeigt. Im Fehlerfall wird eine Meldung mit einer MessageBox gemeldet. Sobald die MessageBox ein Bitmap überdeckt, wird eine neue WM_PAINT Message generiert und nach dem Quittieren der MessageBox wird eine neue MessageBox ausgegeben und das Ganze beginnt wieder von vorne. Den deadlock habe ich gelöst indem ich ich mir die Fehlermeldung als ausgegeben markiere. Aber 2 MessageBoxen für einen Fehler habe ich trotzdem. Das komische dabei ist, bei graphischen Elementen wie Rectangle kann ich dieses Verhalten nicht feststellen. Weiß jemand Rat? Das Programm wurde mit Visual Studio 2008 geschrieben, alles Einstellungen sind Standard mit Ausnahme von Multibyte Zeichensatz.
Gruß
Klaus
Hier ist ein kleines Programm zum Ausprobieren.:
#include "stdafx.h"
#include "messagebox.h"
#include "commctrl.h"
#include <atlimage.h>
#define MAX_LOADSTRING 100
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "comctl32.lib")
using namespace Gdiplus;
// Globale Variablen:
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
ULONG_PTR gdiplusToken;
BOOL Do;
int iCnt;
// Vorwärtsdeklarationen der in diesem Codemodul enthaltenen Funktionen:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int paint(HDC hdc);
int get_image_data(HDC hdc,WCHAR *fname);
HANDLE hImage;
HWND hWndMain;
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
HACCEL hAccelTable;
// Globale Zeichenfolgen initialisieren
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_MESSAGEBOX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// Anwendungsinitialisierung ausführen:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MESSAGEBOX));
// Hauptnachrichtenschleife:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Gdiplus::GdiplusShutdown(gdiplusToken);
return (int) msg.wParam;
}
//
// FUNKTION: MyRegisterClass()
//
// ZWECK: Registriert die Fensterklasse.
//
// KOMMENTARE:
//
// Sie müssen die Funktion verwenden, wenn Sie möchten, dass der Code
// mit Win32-Systemen kompatibel ist, bevor die RegisterClassEx-Funktion
// zu Windows 95 hinzugefügt wurde. Der Aufruf der Funktion ist wichtig,
// damit die kleinen Symbole, die mit der Anwendung verknüpft sind,
// richtig formatiert werden.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MESSAGEBOX));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MESSAGEBOX);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNKTION: InitInstance(HINSTANCE, int)
//
// ZWECK: Speichert das Instanzenhandle und erstellt das Hauptfenster.
//
// KOMMENTARE:
//
// In dieser Funktion wird das Instanzenhandle in einer globalen Variablen gespeichert, und das
// Hauptprogrammfenster wird erstellt und angezeigt.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HDC hdc;
hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern
hWndMain = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL, NULL,hInstance,NULL);
if (!hWndMain)
{
return FALSE;
}
ShowWindow(hWndMain, nCmdShow);
UpdateWindow(hWndMain);
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&InitCtrlEx);
hdc = GetDC(hWndMain);
get_image_data(hdc,L"C:\\Test\\Bitmap.jpg");
ReleaseDC(hWndMain,hdc);
return TRUE;
}
//
// FUNKTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// ZWECK: Verarbeitet Meldungen vom Hauptfenster.
//
// WM_COMMAND - Verarbeiten des Anwendungsmenüs
// WM_PAINT - Zeichnen des Hauptfensters
// WM_DESTROY - Beenden-Meldung anzeigen und zurückgeben
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Menüauswahl bearbeiten:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
iCnt++;
get_image_data(hdc,L"C:\\Test\\Bitmap.jpg"); // diese Datei existiert
get_image_data(hdc,L"C:\\Test\\Bitmap.111"); // diese Datei existiert nicht
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Meldungshandler für Infofeld.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
int get_image_data(HDC hdc,WCHAR *fname)
{
TCHAR string[MAX_LOADSTRING+1];
int flag;
Bitmap *pBitmap = Bitmap::FromFile(fname);
flag = pBitmap->GetLastStatus();
if (flag)
{
sprintf_s(string,MAX_LOADSTRING,_T("Aufgerufen %d mal"),iCnt);
MessageBox(NULL,string,_T("Anzahl der durchlaufenen WM_PAINT"),MB_ICONHAND | MB_TASKMODAL);
}
Rect rect(1,1,650,600);
Graphics g(hdc);
g.DrawImage(pBitmap,rect);
delete pBitmap;
return TRUE;
}