I'm trying to get an openfile dialog to show up on windows CE 6.0 according to msdn it's the same process as in win32, but it doesn't work. I submit for review the interresting part of the code :
#include <windows.h>
#include <commctrl.h>
#include <winuser.h>
#include <stdio.h>
#include <Commdlg.h>
/* Prototypes */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND create_window(int width, int height) ;
void resize_window(int width, int height) ;
HWND g_hWindow ;
/* Function to modify the host window size to match the size of the movie. */
void resize_window(int width, int height)
{
RECT r;
r.left = r.top = 0;
r.right = width ;
r.bottom = height ;
AdjustWindowRectEx(&r,WS_BORDER,false,WS_EX_CLIENTEDGE);
SetWindowPos(g_hWindow, NULL, 0,0,r.right, r.bottom,SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
}
HWND create_window(int width, int height)
{
WNDCLASS wce; // A Window class in Windows CE
wce.style = CS_VREDRAW | CS_HREDRAW;
wce.lpfnWndProc = (WNDPROC) WndProc;
wce.cbClsExtra = 0;
wce.cbWndExtra = 0;
wce.hInstance = GetModuleHandle(NULL);
wce.hIcon = LoadIcon((HINSTANCE) NULL, (LPCWSTR)MB_ICONQUESTION);
wce.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW);
wce.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wce.lpszMenuName = 0;
wce.lpszClassName = _TEXT("TEST");
if (!RegisterClass(&wce)) return 0;
RECT r;
r.left = r.top = 0;
r.right = width ;
r.bottom = height ;
AdjustWindowRectEx(&r,WS_BORDER,false,WS_EX_CLIENTEDGE);
// Create the window
g_hWindow = CreateWindowEx(
0, // Ex Styles
WS_BORDER, // creates a window that has a thin-line border with no title bar
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
r.right-r.left, // Height
r.bottom-r.top, // Width
NULL, // Parent Window
NULL, // Menu, or windows id if child
GetModuleHandle(NULL), //
NULL // Pointer to window specific data
);
ShowWindow( g_hWindow, SW_SHOW ); // make the window visible on the display
return g_hWindow ;
}
/*
* Messaging function call back from Windows CE that is passed as
* an argument when the window is created
*/
LRESULT CALLBACK WndProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch( msg )
{
case WM_ACTIVATEAPP:
// Invalidate to get new text painted.
this->Invalidate();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
LPOPENFILENAME opendialog;
wchar_t szFile[260];
opendialog = (LPOPENFILENAME) malloc(sizeof (LPOPENFILENAME));
opendialog->lStructSize = sizeof (LPOPENFILENAME);
opendialog->hwndOwner = g_hWindow;
opendialog->hInstance = GetModuleHandle(NULL);
*szFile = (char_t)_TEXT("\0");
opendialog->lpstrFile = szFile;
opendialog->nFilterIndex = 0;
opendialog->nMaxFile = 256;
opendialog->lpstrInitialDir = NULL;
opendialog->Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
GetOpenFileName(opendialog);
default:
return DefWindowProc( hWnd, msg, wParam, lParam);
}
return 0;
}
/* Function to hide (or make visible) the taskbar so that the player has the full display */
void set_display(bool set_full)
{
HWND hwndTaskbar = ::FindWindow(L"HHTaskBar", NULL);
if (set_full)
{
::ShowWindow(hwndTaskbar, SW_HIDE);
}
else
{
::ShowWindow(hwndTaskbar, SW_SHOW);
}
g_full_scrn = set_full;
}
int _cdecl WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR argv, int argc )
{
memset(&g_gfx_context,0,sizeof(g_gfx_context));
create_window(1, 1); // This is a windows CE specific call.
}
LPOPENFILENAME opendialog;
mb_char_t szFile[260];
opendialog = (LPOPENFILENAME) mb_malloc(sizeof (LPOPENFILENAME));
opendialog->lStructSize = sizeof (LPOPENFILENAME);
You are declaring a pointer to an OPENFILENAME structure here, and allocating memory for it.
You should be able to allocate OPENFILENAME on stack directly, like so:
OPENFILENAME opendialog = {0};
mb_char_t szFile[260] = {0};
opendialog.lStructSize = sizeof (opendialog);
opendialog.hwndOwner = g_hWindow;
opendialog.hInstance = GetModuleHandle(NULL);
opendialog.lpstrFile = szFile;
opendialog.nFilterIndex = 0;
opendialog.nMaxFile = 256;
opendialog.lpstrInitialDir = NULL;
opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
GetOpenFileName(&opendialog);
Here's a problem:
opendialog->lStructSize = sizeof (LPOPENFILENAME);
That will set the struct size to the size of a pointer, which is 4 in your case. You should have:
opendialog->lStructSize = sizeof (OPENFILENAME);
Related
I'm using GetTextExtentPoint32() to measure the text size and calculate the width and height of my combobox. However, it seems to be adding margin proportional to the amount of text, that I'd to get rid of. It seems the larger the string is, the larger margin I get on right. How do I it doesn't add this margin? a small one is acceptable but look at the second image, the big empty space on right.
With small strings, I find this margin acceptable:
However, with big ones, I get this big white space on right side, that I'd to get rid of:
I'm measuring the text size like this:
int len = wcslen(s);
HDC dc = GetDC(hwndCombo);
SIZE sz;
assert(GetTextExtentPoint32(dc, s, len, &sz));
ReleaseDC(hwndCombo, dc);
int weight = sz.cx + 10;
int height = sz.cy;
assert(SetWindowPos(hwndCombo, HWND_TOP, 0, 0, weight, height, SWP_NOMOVE));
full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "Comdlg32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <winuser.h>
#include <assert.h>
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int largestIndex();
HFONT getDefaultFont();
void SetDefaultFont(HWND hwnd);
HFONT hDefaultSystemFont;
HINSTANCE g_hinst;
const wchar_t *items[] =
{
L"Windows", L"Mac",
L"FreeBSD", L"Arch",
L"aaaaaa!!!!!!!aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa#",
L"foo",
L"baaaa"
};
HWND hwndCombo;
enum
{
ID_COMBO = 10,
ID_BTN1,
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow) {
HWND hwnd;
MSG msg ;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Application";
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0,IDC_ARROW);
g_hinst = hInstance;
RegisterClassW(&wc);
hwnd = CreateWindowW(wc.lpszClassName, L"",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 300, 170, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) {
switch(msg)
{
case WM_CREATE:
{
hwndCombo = CreateWindowW(L"Combobox", NULL,
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
10, 10, 60, 110, hwnd, (HMENU) ID_COMBO, g_hinst, NULL);
for (int i = 0; i < COUNTOF(items); i++ )
{
SendMessageW(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
}
SetDefaultFont(hwndCombo);
HWND btn1 =
CreateWindowW(L"Button", L"Click me",
WS_CHILD | WS_VISIBLE,
5, 40, 90, 25, hwnd, (HMENU) ID_BTN1, g_hinst, NULL);
SetDefaultFont(btn1);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case ID_BTN1:
{
int i = largestIndex();
wchar_t *s = (wchar_t*) items[i];
int len = wcslen(s);
HDC dc = GetDC(hwndCombo);
SIZE sz;
assert(GetTextExtentPoint32(dc, s, len, &sz));
ReleaseDC(hwndCombo, dc);
int weight = sz.cx + 10;
int height = sz.cy;
assert(SetWindowPos(hwndCombo, HWND_TOP, 0, 0, weight, height, SWP_NOMOVE));
}
break;
default:
break;
}
}
break;
case WM_DESTROY:
DeleteObject(hDefaultSystemFont);
hDefaultSystemFont = NULL;
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
int largestIndex()
{
int m = 0;
int idx = -1;
for(int i = 0; i < COUNTOF(items); i++) {
int l = wcslen(items[i]);
if(l > m) {
m = l;
idx = i;
}
}
return idx;
}
HFONT getDefaultFont()
{
if(hDefaultSystemFont == NULL) {
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
hDefaultSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
}
return hDefaultSystemFont;
}
void SetDefaultFont(HWND hwnd)
{
SendMessage(hwnd, WM_SETFONT, (LPARAM) getDefaultFont(), TRUE);
}
You are using different font for measurements.
Try
int len = wcslen(s);
HDC dc = GetDC(hwndCombo);
SIZE sz;
// Set correct font
HFONT old = SelectObject(dc,hDefaultSystemFont);
// or
// HFONT control_font = (HFONT)SendMessage(hwndCombo, WM_GETFONT, 0, 0);
// HFONT old = SelectObject(dc,control_font);
assert(GetTextExtentPoint32(dc, s, len, &sz));
// Restore font for cleanup
SelectObject(dc,old);
ReleaseDC(hwndCombo, dc);
int weight = sz.cx + 10;
int height = sz.cy;
https://learn.microsoft.com/ko-kr/windows/win32/direct2d/direct2d-quickstart-with-device-context
By following above, I typed the Direct2D base code which draw a rectangle. But It didn't draw anything. What is the reason?
It is the result after making a empty project and setting sub system to WINDOW in project properties.
#pragma comment(lib, "D2D1.lib")
#pragma comment(lib, "D3D11.lib")
#pragma comment(lib, "DXGI.lib")
#pragma comment(lib, "dxguid.lib")
#include <windows.h>
#include <d2d1.h>
#include <d2d1helper.h>
#include <d2d1_1.h>
#include <d3d11.h>
#include <dxgi.h>
#include <dxgi1_2.h>
#include <wrl.h>
#include <wincodec.h>
using namespace D2D1;
using namespace Microsoft::WRL;
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("DeviceContext Test");
int m_dpi = 96;
ComPtr<ID2D1Factory1> m_d2dFactory;
D3D_FEATURE_LEVEL m_featureLevel;
ComPtr<ID2D1Device> m_d2dDevice;
ComPtr<ID2D1DeviceContext> m_d2dContext;
ComPtr<IDXGISwapChain1> m_swapChain;
ComPtr<ID2D1Bitmap1> m_d2dTargetBitmap;
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
ComPtr<IDXGIDevice1> dxgiDevice;
ComPtr<IDXGIAdapter> dxgiAdapter;
ComPtr<IDXGIFactory2> dxgiFactory;
ComPtr<ID3D11Texture2D> backBuffer;
ComPtr<IDXGISurface> dxgiBackBuffer;
void onInit();
void onPaint();
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
, LPSTR lpszCmdParam, int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc;
WndClass.lpszClassName = lpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
//CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1400, 500, 500, 500,
NULL, (HMENU)NULL, hInstance, NULL);
hWndMain = hWnd;
ShowWindow(hWnd, nCmdShow);
while (GetMessage(&Message, NULL, 0, 0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (iMessage) {
case WM_CREATE:
hWndMain = hWnd;
onInit();
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
onPaint();
InvalidateRect(hWnd, 0, 0);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
void onPaint()
{
HRESULT res;
m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
auto size = m_d2dTargetBitmap->GetSize();
ComPtr<ID2D1SolidColorBrush> pBlackBrush;
res = m_d2dContext->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
);
m_d2dContext->BeginDraw();
D2D1_RECT_F rc;
rc.left = rc.top = 100;
rc.right = rc.bottom = 200;
m_d2dContext->DrawRectangle(rc, pBlackBrush.Get());
res = m_d2dContext->EndDraw();
RECT rect = { 0, 0, 400, 400 };
DXGI_PRESENT_PARAMETERS parameters;
parameters.DirtyRectsCount = 1;
parameters.pDirtyRects = ▭
parameters.pScrollOffset = 0;
parameters.pScrollRect = 0;
res = m_swapChain->Present1(1, 0, ¶meters);
}
void onInit()
{
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_ERROR;
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), &options, &m_d2dFactory);
// This flag adds support for surfaces with a different color channel ordering than the API default.
// You need it for compatibility with Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
// This array defines the set of DirectX hardware feature levels this app supports.
// The ordering is important and you should preserve it.
// Don't forget to declare your app's minimum required feature level in its
// description. All apps are assumed to support 9.1 unless otherwise stated.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
// Create the DX11 API device object, and get a corresponding context.
D3D11CreateDevice(
nullptr, // specify null to use the default adapter
D3D_DRIVER_TYPE_HARDWARE,
0,
creationFlags, // optionally set debug and Direct2D compatibility flags
featureLevels, // list of feature levels this app can support
ARRAYSIZE(featureLevels), // number of possible feature levels
D3D11_SDK_VERSION,
&device, // returns the Direct3D device created
&m_featureLevel, // returns feature level of device created
&context // returns the device immediate context
);
// Obtain the underlying DXGI device of the Direct3D11 device.
device.As(&dxgiDevice);
// Obtain the Direct2D device for 2-D rendering.
m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice);
// Get Direct2D device's corresponding device context object.
m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_d2dContext
);
// Allocate a descriptor.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = 0; // use automatic sizing
swapChainDesc.Height = 0;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // use double buffering to enable flip
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect
swapChainDesc.Flags = 0;
// Identify the physical adapter (GPU or card) this device is runs on.
dxgiDevice->GetAdapter(&dxgiAdapter);
// Get the factory object that created the DXGI device.
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
// Get the final swap chain for this window from the DXGI factory.
dxgiFactory->CreateSwapChainForHwnd(
device.Get(),
hWndMain,
&swapChainDesc,
nullptr, // allow on all displays
nullptr,
&m_swapChain
);
// Ensure that DXGI doesn't queue more than one frame at a time.
dxgiDevice->SetMaximumFrameLatency(1);
// Get the backbuffer for this window which is be the final 3D render target.
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
// Now we set up the Direct2D render target bitmap linked to the swapchain.
// Whenever we render to this bitmap, it is directly rendered to the
// swap chain associated with the window.
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
m_dpi,
m_dpi
);
// Direct2D needs the dxgi version of the backbuffer surface pointer.
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer));
// Get a D2D surface from the DXGI back buffer to use as the D2D render target.
m_d2dContext->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&m_d2dTargetBitmap
);
}
I can't understand why I got a loop on BeginPaint function. I have already read posts about this kind of loop but almost all of them recommend: "Don't forget to use BeginPaint function on WM_PAINT message, because it entails subsequent WM_PAINT messages otherwise". This isn't my case. May you give me some advices?
This is my windowclass ("CWindow"):
class CWindow {
public:
CWindow();
virtual ~CWindow();
bool RegisterClass(HINSTANCE hInstance);
bool CreateWnd(HINSTANCE hInstance);
bool Show(int nShow);
private:
HWND handleWindow;
ATOM atom;
bool isRegistered;
bool isCreated;
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void OnPaint();
void OnDestroy();
};
WndProc function.
LRESULT CALLBACK CWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CWindow* windowPtr = reinterpret_cast<CWindow*> ( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
PAINTSTRUCT ps;
HDC hdc;
switch( msg ) {
case WM_PAINT:
// There is a loop right here!
hdc = BeginPaint( windowPtr->handleWindow, &ps );
// The code below doesn't executed!
RECT rect;
(void)GetClientRect(windowPtr->handleWindow, &rect);
(void)DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint( windowPtr->handleWindow, &ps );
break;
case WM_DESTROY:
windowPtr->OnDestroy();
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
RegisterClass
bool CWindow::RegisterClass(HINSTANCE hInstance)
{
const TCHAR app_name[] = TEXT("HelloWin");
WNDCLASSEX windowClass;
ZeroMemory( &windowClass, sizeof(windowClass) );
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = 0;
windowClass.hIcon = 0;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = app_name;
windowClass.hIconSm = NULL;
atom = RegisterClassEx( &windowClass );
DWORD errorCode = GetLastError();
if( errorCode ) {
isRegistered = 0;
std::wcout << L"ErrorCode: " << errorCode << std::endl;
} else {
isRegistered = 1;
}
return isRegistered;
}
CreateWindow
bool CWindow::CreateWnd(HINSTANCE hInstance)
{
handleWindow = CreateWindow((PCTSTR)atom, // window class name or atom
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
DWORD errorCode = GetLastError();
if( !handleWindow ) {
isCreated = 0;
} else {
isCreated = 1;
}
return isCreated;
}
Show
bool CWindow::Show(int nShow)
{
if( isCreated ) {
ShowWindow( handleWindow, nShow );
return UpdateWindow( handleWindow );
} else {
return 0;
}
}
WinMain
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevINstance, LPSTR lpCmdLine, int nShow )
{
CWindow window;
window.RegisterClass( hInstance );
window.CreateWnd( hInstance );
window.Show( nShow );
int response = 0;
MSG msg;
while( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
Since you never call SetWindowLongPtr,
CWindow* windowPtr = reinterpret_cast<CWindow*>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
returns a nullptr, that you subsequently try to dereference:
BeginPaint( windowPtr->handleWindow, &ps )
That will trigger an access violation exception, causing the BeginPaint call to never even get executed, leaving the invalid region as is. As a consequence, the system keeps generating WM_PAINT messages. That's the same issue as not calling BeginPaint altogether.1
To solve this, you'll either have to attach the window handle to the window instance by calling SetWindowLongPtr, or simply use the hWnd parameter that's passed into your CWindow::WindowProc.
1 Note that the system silently handles unhandled exceptions in your WindowProc on 64-bit versions of Windows under certain conditions.
Here is my code. I'm trying to create an edit control. It's not showing, however. Can some take a look at my code and point out the errors please. I can't figure out where the error is. I feel It might have something to do with the parent child relationship.
#include <cstdlib>
#include <windows.h>
#define MAINWINDOW_CLASS_ID 140;
const char* MAINWINDOW_CLASS_NAME = "Main Window";
const char* TEXTAREA_CLASS_NAME = "EDIT";
using namespace std;
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
/*
* Initialize the window class and register it.
*/
BOOL initInstance(HINSTANCE hInstance);
/*
* Create and show the window
*/
HWND initWindow(HINSTANCE hInstance);
HWND createTextArea(HWND hParent);
/*
*
*/
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, LPSTR lpCmdline, INT cmdlShow)
{
if (!initInstance(hInstance))
return 0;
HWND hwndMain = initWindow(hInstance);
ShowWindow(hwndMain, cmdlShow);
MSG msg = {} ;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL initInstance(HINSTANCE hInstance)
{
WNDCLASS wc = {};
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance,
wc.lpszClassName = MAINWINDOW_CLASS_NAME;
return RegisterClass(&wc);
}
HWND initWindow(HINSTANCE hInstance)
{
HWND hwndMain = CreateWindow(
MAINWINDOW_CLASS_NAME, // The class name
"Text Editor", // The window name
WS_OVERLAPPEDWINDOW,// The window style
CW_USEDEFAULT, // The x pos
CW_USEDEFAULT, // The y pos
CW_USEDEFAULT, // The width
CW_USEDEFAULT, // The height
(HWND) NULL, // Handle to parent
(HMENU) NULL, // Handle to the menu
hInstance, // Handle to the instance
NULL // Window creation data
);
if (!hwndMain) {
return NULL;
}
else {
return hwndMain;
}
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam) {
HWND htextArea;
char sztestText[] = "I should be able to see this text.";
switch (uMsg) {
case WM_CREATE:
htextArea = createTextArea(hwnd);
SendMessage(htextArea, WM_SETTEXT, 0, (LPARAM) sztestText);
break;
case WM_PAINT:
break;
case WM_CLOSE:
break;
case WM_SIZE:
RECT rectMainWindow;
GetWindowRect(hwnd, &rectMainWindow);
INT x = rectMainWindow.right - rectMainWindow.left + 50;
INT y = rectMainWindow.bottom - rectMainWindow.top + 50;
MoveWindow(htextArea, 0, 0, x, y, TRUE);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
/*******************************************************************/
HWND createTextArea(HWND hParent) {
return CreateWindow(
TEXTAREA_CLASS_NAME, // Class control name
NULL, // Title
WS_CHILD | WS_VISIBLE | ES_MULTILINE, // Styles
0, 0, 0, 0, // Sizing and position
hParent,
(HMENU) MAKEINTRESOURCE(100),
(HINSTANCE) GetWindowLong(hParent, GWL_HINSTANCE),
NULL
);
}
You've defined htextArea as a local variable in WinProc and so every time your window procedure is called its value will be uninitialized. You should make it static or move it to global data outside the function.
(The actual problem is that when you get a WM_SIZE message, you've lost the handle to the edit control, and so its size remains as 0,0).
I found that Microsoft Application Verifier is changing behavior in an unexpected way. I have a program that performs superclassing on system EDIT control. When I run it under Application Verifier with Basics/Heaps/UseLFHGuardPages=TRUE (because I'm on Windows 7 which uses Low Frag Heap), the EDIT WindowProc returns 0 (FALSE) on WM_NCCREATE, preventing the control from being created. This breaks the entire application, as it cannot go forward.
This is a minimalist source that can be used to reproduce problem on Application Verifier:
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK DialogWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
static WNDCLASS wcEDIT;
LRESULT CALLBACK EditWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
LRESULT result = CallWindowProc(wcEDIT.lpfnWndProc, hWnd, Msg, wParam, lParam);
if (Msg == WM_NCCREATE && result == 0) {
puts("UNEXPECTED: WindowProc of EDIT returned 0 (FALSE) on WM_NCCREATE");
}
return result;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wcDialog;
memset(&wcDialog, 0, sizeof wcDialog);
wcDialog.hInstance = hInstance;
wcDialog.lpszClassName = "MyDialog";
wcDialog.lpfnWndProc = DialogWindowProc;
wcDialog.style = CS_DBLCLKS;
if (RegisterClass(&wcDialog) == 0) {
printf("Unable to register class %s\n", wcDialog.lpszClassName);
return 0;
}
HWND hForm;
{
const char *lpClassName = wcDialog.lpszClassName;
const char *lpWindowName = NULL;
DWORD dwStyle = WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_THICKFRAME|WS_SYSMENU|WS_DLGFRAME|WS_BORDER|WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
DWORD dwExStyle = 0;
int X = 0;
int Y = 0;
int nWidth = 320;
int nHeight = 240;
HWND hWndParent = 0;
HMENU hMenu = 0;
LPVOID lpParam = NULL;
hForm = CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
if (hForm == 0) {
printf("Unable to create window of class %s\n", wcDialog.lpszClassName);
return 0;
}
}
memset(&wcEDIT, 0, sizeof wcDialog);
wcEDIT.lpszClassName = "EDIT";
if (!GetClassInfo(NULL, wcEDIT.lpszClassName, &wcEDIT)) {
printf("Unable to get class info of %s\n", wcEDIT.lpszClassName);
return 0;
}
WNDCLASS wcMyEDIT;
memcpy(&wcMyEDIT, &wcEDIT, sizeof WNDCLASS);
wcMyEDIT.hInstance = hInstance;
wcMyEDIT.lpszClassName = "MyEDIT";
wcMyEDIT.lpfnWndProc = EditWindowProc;
wcMyEDIT.style |= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
if (RegisterClass(&wcMyEDIT) == 0) {
printf("Unable to register class %s\n", wcMyEDIT.lpszClassName);
return 0;
}
HWND hEdit;
{
const char *lpClassName = wcMyEDIT.lpszClassName;
const char *lpWindowName = NULL;
DWORD dwStyle = WS_CLIPSIBLINGS|WS_CHILD|ES_AUTOVSCROLL|ES_AUTOHSCROLL;
DWORD dwExStyle = WS_EX_CLIENTEDGE;
int X = 0;
int Y = 0;
int nWidth = 121;
int nHeight = 21;
HWND hWndParent = hForm;
HMENU hMenu = 0;
LPVOID lpParam = NULL;
hEdit = CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
if (hEdit == 0) {
printf("Unable to create window of class %s\n", wcMyEDIT.lpszClassName);
return 0;
}
}
puts("success");
return 0;
}