From a45042b2f14b6b8b68244dbb3d1de3346a3af389 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Sun, 20 Sep 2020 20:34:17 +0100 Subject: [PATCH 1/1] Initial version, working demo. --- .gitignore | 3 + .vscode/settings.json | 20 +++++ ButtonProvider.cpp | 181 +++++++++++++++++++++++++++++++++++++++++ ButtonProvider.h | 30 +++++++ CMakeLists.txt | 19 +++++ PolyButton.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++ PolyButton.h | 36 +++++++++ README.md | 3 + main.cpp | 37 +++++++++ main.rc | 162 +++++++++++++++++++++++++++++++++++++ resource.h | 22 +++++ 11 files changed, 697 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 ButtonProvider.cpp create mode 100644 ButtonProvider.h create mode 100644 CMakeLists.txt create mode 100644 PolyButton.cpp create mode 100644 PolyButton.h create mode 100644 README.md create mode 100644 main.cpp create mode 100644 main.rc create mode 100644 resource.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fcc9ffb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +build/ +*.aps \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fddb5e4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "files.associations": { + "memory": "cpp" + }, + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "C_Cpp.default.defines": [ + "UNICODE", "_UNICODE", "_WIN32_LEAN_AND_MEAN", "STRICT" + ], + "cmake.configureOnOpen": true, + "C_Cpp.default.cppStandard": "c++14", + "C_Cpp.default.cStandard": "c11", + "c-cpp-flylint.defines": [ + "UNICODE", "_UNICODE", "_WIN32_LEAN_AND_MEAN", "STRICT" + ], + "c-cpp-flylint.standard": [ + "c11", + "c++14" + ], + "c-cpp-flylint.cppcheck.suppressions": [] +} \ No newline at end of file diff --git a/ButtonProvider.cpp b/ButtonProvider.cpp new file mode 100644 index 0000000..615f0a2 --- /dev/null +++ b/ButtonProvider.cpp @@ -0,0 +1,181 @@ +//#include +#include "ButtonProvider.h" +#include +#include +#include +#include + +HRESULT ButtonProvider::CreateInstance(HWND hwnd, IRawElementProviderSimple **ppProvider) +{ + ButtonProvider *provider = new (std::nothrow) ButtonProvider(hwnd); + wchar_t wsz[128]; swprintf_s(wsz, L"Created %p\n", provider); OutputDebugStringW(wsz); + return provider->QueryInterface(IID_IRawElementProviderSimple, reinterpret_cast(ppProvider)); +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::QueryInterface(REFIID riid, void **ppv) +{ + HRESULT hr = S_OK; + *ppv = nullptr; + if (IsEqualIID(riid, IID_IUnknown) + || IsEqualIID(riid, IID_IRawElementProviderSimple)) + { + *ppv = static_cast(this); + this->AddRef(); + } + else if (IsEqualIID(riid, IID_IInvokeProvider)) + { + *ppv = static_cast(this); + this->AddRef(); + } + else if (IsEqualIID(riid, IID_IToggleProvider)) + { + *ppv = static_cast(this); + this->AddRef(); + } + else + hr = E_NOINTERFACE; + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) ButtonProvider::AddRef() +{ + ULONG result = InterlockedIncrement(&_refcount); + //wchar_t wsz[128]; swprintf_s(wsz, L"AddRef %lu\n", result); OutputDebugStringW(wsz); + return result; +} + +DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) ButtonProvider::Release() +{ + unsigned long result = InterlockedDecrement(&_refcount); + //wchar_t wsz[128]; swprintf_s(wsz, L"Release %lu\n", result); OutputDebugStringW(wsz); + if (result == 0) + { + wchar_t wsz[128]; swprintf_s(wsz, L"Destroy %p\n", this); OutputDebugStringW(wsz); + delete this; + } + return result; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::get_ProviderOptions(ProviderOptions *pVal) +{ + HRESULT hr = E_POINTER; + if (pVal) + { + if (!IsWindow(_hwnd)) + hr = UIA_E_ELEMENTNOTENABLED; + else + { + *pVal = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading; + hr = S_OK; + } + } + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::GetPatternProvider(PATTERNID patternId, IUnknown **ppVal) +{ + HRESULT hr = E_POINTER; + if (ppVal) + { + hr = S_OK; + *ppVal = nullptr; + if (patternId == UIA_InvokePatternId) + { + hr = QueryInterface(IID_IUnknown, reinterpret_cast(ppVal)); + } + else if (patternId == UIA_TogglePatternId) + { + hr = QueryInterface(IID_IUnknown, reinterpret_cast(ppVal)); + } + } + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::GetPropertyValue(PROPERTYID propertyId, VARIANT *pVal) +{ + if (propertyId == UIA_ControlTypePropertyId) + { + pVal->vt = VT_I4; + pVal->lVal = UIA_ButtonControlTypeId; + } + else if (propertyId == UIA_IsControlElementPropertyId) + { + pVal->vt = VT_BOOL; + pVal->boolVal = VARIANT_TRUE; + } + else if (propertyId == UIA_HasKeyboardFocusPropertyId) + { + pVal->vt = VT_BOOL; + pVal->boolVal = VARIANT_FALSE; + } + else if (propertyId == UIA_ClassNamePropertyId) + { + wchar_t name[32] = { 0 }; + GetClassNameW(_hwnd, name, 32); + pVal->vt = VT_BSTR; + pVal->bstrVal = SysAllocString(name); + } + else if (propertyId == UIA_NamePropertyId) + { + int len = GetWindowTextLengthW(_hwnd) + 1; + wchar_t *name = new (std::nothrow) wchar_t[len](); + GetWindowTextW(_hwnd, name, len); + pVal->vt = VT_BSTR; + pVal->bstrVal = SysAllocString(name); + delete[] name; + } + else + { + pVal->vt = VT_EMPTY; + } + return S_OK; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::get_HostRawElementProvider(IRawElementProviderSimple **ppVal) +{ + HRESULT hr = E_POINTER; + if (ppVal) + { + hr = UiaHostProviderFromHwnd(_hwnd, ppVal); + } + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::Invoke() +{ + HRESULT hr = static_cast(UIA_E_ELEMENTNOTAVAILABLE); + if (IsWindow(_hwnd)) + { + PostMessage(_hwnd, BM_CLICK, 0L, 0L); + hr = S_OK; + } + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::Toggle() +{ + HRESULT hr = static_cast(UIA_E_ELEMENTNOTAVAILABLE); + if (IsWindow(_hwnd)) + { + PostMessage(_hwnd, BM_CLICK, 0, 0); + hr = S_OK; + } + return hr; +} + +DECLSPEC_NOTHROW STDMETHODIMP ButtonProvider::get_ToggleState(ToggleState *pVal) +{ + HRESULT hr = E_POINTER; + if (pVal) + { + if (!IsWindow(_hwnd)) + hr = static_cast(UIA_E_ELEMENTNOTAVAILABLE); + else + { + auto state = SendMessage(_hwnd, BM_GETCHECK, WPARAM(0), LPARAM(0)); + *pVal = (state == BST_CHECKED) ? ToggleState_On : ToggleState_Off; + hr = S_OK; + } + } + return hr; +} \ No newline at end of file diff --git a/ButtonProvider.h b/ButtonProvider.h new file mode 100644 index 0000000..ae1d551 --- /dev/null +++ b/ButtonProvider.h @@ -0,0 +1,30 @@ +#include +#include +#include + +class ButtonProvider : public IRawElementProviderSimple, public IInvokeProvider, public IToggleProvider +{ +public: + static HRESULT CreateInstance(HWND hwnd, IRawElementProviderSimple **ppProvider); + + STDMETHOD(QueryInterface)(REFIID riid, void **ppv); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + STDMETHOD(get_ProviderOptions)(ProviderOptions *pVal); + STDMETHOD(GetPatternProvider)(PATTERNID patternId, IUnknown **ppVal); + STDMETHOD(GetPropertyValue)(PROPERTYID propertyId, VARIANT *pVal); + STDMETHOD(get_HostRawElementProvider)(IRawElementProviderSimple **ppVal); + + STDMETHOD(Invoke)(); + + STDMETHOD(Toggle)(); + STDMETHOD(get_ToggleState)(ToggleState *pVal); + +private: + ButtonProvider() : _refcount(0), _hwnd(HWND_DESKTOP) {} + ButtonProvider(HWND hwnd) : _refcount(0), _hwnd(hwnd) {} + virtual ~ButtonProvider() {} + unsigned long _refcount; + HWND _hwnd; +}; diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a2db266 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +# CMAKE_BUILD_TYPE has no effect on the Visual Studio generator. +# cmake -G"Visual Studio 15 2017 Win64" .. +# cmake --build . --config Release +# +# For LLVM / CLang build: +# cmake -G"Visual Studio 15 2017 Win64" -T LLVM .. +# cmake --build . --config Release + +cmake_minimum_required(VERSION 3.0) + +ENABLE_LANGUAGE(RC) + +project(UIADemo VERSION 1.0) +set(SOURCE main.cpp main.rc resource.h + PolyButton.cpp PolyButton.h + ButtonProvider.cpp ButtonProvider.h) +set(CMAKE_CXX_STANDARD 14) +add_definitions(-DUNICODE -D_UNICODE -DSTRICT -D_WIN32_LEAN_AND_MEAN -D_WIN32_WINNT=_WIN32_WINNT_WIN8) +add_executable(${PROJECT_NAME} WIN32 ${SOURCE}) diff --git a/PolyButton.cpp b/PolyButton.cpp new file mode 100644 index 0000000..65d6932 --- /dev/null +++ b/PolyButton.cpp @@ -0,0 +1,184 @@ +#include "PolyButton.h" +#include "ButtonProvider.h" +#include +#include +#include + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT messageId, WPARAM wparam, LPARAM lparam); + +PolyButton::PolyButton(HWND hwnd) : _hwnd(hwnd), _sides(6), _state(PolyButtonState::Normal), _provider(nullptr) +{ +} + +PolyButton::~PolyButton() +{ + if (_provider) + { + _provider->Release(); + _provider = nullptr; + } +} + +void PolyButton::RegisterControl(HINSTANCE hInstance) +{ + WNDCLASS wc = {}; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszClassName = L"POLYBUTTON"; + RegisterClass(&wc); +} + +IRawElementProviderSimple *PolyButton::GetUIAutomationProvider(HWND hwnd) +{ + if (!_provider) + { + HRESULT hr = ButtonProvider::CreateInstance(hwnd, &_provider); + } + return _provider; +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT messageId, WPARAM wparam, LPARAM lparam) +{ + switch (messageId) + { + case WM_CREATE: + { + PolyButton *ctrl = new (std::nothrow) PolyButton(hwnd); + if (!ctrl) + { + PostQuitMessage(-1); + } + SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast(ctrl)); + } + break; + case WM_DESTROY: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + UiaReturnRawElementProvider(hwnd, 0, 0, nullptr); + UiaDisconnectProvider(ctrl->GetUIAutomationProvider(hwnd)); + delete ctrl; + } + break; + case WM_GETOBJECT: + if (static_cast(lparam) == static_cast(UiaRootObjectId)) + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + IRawElementProviderSimple *provider = ctrl->GetUIAutomationProvider(hwnd); + return UiaReturnRawElementProvider(hwnd, wparam, lparam, provider); + } + break; + case WM_PAINT: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + ctrl->OnPaint(); + return 1L; + } + break; + case WM_SETFOCUS: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + ctrl->OnSetFocus(); + } + break; + case WM_KILLFOCUS: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + ctrl->OnKillFocus(); + } + break; + case WM_LBUTTONDOWN: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + ctrl->InvokeButton(); + } + break; + case BM_CLICK: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + ctrl->InvokeButton(); + } + break; + case BM_GETCHECK: + { + PolyButton *ctrl = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); + return ctrl->IsChecked() ? BST_CHECKED : BST_UNCHECKED; + } + } + return DefWindowProc(hwnd, messageId, wparam, lparam); +} + +void PolyButton::OnSetFocus() +{ + _state |= PolyButtonState::Focussed; + RECT rc = {0}; + GetClientRect(_hwnd, &rc); + InvalidateRect(_hwnd, &rc, TRUE); +} + +void PolyButton::OnKillFocus() +{ + _state &= ~PolyButtonState::Focussed; + InvalidateRect(_hwnd, nullptr, TRUE); +} + +inline Gdiplus::RectF RectItoF (const Gdiplus::Rect &rc) +{ + return Gdiplus::RectF(float(rc.X), float(rc.Y), float(rc.Width), float(rc.Height)); +} + +void PolyButton::OnPaint() +{ + PAINTSTRUCT ps = {0}; + RECT rc; + GetClientRect(_hwnd, &rc); + HDC hdc = BeginPaint(_hwnd, &ps); + { + Gdiplus::Graphics g(hdc); + Gdiplus::Rect clientRect(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); + Gdiplus::Pen pen(Gdiplus::Color::Black, 1.0F); + Gdiplus::SolidBrush redBrush(Gdiplus::Color::Red); + Gdiplus::SolidBrush greenBrush(Gdiplus::Color::Green); + Gdiplus::Brush *brush = IsChecked() ? &redBrush : &greenBrush; + g.FillRectangle(brush, clientRect); + g.DrawRectangle(&pen, clientRect); + + Gdiplus::SolidBrush textBrush(Gdiplus::Color::Black); + Gdiplus::Font font(L"Segoe UI", 10); + Gdiplus::RectF layoutRect(float(clientRect.X), float(clientRect.Y), float(clientRect.Width), float(clientRect.Height)); + Gdiplus::StringFormat format(Gdiplus::StringFormat::GenericDefault()); + format.SetAlignment(Gdiplus::StringAlignmentCenter); + format.SetLineAlignment(Gdiplus::StringAlignmentCenter); + int len = GetWindowTextLength(_hwnd) + 1; + wchar_t *label = new wchar_t[len](); + GetWindowTextW(_hwnd, label, len); + g.DrawString(label, len, &font, layoutRect, &format, &textBrush); + delete [] label; + } + if ((_state & PolyButtonState::Focussed) == PolyButtonState::Focussed) + DrawFocusRect(hdc, &rc); + EndPaint(_hwnd, &ps); +} + +void PolyButton::InvokeButton() +{ + if ((_state & PolyButtonState::Disabled) != PolyButtonState::Disabled) + { + if ((_state & PolyButtonState::Focussed) != PolyButtonState::Focussed) + SetFocus(_hwnd); + _state ^= PolyButtonState::Checked; + if (UiaClientsAreListening()) + { + // Raise an event. + IRawElementProviderSimple *p = nullptr; + if (_provider) + { + _provider->QueryInterface(&p); + UiaRaiseAutomationEvent(p, UIA_Invoke_InvokedEventId); + p->Release(); + } + } + InvalidateRect(_hwnd, nullptr, TRUE); + } +} \ No newline at end of file diff --git a/PolyButton.h b/PolyButton.h new file mode 100644 index 0000000..b262484 --- /dev/null +++ b/PolyButton.h @@ -0,0 +1,36 @@ +// Provide a polygonal button control. +// Used to demo UIAutomation support for custom controls. + +#include +#include +#include + +enum class PolyButtonState { + Normal = 0, + Active = (1 << 0), + Pressed = (1 << 1), + Focussed = (1 << 2), + Checked = (1 << 3), + Disabled = (1 << 4) +}; +DEFINE_ENUM_FLAG_OPERATORS(PolyButtonState); + +class PolyButton +{ +public: + explicit PolyButton(HWND hwnd); + virtual ~PolyButton(); + IRawElementProviderSimple *GetUIAutomationProvider(HWND hwnd); + void InvokeButton(); + static void RegisterControl(HINSTANCE instance); + bool IsChecked() const { return ((_state & PolyButtonState::Checked) == PolyButtonState::Checked); } + void OnPaint(); + void OnSetFocus(); + void OnKillFocus(); +private: + PolyButton() {} + HWND _hwnd; + PolyButtonState _state; + int _sides; + IRawElementProviderSimple * _provider; +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..eede211 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Demonstration of UI Accessibility for Custom Control + +PolyButton is a custom toggle button with UIA support. \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6f09f76 --- /dev/null +++ b/main.cpp @@ -0,0 +1,37 @@ +#include +#include +#include "resource.h" +#include "PolyButton.h" + +#pragma comment(lib, "gdiplus") +#pragma comment(lib, "uiautomationcore") +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) +{ + switch (message) + { + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; +} + +int PASCAL +WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int) +{ + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken(0); + Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + PolyButton::RegisterControl(hinst); + DialogBox(hinst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc); + CoUninitialize(); + Gdiplus::GdiplusShutdown(gdiplusToken); + return 0; +} diff --git a/main.rc b/main.rc new file mode 100644 index 0000000..595a68a --- /dev/null +++ b/main.rc @@ -0,0 +1,162 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Direct2D sample application" + VALUE "CompanyName", "Renishaw plc." + VALUE "FileDescription", "Direct2D sample application" + VALUE "FileVersion", "1, 0, 0, 0" + VALUE "InternalName", "D2DDemo" + VALUE "LegalCopyright", "Copyright (c) 2020 Renishaw plc." + VALUE "OriginalFilename", "D2DDemo.exe" + VALUE "ProductVersion", "1, 0, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include \r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 309, 176 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "UIA Custom Control Demo" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,112,10 + GROUPBOX "Static",IDC_STATIC,7,18,105,38 + CONTROL "Option 1",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,15,28,91,10 + CONTROL "Option 2",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,15,42,92,10 + LTEXT "Label",IDC_STATIC,7,62,18,8 + EDITTEXT IDC_EDIT1,33,59,100,14,ES_AUTOHSCROLL + CONTROL "Hello",IDC_CUSTOM1,"POLYBUTTON",WS_TABSTOP,15,82,60,27 + DEFPUSHBUTTON "OK",IDOK,198,155,50,14 + PUSHBUTTON "Cancel",IDCANCEL,252,155,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 302 + TOPMARGIN, 7 + BOTTOMMARGIN, 169 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_DIALOG1 AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..c312e64 --- /dev/null +++ b/resource.h @@ -0,0 +1,22 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by main.rc +// + +#define IDD_DIALOG1 101 +#define IDC_CHECK1 102 +#define IDC_RADIO1 103 +#define IDC_RADIO2 104 +#define IDC_EDIT1 105 +#define IDC_CUSTOM1 106 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1005 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif -- 2.23.0