Micro framework to generate win32 applications.
Sample:
// Windows Header Files: #include <windows.h> // C RunTime Header Files #include <stdlib.h> #include <malloc.h> #include <memory.h> #include <tchar.h> #include "win32express.h" #include "resource.h" class AboutDlg : public Dialog<AboutDlg, IDD_ABOUT> { void About() { } void OnClose() { EndDialog(IDCANCEL); } void OnOk() { EndDialog(IDCANCEL); PostQuitMessage(1); } public: BEGIN_MSG_MAP(AboutDlg) S_COMMAND_ID_HANDLER(IDCANCEL, OnClose) S_COMMAND_ID_HANDLER(IDOK, OnOk) S_COMMAND_ID_HANDLER(IDM_ABOUT1, About) END_MSG_MAP() AboutDlg(HWND hParent = NULL) : Dialog<AboutDlg, IDD_ABOUT>(hParent) { } void OnPaint(HDC hdc) { ::TextOut(hdc, 10,10,L"hello", 6); } }; class Doc : public Window<Doc, IDI_ICON1, IDR_MENU1> { void Exit() { DestroyWindow(m_hWnd); PostQuitMessage(0); } void About() { AboutDlg dlg(m_hWnd); dlg.ShowDialog(); } public: BEGIN_MSG_MAP(AboutDlg) S_COMMAND_ID_HANDLER(IDM_ABOUT1, About) S_COMMAND_ID_HANDLER(IDM_EXIT1, Exit) END_MSG_MAP() void OnPaint(HDC hdc) { ::TextOut(hdc, 10,10,L"hello", 6); } }; int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { Doc doc; doc.Create(); return RunMessageLoop(); } Header file // Copyright (C) 2010, Thiago Adams (thiago.adams@gmail.com) // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. //This is a experimental code. #pragma once #include <windows.h> #include <commctrl.h> #include <vector> #include <string> #ifndef ASSERT #include <cassert> #define ASSERT assert #endif #include <string.h> template<class T> T* GetWindowDocument(HWND hWnd) { T *pDoc = reinterpret_cast<T *>(static_cast<LONG_PTR>( ::GetWindowLongPtrW(hWnd, GWLP_USERDATA))); return pDoc; } template<class T> T* SetWindowDocument(HWND hWnd, T* pReceiver) { LONG_PTR lptr = ::SetWindowLongPtrW( hWnd, GWLP_USERDATA, PtrToUlong(pReceiver)); T *pOldDoc = (T*)(LONG_PTR)(lptr); return pOldDoc; } template<class T> LRESULT CALLBACK WindowsProcEx(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { T* pDoc = GetWindowDocument<T>(hWnd); BOOL bHandled = false; LRESULT r = Details::SendMessageTo(pDoc, hWnd , message, wParam, lParam, bHandled); if (bHandled) { return r; } return DefWindowProc(hWnd, message, wParam, lParam); } inline bool IsControlKeyPressed() { return (GetKeyState(VK_CONTROL) & 0xf000) == 0xf000; } inline bool IsShiftKeyPressed() { return (GetKeyState(VK_SHIFT) & 0xf000) == 0xf000; } #ifndef GET_X_LPARAM #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) #endif #ifndef GET_Y_LPARAM #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) #endif namespace Details { class MemoryDC { public: HDC m_hDC; HDC m_hDCOriginal; RECT m_rcPaint; HBITMAP m_hBitmap; HBITMAP m_hBmpOld; MemoryDC(HDC hDC, RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL) { m_rcPaint = rcPaint; m_hDC = ::CreateCompatibleDC(m_hDCOriginal); ASSERT(m_hDC != NULL); m_hBitmap = ::CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top); ASSERT(m_hBitmap != NULL); m_hBmpOld = (HBITMAP)::SelectObject(m_hDC, m_hBitmap); ::SetViewportOrgEx(m_hDC, -m_rcPaint.left, -m_rcPaint.top, 0); } ~MemoryDC() { ::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY); (HBITMAP)::SelectObject(m_hDC, m_hBmpOld); ::DeleteObject(m_hBitmap); ::DeleteObject(m_hDC); } }; template<class TEventReceiver> LRESULT SendMessageTo(TEventReceiver* pEventReceiver, HWND hWnd, UINT uMsg, WPARAM wparam, LPARAM lparam, BOOL& bHandled) { bHandled = FALSE; if (pEventReceiver == NULL) { return FALSE; } bHandled = TRUE; switch (uMsg) { //notifications case WM_COMMAND: case WM_NOTIFY: { LRESULT lresult; pEventReceiver->ProcessWindowMessage(hWnd, uMsg, wparam, lparam, lresult); } break; __if_exists(TEventReceiver::OnDeactivate) { case WM_ACTIVATE: { if (LOWORD(wparam) == WA_INACTIVE) { pEventReceiver->OnDeactivate(); } break; } } //OnDeactivate #ifndef _WIN32_WCE __if_exists(TEventReceiver::OnMouseWheel) { case WM_MOUSEWHEEL: { int fwKeys = GET_KEYSTATE_WPARAM(wparam ); short zDelta = GET_WHEEL_DELTA_WPARAM(wparam ); pEventReceiver->OnMouseWheel(fwKeys, zDelta); } break; }//OnMouseWheel #endif __if_exists(TEventReceiver::OnSetFocus) { case WM_SETFOCUS: { pEventReceiver->OnSetFocus(); } break; } __if_exists(TEventReceiver::OnSetCursor) { case WM_SETCURSOR: { if (!pEventReceiver->OnSetCursor()) { bHandled = FALSE; } } break; } __if_exists (TEventReceiver::OnKillFocus) { case WM_KILLFOCUS: { pEventReceiver->OnKillFocus(); } break; }//OnKillFocus __if_exists (TEventReceiver::OnPaint) { case WM_PAINT: { PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); pEventReceiver->OnPaint(hDC); EndPaint(hWnd, &ps); } break; } default: bHandled = FALSE; return FALSE; } return TRUE; } } //namespace details int RunMessageLoop() { MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } return (int) msg.wParam; } DWORD GetStyle(HWND m_hWnd) { ASSERT(::IsWindow(m_hWnd)); return (DWORD)::GetWindowLong(m_hWnd, GWL_STYLE); } BOOL CenterWindow(HWND m_hWnd, HWND hWndCenter = NULL) { ASSERT(::IsWindow(m_hWnd)); // determine owner window to center against DWORD dwStyle = GetStyle(m_hWnd); if(hWndCenter == NULL) { if(dwStyle & WS_CHILD) hWndCenter = ::GetParent(m_hWnd); else hWndCenter = ::GetWindow(m_hWnd, GW_OWNER); } // get coordinates of the window relative to its parent RECT rcDlg; ::GetWindowRect(m_hWnd, &rcDlg); RECT rcArea; RECT rcCenter; HWND hWndParent; if(!(dwStyle & WS_CHILD)) { // don't center against invisible or minimized windows if(hWndCenter != NULL) { DWORD dwStyleCenter = ::GetWindowLong(hWndCenter, GWL_STYLE); if(!(dwStyleCenter & WS_VISIBLE) || (dwStyleCenter & WS_MINIMIZE)) hWndCenter = NULL; } // center within screen coordinates #if WINVER < 0x0500 ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL); #else HMONITOR hMonitor = NULL; if(hWndCenter != NULL) { hMonitor = ::MonitorFromWindow(hWndCenter, MONITOR_DEFAULTTONEAREST); } else { hMonitor = ::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); } //ATLENSURE_RETURN_VAL(hMonitor != NULL, FALSE); MONITORINFO minfo; minfo.cbSize = sizeof(MONITORINFO); BOOL bResult = ::GetMonitorInfo(hMonitor, &minfo); //ATLENSURE_RETURN_VAL(bResult, FALSE); rcArea = minfo.rcWork; #endif if(hWndCenter == NULL) rcCenter = rcArea; else ::GetWindowRect(hWndCenter, &rcCenter); } else { // center within parent client coordinates hWndParent = ::GetParent(m_hWnd); ASSERT(::IsWindow(hWndParent)); ::GetClientRect(hWndParent, &rcArea); ASSERT(::IsWindow(hWndCenter)); ::GetClientRect(hWndCenter, &rcCenter); ::MapWindowPoints(hWndCenter, hWndParent, (POINT*)&rcCenter, 2); } int DlgWidth = rcDlg.right - rcDlg.left; int DlgHeight = rcDlg.bottom - rcDlg.top; // find dialog's upper left based on rcCenter int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2; int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2; // if the dialog is outside the screen, move it inside if(xLeft + DlgWidth > rcArea.right) xLeft = rcArea.right - DlgWidth; if(xLeft < rcArea.left) xLeft = rcArea.left; if(yTop + DlgHeight > rcArea.bottom) yTop = rcArea.bottom - DlgHeight; if(yTop < rcArea.top) yTop = rcArea.top; // map screen coordinates to child coordinates return ::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } // Message handler for about box. template<class T> INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bHandled = FALSE; UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: { T * p = (T*)lParam; SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR) p); p->InitEntry(hDlg); return (INT_PTR)TRUE; } } //TODO : all messages? T * p = (T*)GetWindowLongPtr(hDlg, GWLP_USERDATA); LRESULT r = Details::SendMessageTo(p, hDlg, message, wParam, lParam, bHandled); return bHandled; } template<class T> INT_PTR ShowDialog(LPCWSTR lpTemplateName, T * p, HWND hWndParent) { HINSTANCE hInst = GetModuleHandle(NULL); INT_PTR r = DialogBoxParam(hInst, lpTemplateName, hWndParent, &DlgProc<T>,(LPARAM) p); ASSERT(r != 0); //resource exists? (1813) return r; } template<class T> HWND ShowModeless(UINT IDD, T* p, HWND hParent) { HWND hWnd = NULL; HINSTANCE hInstance = GetModuleHandle(NULL); HRSRC hDlg = FindResource(hInstance, MAKEINTRESOURCE(IDD), RT_DIALOG); if (hDlg != NULL) { DWORD dwLastError = 0; HGLOBAL hResource = LoadResource(hInstance, hDlg); if (hResource != NULL) { DLGTEMPLATE* pDlg = (DLGTEMPLATE*) LockResource(hResource); if (pDlg != NULL) { hWnd = CreateDialogIndirectParam( hInstance, pDlg, hParent, &DlgProc<T>, (LPARAM)p); UnlockResource(hResource); } else dwLastError = ::GetLastError(); } else dwLastError = ::GetLastError(); if (dwLastError != 0) SetLastError(dwLastError); } return hWnd; } template<class T, UINT IDD> class Dialog { protected: HWND m_hDlg; HWND m_hParent; public: int EndDialog(int r) { return ::EndDialog(m_hDlg, r); } UINT GetDlgItemText(int nID, std::wstring& s) const { ASSERT(::IsWindow(m_hDlg)); HWND hItem = GetDlgItem(nID); if (hItem != NULL) { int nLength = ::GetWindowTextLength(hItem); std::vector<wchar_t> buffer(nLength+1); wchar_t* pszText = &buffer[0]; nLength = ::GetWindowText(hItem, pszText, nLength+1); s = pszText; return nLength; } else { s.clear(); return 0; } } HWND GetDlgItem(UINT id) const { return ::GetDlgItem(m_hDlg, id); } Dialog(HWND hParent = NULL) : m_hParent(hParent) { } //WM_INITDIALOG void InitEntry(HWND hDlg) { m_hDlg = hDlg; CenterWindow(m_hDlg, m_hParent); __if_exists (T::InitDialog) { static_cast<T*>(this)->InitDialog(); } } //show modeless void Show() { m_hDlg = ShowModeless(IDD, this, m_hParent); } //show modal int ShowDialog() { return ::ShowDialog(MAKEINTRESOURCE(IDD), static_cast<T*>(this), m_hParent); } }; template<class T, UINT IconId =0, UINT MENUIDD = 0, UINT wStyle = WS_OVERLAPPEDWINDOW | CS_DBLCLKS > class Window { protected: HWND m_hWnd; public: static const WNDCLASSEX * GetClass() { HINSTANCE hInstance = GetModuleHandle(NULL); static WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = &WindowsProcEx<T>; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IconId)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); if (MENUIDD != NULL) wcex.lpszMenuName = MAKEINTRESOURCE(MENUIDD); else wcex.lpszMenuName = NULL; wcex.lpszClassName = L"class"; wcex.hIconSm = 0;//LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_SMALL)); return &wcex; } Window() : m_hWnd(NULL) { } void Create(HWND hWndParent = 0) { HINSTANCE hInstance = GetModuleHandle(NULL); RegisterClassEx(GetClass()); m_hWnd = CreateWindow(GetClass()->lpszClassName, L"", wStyle, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, NULL, hInstance, NULL); SetWindowDocument(m_hWnd, static_cast<T*>(this)); ShowWindow(m_hWnd, TRUE); UpdateWindow(m_hWnd); } }; #if defined _M_IX86 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_IA64 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_X64 #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") #else #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif #define COMMAND_ID_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define S_COMMAND_ID_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = 1;\ bHandled = TRUE;\ func(); \ if(bHandled) \ return TRUE; \ } #define COMMAND_HANDLER(id, code, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define BEGIN_MSG_MAP(theClass) \ public: \ BOOL ProcessWindowMessage(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam,\ _In_ LPARAM lParam, _Inout_ LRESULT& lResult, _In_ DWORD dwMsgMapID = 0) \ { \ BOOL bHandled = TRUE; \ (hWnd); \ (uMsg); \ (wParam); \ (lParam); \ (lResult); \ (bHandled); \ switch(dwMsgMapID) \ { \ case 0: #define END_MSG_MAP() \ break; \ default: \ break; \ } \ return FALSE; \ }