Related
I saw an article on the Microsoft website MSDN that introduced an advanced way of writing.
I apply it to the extension of the class, and usually I don't have a problem.
But recently I encountered a problem when I tried to write a class.
I want to implement a listview class to provide us some convenience when we manipulate the listview control.
template <class DERIVED_TYPE>
class BaseWindow
{
public:
LPCTSTR className = "myWindows";
LPCTSTR Caption = "myWindows";
DWORD Style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
UINT classStyle = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
DWORD ExStyle = 0;
...
other_property
...
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
DERIVED_TYPE *pThis = NULL;
if (uMsg == WM_NCCREATE)
{
CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
if (pThis)pThis->m_hwnd = hwnd;
}else{
pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(pThis)pThis->m_hwnd = hwnd;
}
if (pThis)
{
return pThis->HandleMessage(hwnd, uMsg, wParam, lParam);
}else{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
ATOM RegClass()
{
WNDCLASS wc = { 0 };
wc.lpfnWndProc = BaseWindow::WindowProc;
wc.hInstance = hInst;
wc.lpszClassName = className;
wc.style = classStyle;
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
return RegisterClass(&wc);
}
BOOL CreateWinEx( LPCTSTR className_,LPCTSTR Caption_,
DWORD Style_,DWORD ExStyle_,
int x_,int y_,int w_,int h_,
HWND hWndParent_,HMENU hMenu_,HINSTANCE hInst_)
{
m_hwnd = CreateWindowEx(
ExStyle_, className_, Caption_, Style_,
x_, y_, w_, h_,
hWndParent_, hMenu_, hInst_, this
);
return (m_hwnd ? TRUE : FALSE);
}
BOOL Create()
{
ATOM rst = RegClass();
if(rst == 0) return FALSE;
m_hwnd = CreateWindowEx(
ExStyle, className, Caption, Style,
x, y, w, h,
hWndParent, hMenu, hInst, this
);
return (m_hwnd ? TRUE : FALSE);
}
}
Based on the above, I have derived two classes, one as the main form and the other as the listview class that I am going to design.
class FirstWindow : public BaseWindow<FirstWindow>
{
public:
FirstWindow(){};
...
some_property
...
LRESULT HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
};
class listView : public BaseWindow<listView>
{
public:
listView();
int init(LPCTSTR className_,HWND hWndParent_,int x,int y,int w,int h)
{
this->className = className_;
this->hWndParent = hWndParent_;
this->Style = WS_CHILD| WS_VISIBLE | ~WS_CAPTION;
this->x = x;
this->y = y;
this->w = w;
this->h = h;
this->Create();
hWndMsgWindow = m_hwnd;
CreateListView(hWndMsgWindow);
ShowWindow(hWndMsgWindow,SW_SHOW);
ShowWindow(hWndListView,SW_SHOW);
UpdateWindow(hWndMsgWindow);
UpdateWindow(hWndListView);
idebug("listview::init >> hWndMsgWindow:%d,parent:%d, error:%d\n",hWndMsgWindow,GetParent(hWndMsgWindow), GetLastError());
idebug("listview::init >> hWndListView:%d,parent:%d,error:%d\n",hWndListView,GetParent(hWndListView), GetLastError());
return 1;
}
LRESULT HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT listView::CreateListView(HWND hwndParent_)
{
InitCommonControls();
bool rst = CreateWinEx(WC_LISTVIEW, NULL,
WS_CHILD | WS_VISIBLE | LVS_REPORT |LVS_EDITLABELS | LVS_NOCOLUMNHEADER | LVS_OWNERDATA |LVS_OWNERDRAWFIXED | WS_BORDER,0,
x,y,w,h,
hwndParent_, NULL, GetModuleHandle(NULL));
if(rst)
hWndListView = m_hwnd;
idebug("CreateListView >> rst:%d,hwndlistview:%d,parent:%d,hwndParent_:%d, error:%d\n",rst,hWndListView,GetParent(hWndListView),hwndParent_, GetLastError());
return rst;
}
LRESULT AddItem();
LRESULT OnListViewNotify(HWND hwnd, LPARAM lParam);
void OwnerDraw(LPDRAWITEMSTRUCT lpdis, HDC hdc, HWND hWnd, const TCHAR* szDraw);
void on_drawItem(HWND hWnd, LPARAM lParwm);
void on_notify(HWND hWnd, WPARAM wParwm, LPARAM lParam);
void on_create(HWND hWnd);
void on_measureItem(LPARAM lParam);
bool add_item();
bool add_item_sub();
...
some_property
...
};
fire FirstWindow first
FirstWindow * pFirstWnd;
listView lv;
int main(int argc, char** argv)
{
FirstWindow win;
pFirstWnd = &win;
win.className = "FirstWindow";
win.Style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
win.x = 100;
win.y = 100;
win.w = 600;
win.h = 300;
bool rst = win.Create();
if (!rst)
{
idebug("getlasterror:%d,line:201\n", GetLastError());
bug.ShowErr();
}
else {
lv.init("mylistview",pFirstWnd->m_hwnd,20,20,300,200);
ShowWindow(lv.m_hwnd, SW_SHOW);
}
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
The goal of the listview_class is to be able to receive and process window messages independently. not like this:
LRESULT FirstWindow::HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
//lv.init("mylistview2",pFirstWnd->m_hwnd,20,20,300,200);
//ShowWindow(lv.m_hwnd, SW_SHOW);
break;
}
case WM_NOTIFY:
{
lv.on_notify(hWnd,wParam,lParam);
break;
}
...
}
default:
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
return TRUE;
}
Instead, I want to process messages independently within listview class,like this:
LRESULT listView::HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
static HDC hdc;
HRESULT lResult;
switch (uMsg)
{
case WM_CREATE:
{
idebug("class_listview >> WM_CREATE >> hWnd :%d, className:%s, parent:%d\n",hWnd, className , GetParent(hWnd));
//HWND h = CreateWindowEx(0, WC_LISTVIEW, NULL,
WS_CHILD | WS_VISIBLE | LVS_REPORT |LVS_EDITLABELS | LVS_NOCOLUMNHEADER | LVS_OWNERDATA |LVS_OWNERDRAWFIXED | WS_BORDER,
20,20,300,200,
hWnd,NULL, GetModuleHandle(NULL),NULL);
//ShowWindow(h,SW_SHOW);
//UpdateWindow(hWnd);
//idebug("class_listview >> WM_CREATE >> hwnd:%d,parent:%d,error:%d\n",h,GetParent(h), GetLastError());
//ShowWindow(h,SW_SHOW);
//UpdateWindow(h);
break;
}
case WM_NOTIFY:
{
on_notify(hWnd,wParam,lParam);
break;
}
case WM_MEASUREITEM:
{
on_measureItem(lParam);
break;
}
case WM_DRAWITEM:
{
on_drawItem(hWnd,lParam);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
EndPaint(hWnd, &ps);
idebug("class_listview >> WM_PAINT->hWnd:%d,id:%d,err:%d\n", hWnd, id, GetLastError());
break;
}
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
The problem now is that i can't see other control windows except that FirstWindow can display normally.
update:
some message from debug:
class_listview >> WM_CREATE >> hWnd :1443146, className:mylistview, parent:262350,error:0
listView >> WM_SIZE >> hWnd:1443146,parent:262350
CreateListView >> rst:1,hwndlistview:853318,parent:1443146,hwndParent_:1443146, error:5
listview::init >> hWndMsgWindow:1443146,parent:262350, error:5
listview::init >> hWndListView:853318,parent:1443146,error:5
the key of the problem is the return value of WM_NOTIFY message.
i typed :
case WM_NOTIFY:
{
retnrn on_notify(hWnd,wParam,lParam);
}
the problem was resolved.
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.
I've started Direct2D from a very simple example.
Acquire the factory and ID2D1HwndRenderTarget, then handle WM_PAINT message to draw just a background with a solid color using "Clear" function.
It's work fine, until I start to move the window. When the window is moving it turns gray like nothing is drawing. I've tried to draw an ellipse, and the result is the same.
How could one present the window content with the window moving?
P.S. In case the code is needed
#include <Windows.h>
#include <d2d1_1.h>
#pragma comment(lib,"d2d1")
ID2D1Factory * d2factory_ptr = NULL;
ID2D1HwndRenderTarget * renderTarget_ptr = NULL;
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(
HINSTANCE hInstance
, HINSTANCE prevInstance
, LPWSTR cmd
, int nCmdShow
) {
WNDCLASSEX wndClassStruct;
ZeroMemory(&wndClassStruct, sizeof(WNDCLASSEX));
wndClassStruct.cbSize = sizeof(WNDCLASSEX);
wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndClassStruct.style = CS_HREDRAW | CS_VREDRAW;
wndClassStruct.hInstance = hInstance;
wndClassStruct.lpfnWndProc = mainWinProc;
wndClassStruct.lpszClassName = TEXT("MainWnd");
RegisterClassEx(&wndClassStruct);
RECT windowRect = { 0,0,640,480};
AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, 0, WS_EX_APPWINDOW);
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, TEXT("MainWnd"), TEXT("Direct 2D Test Window"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, NULL, NULL, hInstance, 0);
{
D2D1_FACTORY_OPTIONS fo;
ZeroMemory(&fo, sizeof(D2D1_FACTORY_OPTIONS));
IID const factoryIID = IID_ID2D1Factory1;
HRESULT res = S_OK;
if (S_OK != (res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factoryIID, &fo, &d2factory_ptr))) {
return 0;
}
RECT clientRect;
GetClientRect(hWnd, &clientRect);
D2D1_RENDER_TARGET_PROPERTIES renderTargetProps;
ZeroMemory(&renderTargetProps, sizeof(D2D1_RENDER_TARGET_PROPERTIES));
renderTargetProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
renderTargetProps.pixelFormat = (D2D1_PIXEL_FORMAT) { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED };
renderTargetProps.dpiX = 0;
renderTargetProps.dpiY = 0;
renderTargetProps.usage = D2D1_RENDER_TARGET_USAGE_FORCE_BITMAP_REMOTING;
renderTargetProps.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
D2D1_HWND_RENDER_TARGET_PROPERTIES hwndRenderProps;
ZeroMemory(&hwndRenderProps, sizeof(D2D1_HWND_RENDER_TARGET_PROPERTIES));
hwndRenderProps.hwnd = hWnd;
hwndRenderProps.pixelSize = (D2D1_SIZE_U) { clientRect.right - clientRect.left, clientRect.bottom - clientRect.top };
hwndRenderProps.presentOptions = D2D1_PRESENT_OPTIONS_NONE;
if (S_OK != (res = d2factory_ptr->lpVtbl->CreateHwndRenderTarget(d2factory_ptr, &renderTargetProps, &hwndRenderProps, &renderTarget_ptr))) {
return 0;
}
}
ShowWindow(hWnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(hWnd);
if(NULL != renderTarget_ptr)
renderTarget_ptr->lpVtbl->Base.Base.Base.Release((IUnknown*)renderTarget_ptr);
if (NULL != d2factory_ptr)
d2factory_ptr->lpVtbl->Base.Release((IUnknown*)d2factory_ptr);
return 0;
}
LRESULT onPaintMainWindow() {
ID2D1RenderTargetVtbl renderTargetFuncs = renderTarget_ptr->lpVtbl->Base;
ID2D1RenderTarget * This = (ID2D1RenderTarget*)renderTarget_ptr;
D2D1_TAG tag1, tag2;
D2D1_COLOR_F backgroundClr = (D2D1_COLOR_F) { 0.0, 0.5, 1.0, 1.0 };
renderTargetFuncs.BeginDraw(This);
renderTargetFuncs.Clear(This, &backgroundClr);
renderTargetFuncs.EndDraw(This, &tag1, &tag2);
return 0;
}
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_PAINT == uMsg)
return onPaintMainWindow();
if (WM_DESTROY == uMsg) {
PostQuitMessage(0); return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Configure your WNDCLASSEX to not have a background brush.
Replace this line:
wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;
With this:
wndClassStruct.hbrBackground = GetStockObject(NULL_BRUSH);
Alternatively, you can modify mainWndProc to swallow the WM_ERASEBKGND messages. It achieves the same effect by not allowing the window to erase itself before issuing a WM_PAINT.
LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_PAINT == uMsg)
return onPaintMainWindow();
if (uMsg == WM_ERASEBKGND)
{
// ignore requests to erase the background since the wm_paint
// handler is going to redraw the entire window.
return 0;
}
if (WM_DESTROY == uMsg) {
PostQuitMessage(0); return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
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;
}
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);