I bit new to win32 I usually work with Qt.
I want to create a splash type window i.e. a window on different thread and rotate a image with transparent background till the main thread is busy.
I found a code of splash screen in win32. and tried to modify it. Please help me to do following task.
1) call "drawImage" method again and again to animate.
2) how to set transparency or alpha blend on. (image have transparent background).
3) how to remove previous image data.
BusyWnd.h
class CBusyWnd
{
public:
CBusyWnd ( HWND inParent = NULL );
~CBusyWnd ( void );
public:
void setImage ( Gdiplus::Image& inImage);
void setWindowName ( LPCWSTR inName );
void show ( );
void hide ( );
inline HWND windowHandle ( ) const{return mWnd;}
private:
bool regWndClass ( WNDCLASS& outWndClass);
void findImagePos ( RECT& outRect);
void eventLoop ( );
void drawImage ( HWND inHwnd);
static LRESULT CALLBACK wndProc ( HWND inHW,
UINT inMsg,
WPARAM inWParam,
LPARAM inLParam);
static unsigned int __stdcall threadProc ( void* inLPParameter);
private:
HWND mParent;
HWND mWnd;
std::wstring mName;
HANDLE mEvent;
HANDLE mThread;
unsigned int mThreadID;
Gdiplus::Image* mImage;
Gdiplus::REAL mAngle;
};
BusyWnd.cpp
CBusyWnd::CBusyWnd (HWND inParent)
:mParent(inParent),
mWnd(NULL),
mEvent(NULL),
mThread(NULL),
mThreadID(0),
mImage(NULL),
mAngle(0.0){}
CBusyWnd::~CBusyWnd (void)
{
hide();
if(mImage) delete mImage;
}
void CBusyWnd::setImage ( Gdiplus::Image& inImage )
{
if (mImage == NULL && &inImage != NULL)
mImage = inImage.Clone();
}
void CBusyWnd::setWindowName( LPCWSTR inName )
{
mName = inName;
}
void CBusyWnd::show ( )
{
if (mThread == NULL)
{
mEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
mThread = (HANDLE) _beginthreadex ( NULL,
0,threadProc,
static_cast<LPVOID>(this),
0,&mThreadID);
if (WaitForSingleObject(mEvent, 5000) == WAIT_TIMEOUT)
{
OutputDebugString(L"Error starting \"Busy Window\" Thread\n");
}
}
else
{
PostThreadMessage( mThreadID, WM_ACTIVATE, WA_CLICKACTIVE, 0 );
}
}
void CBusyWnd::hide ( )
{
if (mThread)
{
PostThreadMessage(mThreadID, WM_QUIT, 0, 0);
if ( WaitForSingleObject(mThread, 9000) == WAIT_TIMEOUT )
{
::TerminateThread( mThread, 2222 );
}
CloseHandle(mThread);
CloseHandle(mEvent);
}
mThread = NULL;
}
bool CBusyWnd::regWndClass ( WNDCLASS& outWndClass )
{
outWndClass.style = CS_HREDRAW | CS_VREDRAW;
outWndClass.lpfnWndProc = wndProc;
outWndClass.hInstance = GetModuleHandle(NULL);
outWndClass.hCursor = LoadCursor(NULL, IDC_APPSTARTING);
outWndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
outWndClass.lpszClassName = L"BusyWnd";
outWndClass.hIcon = LoadIcon(outWndClass.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClass(&outWndClass))
{
if (GetLastError() != 0x00000582) {
OutputDebugString(L"Unable to register class BusyWnd\n");
return false;
}
}
return true;
}
void CBusyWnd::findImagePos ( RECT& outRect )
{
POINT point = { 0 };
MONITORINFO mi = { sizeof(MONITORINFO), 0 };
HMONITOR hMonitor = 0;
::GetCursorPos( &point );
hMonitor = ::MonitorFromPoint( point, MONITOR_DEFAULTTONEAREST );
if ( ::GetMonitorInfo( hMonitor, &mi ) )
{
outRect.left = ( mi.rcMonitor.right + mi.rcMonitor.left - static_cast<long>(mImage->GetWidth()) ) /2;
outRect.top = ( mi.rcMonitor.top + mi.rcMonitor.bottom - static_cast<long>(mImage->GetHeight()) ) /2;
}
else
{
SystemParametersInfo(SPI_GETWORKAREA, NULL, &outRect, NULL);
outRect.left = (outRect.right + outRect.left - mImage->GetWidth())/2;
outRect.top = (outRect.top + outRect.bottom - mImage->GetHeight())/2;
}
}
void CBusyWnd::eventLoop ( )
{
SetWindowLongPtr(mWnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this) );
ShowWindow(mWnd, SW_SHOWNOACTIVATE);
MSG msg;
BOOL bRet;
LONG timerCount = 0;
PeekMessage(&msg, NULL, 0, 0, 0); SetEvent(mEvent);
while ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1 || msg.message == WM_QUIT)
return;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(mWnd);
}
void CBusyWnd::drawImage ( HWND inHwnd )
{
if (mImage)
{
Gdiplus::Graphics gdip(inHwnd);
gdip.ResetTransform();
gdip.TranslateTransform((Gdiplus::REAL)(mImage->GetWidth())/2.0f,(Gdiplus::REAL)(mImage->GetHeight())/2.0f);
gdip.RotateTransform(mAngle=mAngle>360?0:mAngle+1);
gdip.TranslateTransform(-1.0f*(Gdiplus::REAL)(mImage->GetWidth())/2.0f,-1.0f*(Gdiplus::REAL)(mImage->GetHeight())/2.0f);
gdip.DrawImage(mImage, 0, 0, mImage->GetWidth(), mImage->GetHeight());
}
InvalidateRect(inHwnd, NULL, TRUE);
}
unsigned int __stdcall CBusyWnd::threadProc ( void* inLPParameter )
{
CBusyWnd* bWnd = static_cast<CBusyWnd*>(inLPParameter);
if (bWnd->mImage == NULL) return 0;
WNDCLASS wndcls = {0};
if(!bWnd->regWndClass(wndcls))
return 0;
RECT rcArea = { 0 };
bWnd->findImagePos(rcArea);
bWnd->mWnd = CreateWindowEx ( bWnd->mName.length()?0:WS_EX_TOOLWINDOW,
L"BusyWnd",
bWnd->mName.c_str(),
WS_CLIPCHILDREN|WS_POPUP,
rcArea.left,
rcArea.top,
bWnd->mImage->GetWidth(),
bWnd->mImage->GetHeight(),
bWnd->mParent,
NULL,
wndcls.hInstance,
NULL);
if (!bWnd->mWnd)
{
OutputDebugString(L"Unable to create BusyWnd\n");
return 0;
}
bWnd->eventLoop();
return 0;
}
LRESULT CALLBACK CBusyWnd::wndProc ( HWND inHW,
UINT inMsg,
WPARAM inWParam,
LPARAM inLParam )
{
CBusyWnd* bWnd = reinterpret_cast<CBusyWnd*>(GetWindowLongPtr(inHW, GWL_USERDATA));
if (bWnd == NULL)
return DefWindowProc(inHW, inMsg, inWParam, inLParam);
switch (inMsg)
{
case WM_PAINT:
bWnd->drawImage(inHW);
break;
}
return DefWindowProc(inHW, inMsg, inWParam, inLParam);
}
in this code I am not able to call my drawImage method again and again. when I call show it start a new thread and create a Image window and when I call hide it kills the thread and window.