Discussion:
Gdiplus and Multithreading.
(too old to reply)
Infro
2007-09-10 21:18:01 UTC
Permalink
When I try to use an Image Object created in a auxilery thread, all the other
threads of the same process cannot use this object. Is there a way around
this?
This is particularly annoying because I am trying to use
CreateTimerQueueTimer for syncronizing the Image Frames.

Example:
[code]
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(hThreadId,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
return 0;
}
case WM_DESTROY:
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}

UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
ExitThread(NULL);
return NULL;
}
[/code]
This will always break at if(st), and always with InvalidParamater.
Mark Salsbery [MVP]
2007-09-11 02:21:53 UTC
Permalink
I don't know if you left out code but I'm wondering:

Did you intentionally leave out a call to EndPaint() in your WM_PAINT
handling code?

I don't see any synchronization code - what guarantees MyThread executes
before any WM_PAINT message is processed?

Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Post by Infro
When I try to use an Image Object created in a auxilery thread, all the other
threads of the same process cannot use this object. Is there a way around
this?
This is particularly annoying because I am trying to use
CreateTimerQueueTimer for syncronizing the Image Frames.
[code]
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(hThreadId,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
ExitThread(NULL);
return NULL;
}
[/code]
This will always break at if(st), and always with InvalidParamater.
Infro
2007-09-11 03:16:01 UTC
Permalink
EndPaint was a bug, that was just some code I made to test to see if the
problem existed because of different threads.
WaitForSingleObject was suppose to do wait for the thread to terminate as it
states, but after running it in olly I see that it doesn't,, From
http://msdn2.microsoft.com/en-us/library/ms687032.aspx

"The WaitForSingleObject function can wait for the following objects:

* Change notification
* Console input
* Event
* Memory resource notification
* Mutex
* Process
* Semaphore
* Thread
* Waitable timer"

But still, I know the thread executes before the DrawImage function executes
because I put breakpoints on the thread and the function, just to make sure
when I did run it. InvalidParamater, every time.
Also, I'll be posting new code for anyone to test, that has the SetEvent in
the thread.
Infro
Post by Mark Salsbery [MVP]
Did you intentionally leave out a call to EndPaint() in your WM_PAINT
handling code?
I don't see any synchronization code - what guarantees MyThread executes
before any WM_PAINT message is processed?
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Post by Infro
When I try to use an Image Object created in a auxilery thread, all the other
threads of the same process cannot use this object. Is there a way around
this?
This is particularly annoying because I am trying to use
CreateTimerQueueTimer for syncronizing the Image Frames.
[code]
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(hThreadId,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
ExitThread(NULL);
return NULL;
}
[/code]
This will always break at if(st), and always with InvalidParamater.
Infro
2007-09-11 04:22:00 UTC
Permalink
#include "windows.h"
#include "gdiplus.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void main() {
WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWNORMAL);
return;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow) {
static TCHAR szAppName[]=TEXT("Windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=szAppName;

if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("This program requires Windows
NT!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(szAppName, //window class name
TEXT("Windows Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters

ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// MessageBox(NULL,TEXT("IDrawText"),TEXT("CAPTION"),MB_OK);
return msg.wParam;
}

ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
HANDLE g_hThreadEvent;

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
g_hThreadEvent=CreateEvent(NULL,TRUE,FALSE,TEXT("g_hThreadEvent_Gditest"));
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(g_hThreadEvent,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
EndPaint(hwnd,&ps);
return 0;
}
case WM_DESTROY:
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}

UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
SetEvent(g_hThreadEvent);
ExitThread(NULL);
return NULL;
}
Joe Butler
2007-09-11 08:55:40 UTC
Permalink
I don't use gdi+, but...

if you do:
MyImage=new Gdiplus::Image(L"Image.bmp");
from the wm_create handler instead of from the thread can you confirm that
it now works?

Is the Image.bmp file being found? e.g. if you are running from dev studio,
it may be looking for the file in a different directory to where the exe is
located.

your threading wait that didn't work:
you probably want somethign like this.

hThread= CreateThread();
WaitForSingleObject(hThread);
CloseHandle(hThread);

and in the thread:
thread(){
no events needed. the waitfor will return as soon as this thread exits.
}
Post by Infro
#include "windows.h"
#include "gdiplus.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void main() {
WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWNORMAL);
return;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow) {
static TCHAR szAppName[]=TEXT("Windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("This program requires Windows
NT!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(szAppName, //window class name
TEXT("Windows Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// MessageBox(NULL,TEXT("IDrawText"),TEXT("CAPTION"),MB_OK);
return msg.wParam;
}
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
HANDLE g_hThreadEvent;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
g_hThreadEvent=CreateEvent(NULL,TRUE,FALSE,TEXT("g_hThreadEvent_Gditest"));
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(g_hThreadEvent,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
EndPaint(hwnd,&ps);
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
SetEvent(g_hThreadEvent);
ExitThread(NULL);
return NULL;
}
Mark Salsbery [MVP]
2007-09-11 16:35:02 UTC
Permalink
As for one of the comments in your original post...
Post by Infro
Post by Infro
When I try to use an Image Object created in a auxilery thread, all the
other threads of the same process cannot use this object.
That's not true.

Looking at your latest code sample:

The thread here is useless, but I'm assuming you'll be doing more and this
is a test.

Your code should work provided there's no runtime errors.

I would start with a breakpoint at where you create/load the image in the
aux thread.
Single step past the "MyImage = new..." line and do a quickwatch on MyImage
Gdiplus::Image::lastResult should be Ok. If not, your image didn't load.


Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Post by Infro
#include "windows.h"
#include "gdiplus.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void main() {
WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWNORMAL);
return;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow) {
static TCHAR szAppName[]=TEXT("Windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("This program requires Windows
NT!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(szAppName, //window class name
TEXT("Windows Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// MessageBox(NULL,TEXT("IDrawText"),TEXT("CAPTION"),MB_OK);
return msg.wParam;
}
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
HANDLE g_hThreadEvent;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
g_hThreadEvent=CreateEvent(NULL,TRUE,FALSE,TEXT("g_hThreadEvent_Gditest"));
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(g_hThreadEvent,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
EndPaint(hwnd,&ps);
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
SetEvent(g_hThreadEvent);
ExitThread(NULL);
return NULL;
}
Infro
2007-09-11 18:06:01 UTC
Permalink
You all are right, A simple change fixed that test program's problem,
L"MyImage" (doh, idiot mistake), question is now reverted back to my old one,
why isn't it working there after it successfully creates the image. I think
I'm going to try and put some break points on the memmories around my
pointers, just to make sure some buffer isn't overrunning. :) Thanks for all
the help so far.

Infro
Post by Mark Salsbery [MVP]
As for one of the comments in your original post...
Post by Infro
Post by Infro
When I try to use an Image Object created in a auxilery thread, all the
other threads of the same process cannot use this object.
That's not true.
The thread here is useless, but I'm assuming you'll be doing more and this
is a test.
Your code should work provided there's no runtime errors.
I would start with a breakpoint at where you create/load the image in the
aux thread.
Single step past the "MyImage = new..." line and do a quickwatch on MyImage
Gdiplus::Image::lastResult should be Ok. If not, your image didn't load.
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Post by Infro
#include "windows.h"
#include "gdiplus.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void main() {
WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOWNORMAL);
return;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow) {
static TCHAR szAppName[]=TEXT("Windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=szAppName;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("This program requires Windows
NT!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd=CreateWindow(szAppName, //window class name
TEXT("Windows Program"), //window caption
WS_OVERLAPPEDWINDOW, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// MessageBox(NULL,TEXT("IDrawText"),TEXT("CAPTION"),MB_OK);
return msg.wParam;
}
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
HANDLE g_hThreadEvent;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
g_hThreadEvent=CreateEvent(NULL,TRUE,FALSE,TEXT("g_hThreadEvent_Gditest"));
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(g_hThreadEvent,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
EndPaint(hwnd,&ps);
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
SetEvent(g_hThreadEvent);
ExitThread(NULL);
return NULL;
}
Infro
2007-09-11 18:32:07 UTC
Permalink
As it turns out, this problem that has been nagging me for so long is a
simple problem. In one area I defined a structure with RectF first, then
Image,, same structure, different file, defined it the other way around, I
was passing the wrong arguments to DrawImage,,, now I feel like a true
dumb***,, ah well, at least I know why It wasn't working now.
Mark Salsbery [MVP]
2007-09-11 18:43:00 UTC
Permalink
Cool :)

Cheers,
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Post by Infro
As it turns out, this problem that has been nagging me for so long is a
simple problem. In one area I defined a structure with RectF first, then
Image,, same structure, different file, defined it the other way around, I
was passing the wrong arguments to DrawImage,,, now I feel like a true
dumb***,, ah well, at least I know why It wasn't working now.
Michael Phillips, Jr.
2007-09-11 13:30:54 UTC
Permalink
Have you tried loading your image as a stream.

Gdiplus maintains a file lock for the life of an image because it does not
internally allocate resources until the image bits are actually accessed.

Try creating an IStream interface from the image file and Marshaling the
interface pointer to your image loading thread.
Post by Infro
When I try to use an Image Object created in a auxilery thread, all the other
threads of the same process cannot use this object. Is there a way around
this?
This is particularly annoying because I am trying to use
CreateTimerQueueTimer for syncronizing the Image Frames.
[code]
ULONG_PTR g_GDI_Token;
HANDLE hThreadId;
UINT WINAPI CALLBACK MyThread(LPVOID lParam);
Gdiplus::Image* MyImage;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
switch(message)
{
case WM_CREATE: {
SECURITY_ATTRIBUTES sa;
Gdiplus::GdiplusStartupInput l_GDI_SI;
ZeroMemory((BYTE*)&l_GDI_SI,sizeof (l_GDI_SI));
ZeroMemory((BYTE*)&sa,sizeof(sa));
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
l_GDI_SI.GdiplusVersion=1;
GdiplusStartup(&g_GDI_Token,&l_GDI_SI,NULL);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)MyThread,NULL,NULL,(LPDWORD)&hThreadId);
WaitForSingleObject(hThreadId,INFINITE);
CloseHandle(hThreadId);
return 0;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
if(!GetUpdateRect(hwnd,&rect,0)) return 0;
hdc=BeginPaint(hwnd,&ps);
Gdiplus::Graphics gr(hdc);
gr.DrawImage(MyImage,0,0,400,400);
Gdiplus::Status st=gr.GetLastStatus();
if(st) __asm int 3;
return 0;
}
delete MyImage;
GdiplusShutdown(g_GDI_Token);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
UINT WINAPI CALLBACK MyThread(LPVOID lParam) {
MyImage=new Gdiplus::Image(L"Image.bmp");
ExitThread(NULL);
return NULL;
}
[/code]
This will always break at if(st), and always with InvalidParamater.
Loading...