// Common, groups WinWrap and WinSystem
// Copyright Alexander Liss
#include "winsystem.h"
#include "gdi.h"
AppInstanceData *G_app_instance_data=0;
struct CreationCallbackData
{
int (*callback)(LPVOID);
LPVOID data;
};
BOOL CALLBACK property_destruction_callback(HWND hWnd,LPTSTR lpszString,HANDLE , DWORD )
{
::RemoveProp(hWnd, lpszString);
return TRUE;
}
BOOL CALLBACK window_destruction_callback(HWND hwnd, LPARAM lParam )
{
Window w(hwnd);
w.destroy();
return TRUE;
}
// WindowDriver
LRESULT CALLBACK WindowDriver::generic_procedure(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if(!IsWindow(hWnd)) return 1;
int g=0;
WindowMessageData message(uMsg,wParam,lParam);
GenericWindow window(hWnd);
WindowDriver *p=window.get_driver();
if(p)
{
g=p->respond(window,message);
if(g==-1) return 1; // error
if(!g) return 0; // processed
}
BOOL z=::DefWindowProc( hWnd, uMsg, wParam, lParam );
if(z && message.message==WM_DESTROY)
{
z=window.destroy();
}
return z;
}
BOOL CALLBACK WindowDriver::dialog_procedure(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if(!IsWindow(hWnd)) return 1;
int g=0;
WindowMessageData message(uMsg,wParam,lParam);
DialogWindow window(hWnd);
WindowDriver *p=window.get_driver();
if(p)
{
g=p->respond(window,message);
if(!g) return TRUE; // processed
}
if( message.message==WM_DESTROY)
{
window.destroy();
}
// PASS TO TEMPLATE DEFINED DIALOG PROCEDURE
return FALSE;
}
// WindowTemplateData
BOOL WindowTemplateData::set_from(const WindowTemplateId& id)
{
WNDCLASSEX data;
data.cbSize=sizeof(WNDCLASSEX);
BOOL g=::GetClassInfoEx(id.app_instance,id.name,&data);
if(!g) return FALSE;
style=data.style;
procedure=data.lpfnWndProc;
icon=data.hIcon;
cursor=data.hCursor;
background=data.hbrBackground;
menu_name=data.lpszMenuName;
small_icon=data.hIconSm;
return TRUE;
}
// WindowTemplate
BOOL WindowTemplate::store(const WindowTemplateData& d,const WindowTemplateId& Id)
{
id=Id;
WNDCLASSEX data;
data.cbSize=sizeof(WNDCLASSEX);
data.style=d.style;
data.lpfnWndProc=d.procedure;
data.cbClsExtra=0;
data.cbWndExtra=0;
data.hInstance=Id.app_instance;
data.hIcon=d.icon;
data.hCursor=d.cursor;
data.hbrBackground=d.background;
data.lpszMenuName=d.menu_name;
data.lpszClassName=Id.name;
data.hIconSm=d.small_icon;
handle=::RegisterClassEx(&data);
return handle!=0;
}
BOOL WindowTemplate::remove()
{
BOOL z = ::UnregisterClass(id.name,id.app_instance);
if(z)
{
id.name=0;
id.app_instance=0;
handle=0;
}
return z;
};
BOOL WindowTemplate::get_stored(WindowTemplateData& d )
{
return d.set_from(id);
}
// WindowData
BOOL WindowData::set_client_area(const Area& z)
{
RECT r = z.get_rect();
::AdjustWindowRectEx(&r,style,(menu != 0),style_ex);
return 0;
}
// WINDOW
UINT Window::change_base_style(UINT style)const
{ return (UINT)::SetClassLong(handle,GCL_STYLE,(LONG)style);}
HICON Window::change_icon(HICON icon)const
{ return (HICON)::SetClassLong(handle,GCL_HICON,(LONG)icon);}
HICON Window::change_small_icon(HICON small_icon)const
{ return (HICON)::SetClassLong(handle,GCL_HICONSM,(LONG)small_icon);}
HCURSOR Window::change_cursor(HCURSOR cursor)const
{ return (HCURSOR)::SetClassLong(handle,GCL_HCURSOR,(LONG)cursor);}
HBRUSH Window::change_background(HBRUSH brush)const
{ return (HBRUSH)::SetClassLong(handle,GCL_HBRBACKGROUND,(LONG)brush);}
LPCTSTR Window::change_base_menu(LPCTSTR name)const
{ return (LPCTSTR)::SetClassLong(handle,GCL_MENUNAME,(LONG)name);}
DWORD Window::change_style(DWORD style)const
{return ::SetWindowLong(handle,GWL_STYLE,(LONG)style);}
DWORD Window::change_style_ex(DWORD style)const
{return ::SetWindowLong(handle,GWL_EXSTYLE,(LONG)style);}
WindowDriver* Window::change_driver(WindowDriver &z)
{return (WindowDriver*)::SetWindowLong(handle,GWL_USERDATA,(LONG)(&z));}
BOOL Window::store_data( LPCTSTR data_name, HANDLE data)
{ if(handle) return ::SetProp(handle,data_name,data); return FALSE;}
VOID Window::remove_data( LPCTSTR data_name)
{ ::RemoveProp(handle,data_name);}
HANDLE Window::get_stored_data(LPCTSTR data_name)const
{ if(handle) return ::GetProp(handle,data_name); return 0;}
BOOL Window::destroy()
{
if(!handle) return FALSE;
// destroy window's "properties"
EnumPropsEx(handle,property_destruction_callback, NULL);
// remove window's driver
::SetWindowLong(handle,GWL_USERDATA,0);
BOOL z=::DestroyWindow(handle);
handle=0;
return z;
}
BOOL Window::client_area(Area& z)const
{
if(!handle) return FALSE;
RECT r;
BOOL g=::GetClientRect(handle,&r);
if(!g) return FALSE;
z.set(r);
return TRUE;
}
BOOL Window::selfsend_destroy_message()
{
WindowMessageData m(WM_DESTROY);
return send(m,handle);
}
BOOL Window::selfsend_end_thread_message()
{
BOOL z=selfsend_destroy_message();
if(z)
{
WindowMessageData m(WM_QUIT);
z=send(m,handle);
}
return z;
}
// GenericWindow
int GenericWindow::create(
LPCTSTR name,
const WindowData& d,
const WindowId& parent,
const WindowDriver &driver
)
{
handle=::CreateWindowEx(
d.style_ex,
d.window_template.get_id().name,
name,
d.style,
d.area.left,
d.area.top,
d.area.width,
d.area.height,
parent.window,
d.menu,
parent.app_instance,
0);
if(!handle) return 1;
set(driver);
return 0;
}
// DialogWindow
int DialogWindow::create(
LPCTSTR lpTemplateName,
const WindowId& parent,
const WindowDriver &driver
)
{
handle=::CreateDialogParam(
parent.app_instance,
lpTemplateName,
parent.window,
WindowDriver::dialog_procedure,
0);
if(!handle) return 1;
set(driver);
return 0;
}
// FUNCTIONS
int GUI_step( WindowMessageFilter filter, HACCEL accelerator )
{
MSG msg;
BOOL z=FALSE;
z=::get(&msg,filter);
if(z==FALSE) return 1;
if(z==-1) return 2; // error
if(accelerator)
{
z=::process_accelerator(&msg,filter.window,accelerator);
if(z) return 0; // message processed, window procedure called
}
z=::check_process_dialog(&msg,filter.window);
if(z) return 0; // message processed, window procedure called
// pass to window procedure untranslated value to ignore
// and translated value place back in queue
::translate( &msg );
::dispatch(&msg);
return 0;
}
VOID winsystem_thread_cleanup()
{
EnumThreadWindows(GetCurrentThreadId(),window_destruction_callback,0);
}
VOID last_error_message_box(HWND handle)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
MessageBox( handle, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}