Thursday, November 10, 2011

a scratch program

I have been working on a library for building win32 windows. MFC and WTL were both great designs at the time that they were introduced, but C++ has moved on. Then there is Raymond Chen's new(2005) C++ scratch program which eschews libraries and builds a simple base class with virtual functions

One of the things that bothers me about all the existing libraries is that they mix two distinct objects with separate lifetimes into one object with incoherent lifetime. I will go into more detail on this and other design decisions in additional posts.

So here is a port of Raymond's scratch program using my window library.

#define STRICT
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <windowsx.h>
#include <ole2.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <shlobj.h>
#include <shellapi.h>

#include <new>
#include <utility>
#include <memory>
#include <type_traits>
#include <tuple>
#include <string>
#include <vector>

#define LIBRARIES_NAMESPACE mylib
#include "..\libraries\libraries.h"
namespace l = LIBRARIES_NAMESPACE;

void unique_error_report_initiated(
  DWORD value,
  unique_winerror::tag &&)
{
  static DWORD anchor;
  anchor = value;
}

void unique_error_report_reset(
  DWORD value,
  unique_winerror::tag &&)
{
  static DWORD anchor;
  anchor = value;
}

void unique_error_report_initiated(
  HRESULT value,
  unique_hresult::tag &&)
{
  static HRESULT anchor;
  anchor = value;
}

void unique_error_report_reset(
  HRESULT value,
  unique_hresult::tag &&)
{
  static HRESULT anchor;
  anchor = value;
}

namespace RootWindow {
struct tag {};

typedef
  l::wnd::Context<tag>
    Context;

struct window
{
  l::wr::unique_close_window child;

  LRESULT OnCreate(const Context& , LPCREATESTRUCT) {
    return 0;
  }

  LRESULT OnSize(const Context& , UINT , int cx, int cy) {
    if (child) {
      SetWindowPos(
        child.get(), NULL,
        0, 0, cx, cy,
        SWP_NOZORDER | SWP_NOACTIVATE);
    }
    return 0;
  }

  LRESULT PaintContent(PAINTSTRUCT&) {
    return 0;
  }

  LRESULT OnPaint(const Context& context) {
    PAINTSTRUCT ps = {};
    BeginPaint(context.window, &ps);
    l::wr::unique_gdi_end_paint ender(
      std::make_pair(context.window, &ps));
    return PaintContent(ps);
  }

  LRESULT OnPrintClient(const Context& context, HDC hdc, DWORD) {
    PAINTSTRUCT ps = {};
    ps.hdc = hdc;
    GetClientRect(context.window, &ps.rcPaint);
    return PaintContent(ps);
  }

  LRESULT OnNCDestroy(const Context&) {
    PostQuitMessage(0);
    return 0;
  }
};

l::wnd::window_class_traits_builder<window>
window_class_traits(tag &&);

void window_class_register(
  PCWSTR windowClass,
  WNDCLASSEX* wcex,
  tag &&) {
  wcex->style         = 0;
  wcex->hIcon         = NULL;
  wcex->hCursor       = LoadCursor(NULL, IDC_ARROW);
  wcex->lpszMenuName  = NULL;
  wcex->lpszClassName = windowClass;
}
}

template<typename Function, typename MessageTag>
void window_message_error_contract(
  Function && function,
  RootWindow::Context& ,
  MessageTag && ,
  RootWindow::tag &&)
{
  try {
    std::forward<Function>(function)();
  } catch (std::bad_alloc &&) {
  } catch (unique_winerror::exception &&) {
  } catch (unique_hresult::exception &&) {
  }
}

typedef
  l::wnd::window_class<RootWindow::tag>
    RootWindowClass;

int PASCAL
wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int nShowCmd)
{
  unique_hresult hr;

  hr.reset(CoInitialize(NULL));
  if (!hr) {
    return FALSE;
  }
  ON_UNWIND_AUTO([&] {CoUninitialize();});

  InitCommonControls();

  RootWindowClass::Register(L"Scratch");

  unique_winerror winerror;
  l::wr::unique_close_window window;

  std::tie(winerror, window) =
    l::wr::winerror_and_close_window(
        CreateWindow(
            L"Scratch", L"Scratch",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL,
            hinst,
            NULL));

  if (!winerror || !window) {
    return winerror.get();
  }

  ShowWindow(window.get(), nShowCmd);

  MSG msg = {};
  while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return 0;
}

No comments:

Post a Comment