WinApi - zabawa z tworzeniem wrappera

0

Witam,
Czy jest szybszy sposób pisania wrappera do WinAPI od wypisywania po kolei WM_* ? (Chodzi o wrapper do pisania okien, kontrolek i innych takich tam customowych rzeczy w WinAPI)

	virtual void OnCreate();
	virtual void OnDestroy();
	virtual void OnMove();
	virtual void OnSize();
	virtual void OnActivate(int state);
	virtual void OnSetFocus();
	virtual void OnKillFocus();
	virtual void OnEnable();
	virtual void OnSetRedraw();
	virtual void OnSetText();
	virtual void OnGetText();
	virtual void OnGetTextLength();
	virtual void OnPaint();
	virtual void OnClose();
#ifndef _WIN32_WCE
	virtual void OnQueryEndSession();
	virtual void OnQueryOpen();
	virtual void OnEndSession();
#endif
	virtual void OnQuit();
	virtual void OnEraseBkgnd();
	virtual void OnSysColorChange();
	virtual void OnShowWindow();
	virtual void OnWinIniChange();
#if(WINVER >= 0x0400)
	virtual void OnSettingChange();
#endif
	virtual void OnDevModeChange();
	virtual void OnActivateApp();
	virtual void OnFontChange();
	virtual void OnTimeChange();
	virtual void OnCancelMode();
	virtual void OnSetCursor();
	virtual void OnMouseActivate();
	virtual void OnChildActivate();
	virtual void OnQueueSync();
	virtual void OnGetMinMaxInfo(MINMAXINFO* info);
	virtual void OnPaintIcon();
	virtual void OnIconEraseBkgnd();
	virtual void OnNextDlgCtl();
	virtual void OnSpoolerStatus();
	virtual void OnDrawItem();
	virtual void OnMeasureItem();
	virtual void OnDeleteItem();
	virtual void OnVKeyToItem();
	virtual void OnCharToItem();
	virtual void OnSetFont();
	virtual void OnGetFont();
	virtual void OnSetHotkey();
	virtual void OnGetHotkey();
	virtual void OnQueryDragIcon();
	virtual void OnCompareItem();
#if(WINVER >= 0x0500)
#ifndef _WIN32_WCE
	virtual void OnGetObject();
#endif
#endif
	virtual void OnCompacting();
	virtual void OnCommNotify();
	virtual void OnWindowPosChanging();
	virtual void OnWindowPosChanged();
	virtual void OnPower(int state);
	virtual void OnCopyData(COPYDATASTRUCT* data);
	virtual void OnCancelJournal();
#if(WINVER >= 0x0400)
	virtual void OnNotify();
	virtual void OnInputLangChangeRequest();
	virtual void OnInputLangChange();
	virtual void OnTCard();
	virtual void OnHelp();
	virtual void OnUserChanged();
	virtual void OnNotifyFormat(int state);
	virtual void OnContextMenu();
	virtual void OnStyleChanging();
	virtual void OnStyleChanged();
	virtual void OnDisplayChanged();
	virtual void OnGetIcon();
	virtual void OnSetIcon();
#endif
	virtual void OnNCCreate();
	virtual void OnNCDestroy();
	virtual void OnNCCalcSize();
	virtual void OnNCHitTest();
	virtual void OnNCPaint();
	virtual void OnNCActivate();
	virtual void OnGetDlgCode();
#ifndef _WIN32_WCE
	virtual void OnSyncPaint();
#endif
	virtual void OnNCMouseMove();
	virtual void OnNCLButtonDown();
	virtual void OnNCLButtonUp();
	virtual void OnNCLButtonDblClk();
	virtual void OnNCRButtonDown();
	virtual void OnNCRButtonUp();
	virtual void OnNCRButtonDblClk();
	virtual void OnNCMButtonDown();
	virtual void OnNCMButtonUp();
	virtual void OnNCMButtonDblClk();
#if(_WIN32_WINNT >= 0x0500)
	virtual void OnNCXButtonDown();
	virtual void OnNCXButtonUp();
	virtual void OnNCXButtonDblClk();
#endif
#if(_WIN32_WINNT >= 0x0501)
	virtual void OnInputDevice();
#endif
	virtual void OnInput();
	virtual void OnKeyFirst();
	virtual void OnKeyDown();
	virtual void OnKeyUp();
	virtual void OnChar();
	virtual void OnDeadChar();
	virtual void OnSysKeyDown();
	virtual void OnSysKeyUp();
	virtual void OnSysChar();
	virtual void OnSysDeadChar();
#if(_WIN32_WINNT >= 0x0501)
	virtual void OnUniChar();
	virtual void OnKeyLast();
	virtual void OnUnicodeNoChar();
#else
	virtual void OnKeyChar();
#endif
#if(WINVER >= 0x0400)
	virtual void OnImeStartComposition();
	virtual void OnImeEndComposition();
	virtual void OnImeComposition();
	virtual void OnImeKeyLast();
#endif
	virtual void OnInitDialog();
	virtual void OnCommand();
	virtual void OnSysCommand();
	virtual void OnTimer();
	virtual void OnHScroll();
	virtual void OnVScroll();
	virtual void OnInitMenu();
	virtual void OnInitMenuPopup();
#if(WINVER >= 0x0601)
	virtual void OnGesture();
	virtual void OnGestureNotify();
#endif
	virtual void OnMenuSelect();
	virtual void OnMenuChar();
	virtual void OnEnterIdle();
#if(WINVER >= 0x0500)
#ifndef _WIN32_WCE
	virtual void OnMenuRButtonUp();
	virtual void OnMenuDrag();
	virtual void OnMenuGetObject();
	virtual void OnUnInitMenuPopup();
	virtual void OnMenuCommand();

#ifndef _WIN32_WCE
#if(_WIN32_WINNT >= 0x0500)
	virtual void OnChangeUIState(int lState, int rState);
	virtual void OnUpdateUIState(int lState, int rState);
	virtual void OnQueryUIState(int lState, int rState);

#endif /* _WIN32_WINNT >= 0x0500 */
#endif

#endif
#endif /* WINVER >= 0x0500 */
	virtual void OnCtlColorMsgBox();
	virtual void OnCtlColorEdit();
	virtual void OnCtlColorListBox();
	virtual void OnCtlColorBtn();
	virtual void OnCtlColorDlg();
	virtual void OnCtlColorScrollBar();
	virtual void OnCtlColorStatic();
	virtual void OnMouseFirst();
	virtual void OnMouseMove();
	virtual void OnLButtonDown();
	virtual void OnLButtonUp();
	virtual void OnLButtonDblClk();
	virtual void OnRButtonDown();
	virtual void OnRButtonUp();
	virtual void OnRButtonDblClk();
	virtual void OnMButtonDown();
	virtual void OnMButtonUp();
	virtual void OnMButtonDblClk();
#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
	virtual void OnMouseWhell();
#endif
#if (_WIN32_WINNT >= 0x0500)
	virtual void OnXButtonDown();
	virtual void OnXButtonUp();
	virtual void OnXButtonDblClk();
#endif
#if (_WIN32_WINNT >= 0x0600)
	virtual void OnMouseWhell();
#endif
#if (_WIN32_WINNT >= 0x0600)
	virtual void OnMouseLast();
#elif (_WIN32_WINNT >= 0x0500)
	virtual void OnMouseLast();
#elif (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
	virtual void OnMouseLast();
#else
	virtual void OnMouseLast();
#endif
	virtual void OnParentNotify();
	virtual void OnEnterMenuLoop();
	virtual void OnExitMenuLoop();
#if(WINVER >= 0x0400)
	virtual void OnNextMenu();
	virtual void OnSizing();
	virtual void OnCaptureChanged();
	virtual void OnMoving();
	virtual void OnPowerBoardcast();
#endif
0

Ło rany, że też ci się chce to tak robić :-)

Pytanie jak u ciebie ma wyglądać procedura okna.
Czy to jest coś w rodzaju:

case WM_CREATE: OnCreate(); break;
case WM_DESTROY: OnDestroy(); break;

Taki kod może być trochę niewydajny, zwłaszcza że chcesz tam wsadzić wszystkie message'e jak leci.
Ale nie żeby to miało specjalnie znaczenie...

Trzeba by zobaczyć jak to jest zrobione w istniejących bibliotekach, zwłaszcza w MFC które jest dość cienkim wrapperem na WinAPI.
Ja nie znam szczegółów implementacji, ale na pewno nie działa to tak że jest kilkaset funkcji wirtualnych które są zawsze odpalane nawet jeśli są puste.

Ja tam nie widzę sensu robienia takiego full-wypasionego wrappera na wszystko. Ostatnio zacząłem pisać program pod WinAPI, jednocześnie powstaje minimalistyczny wrapper w którym jest tylko to co potrzebne w programie.

0

A czy dobry sens by stworzyc typedefa funkcji oraz map?

typedef long (* tyMessageHandler)(Window &, HWND, long, long);
typedef std::map<long, tyMessageHandler> tyMessageMap;
typedef tyMessageMap::iterator tyMessageIterator;

a tam gdzie procedura okna zrobic

    tyMessageIterator it;
    it = GetMessageHandler(message);
    if(it != NULL)
      return (it->second)((*wnd), hwnd, wparam, lparam);

Jak bedziee z stabilnoscia oraz jak bedzie z szybkoscia tego wrapperAa? Czy bedzie dobrze dzialac z kazdym komunikatem?

1

Nie możesz porównać iteratora do NULLa, tylko do std::end(tyMessageMap). Jeśli chodzi o szybkość, unordered_map jest szybszym kontenerem.

0

Chciabym uzyc do tego biblioteke boost... Jakich funkcji moge uzyc do tego(map, iterator, cos moze z komunikatami, pointerami - smart ptr ale do winapi?)?

1
tyMessageHandler handler = tyMessageMap[message];
if (handler != nullptr)
    handler(...);
0
tyMessageHandler CMessages::GetMessageHandler(long message)
{
	tyMessageHandler msgH = g_maps[message];

	return msgH != nullptr ? msgH : nullptr;
}

Zgrzeszylem gdzies?

0

@_0x666_ tak wiem, ze zwraca.

Teraz zostala sprawa z dodawaniem do mapy. Czytalem ze poprzez [] jest bezpieczniej niz "insert" a na dodatek operator [] sprawdza czy juz istnieje.
Wiec skoro sprawdza czy juz istnieje to jak mi pokaze ze nie moze go dodac? Poprzez exception?

g_maps[message] = handler;
2

Po prostu nadpisze obecną wartość. Insert tak samo. Polecam poczytanie dokumentacji: http://en.cppreference.com/w/cpp/container/map

1

Ten sposób może doprowadzić do prawie nieograniczonego rozrostu mapy i nie jest thread-safe.

  1. lista komunikatów nie jest prawie nieograniczona, jest dość konkretnie ograniczona a wydaje mi się, że lepiej by ten NULL dodał się sam do mapy i był wyszukiwany potem już szybko, niż żeby za każdym razem przeszukiwana była mapa...
    Trzeba by to pomierzyć co jest szybsze, a nie zakładać z góry że operator[] considered harmful :-)

  2. WndProc z tego co mi wiadomo nie musi być thread-safe.

1

lista komunikatów nie jest prawie nieograniczona, jest dość konkretnie ograniczona a wydaje mi się, że lepiej by ten NULL dodał się sam do mapy i był wyszukiwany potem już szybko, niż żeby za każdym razem przeszukiwana była mapa...
Lista komunikatów może i nie jest nieograniczona, ale może tam dostawać skądś śmieciowe wartości. W przypadku zwykłej mapy pewnie masz rację jeśli chodzi o wydajność, ale w przypadku unordered już bym się poważnie zastanowił (powiększenie jest kosztowne, a potem wyszukanie w przypadku kolizji jest droższe).

WndProc z tego co mi wiadomo nie musi być thread-safe.
Fakt, nie pomyślałem o kontekście użycia, to był raczej taki ogólny komentarz.

0

Witam ponownie. Mam pewien problem. Naprawde nie mam pojecia co jest nie tak:

AifamFramework.lib(WinAPI_Window.obj) : error LNK2001: unresolved external symbol "private: static class WinAPI_Messages * WinAPI_Window::g_waMsg" (?g_waMsg@WinAPI_Window@@0PAVWinAPI_Messages@@A)

#pragma once
class WinAPI_Window
{
private:
	static WinAPI_Messages* g_waMsg;
public:
	WinAPI_Window(HINSTANCE hInst, LPCWSTR lpClassName, int nCmdShow);
	~WinAPI_Window();
};
#include "stdafx.h"
#include "WinAPI_Messages.h"
#include "WinAPI_Window.h"

WinAPI_Window::WinAPI_Window(HINSTANCE hInst, LPCWSTR lpClassName, int nCmdShow)
{
	g_waMsg = new WinAPI_Messages();
}

Logi:

1>------ Rebuild All started: Project: A, Configuration: Debug Win32 ------
1>  stdafx.cpp
1>  main.cpp
1>  DirectX9.cpp
1>  Generating Code...
1>AifamFramework.lib(WinAPI_Window.obj) : error LNK2001: unresolved external symbol "private: static class WinAPI_Messages * WinAPI_Window::g_waMsg" (?g_waMsg@WinAPI_Window@@0PAVWinAPI_Messages@@A)
1>c:\users\theaifam5\documents\visual studio 2013\Projects\A\Debug\A.exe : fatal error LNK1120: 1 unresolved externals
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Build Summary
-------------
00:02.367 - Failed  - Debug Win32 - A\A.vcxproj

Total build time: 00:02.367

========== Rebuild All: 0 succeeded or up-to-date, 1 failed, 1 skipped, Completed at 9/4/2014 8:41:17 PM ==========

1>------ Rebuild All started: Project: AifamFramework, Configuration: Debug Win32 ------
1>  stdafx.cpp
1>  WinAPI_Window.cpp
1>  WinAPI_Messages.cpp
1>  Generating Code...
1>  AifamFramework.vcxproj -> c:\users\theaifam5\documents\visual studio 2013\Projects\A\Debug\AifamFramework.lib
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Build Summary
-------------
00:01.554 - Success - Debug Win32 - AifamFramework\AifamFramework.vcxproj

Total build time: 00:01.554

========== Rebuild All: 1 succeeded or up-to-date, 0 failed, 1 skipped, Completed at 9/4/2014 8:48:47 PM ==========
0

Musisz w pliku cpp zadeklarować:

WinAPI_Messages* WinAPI_Window::g_waMsg = 0; 

Poza tym, czemu to static?

0

Poniewaz:

LRESULT CALLBACK WinAPI_Window::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	tyMessageHandler tMsgHand = WinAPI_Window::g_waMsg->GetMessageHandler(msg);
[...]
}

A WNDPROC musi byc statyczne.

0

Masz mały błąd myśleniowy. WndProc w WinAPI_Window musi być static(tzn. nie musi, ale to inna bajka), ale dlaczego u ciebie g_waMsg to static. Bez sensu. Kompletnie nie obiektowo. Poza tym, za każdym razem jak walisz konstruktor WinAPI_Window to alokujesz na nowo g_waMsg. Ty traktujesz statica jako składową klasy, ale ty musisz to traktować jako zmienną globalną, i wprawdzie tak ją nazwałeś (g_ = global, s_ = static [Jak tak bardzo notacje chcesz stosować]).

0

To jest źle zaprojektowane.
Kiedyś jak pisałem wrapper to robiłem coś w ten deseń:

class CWindow
{
private:
    CWndRect m_Rect;

    HWND m_hWnd;

protected:
    bool m_bIsInitialized;

public:
    CWindow();
    virtual ~CWindow();

    virtual CWndRect GetRect();
    virtual void SetRect(CWndRect Rect, bool bResizeWindow);

    virtual HWND GetHwnd();
    virtual void SetHwnd(HWND hWnd);

    virtual void ShowWindow();
    virtual void HideWindow();

    virtual bool IsVisible();

    virtual bool CreateClass() = 0;

    virtual bool CreateControls() = 0;

    virtual LRESULT WindowProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

    virtual void Destroy() = 0;

    virtual bool IsInitialized();

};

I jak chcę stworzyć okno np. About to robię nową klasę dla takiego okna:

class CAboutWindow : public CWindow
{
private:
    CStatic * m_pStaticYearLicense;
    CStatic * m_pStaticCopyright;
    CStatic * m_pStaticCompilationDate;
    CStatic * m_pStaticTitle;

    CButton * m_pButtonClose;

public:
    CAboutWindow();
    ~CAboutWindow();

    bool CreateClass();

    bool CreateControls();

    LRESULT WindowProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    bool InitWindow();

    void Destroy();

    void ProcessControls(ECtrlId Id, EAction Action);

    void OnClose();

};

I w CreateClass takiej klasy walę:

LRESULT __stdcall tAboutWindowProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

bool CAboutWindow::CreateClass()
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = tAboutWindowProcess;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = CCtrl::GetSingleton()->GetModuleInstance();
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "win32_about_window";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if(!::RegisterClassEx(&wc))
        return false;

    return true;
}

LRESULT __stdcall tAboutWindowProcess(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return CCtrl::GetSingleton()->GetAboutWindow()->WindowProcess(hWnd, uMsg, wParam, lParam);
}

Oczywiście lepiej by było walić SetWindowLong z thisem, ale po prostu mi się nie chciało, ponieważ okna w moim programie były pojedyncze, każde miało swoją właściwość, i takie rozwiązanie było dla mnie w pełni dobre.
Oczywiście do tego robiłem własne klasy buttonów, staticów, editów itd. i tworzenie wyglądało powiedzmy tak:

bool CAboutWindow::CreateControls()
{
    m_pStaticYearLicense = new CStatic();
    if(!m_pStaticYearLicense)
        return false;
    m_pStaticYearLicense->Init(this, "blabla", Static, CWndRect(15, 158, 90, 13), NULL, CCtrl::GetSingleton()->GetFontById(0));
..
}

void CButton::Init(CWindow * pParentWnd, StringT & sName, ECtrlId eId, CWndRect & Dimension, DWORD dwAdditionalFlags, HFONT hFont)
{
    HWND hWnd;

    hWnd = ::CreateWindowEx(
        0,
        WC_BUTTON,
        sName.C_Str(),
        WS_VISIBLE | WS_CHILD | dwAdditionalFlags,
        0, 0,
        0, 0,
        pParentWnd->GetHwnd(),
        (HMENU)eId,
        CCtrl::GetSingleton()->GetModuleInstance(),
        NULL);
    if(!hWnd)
        return;

    SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, FALSE);

    this->SetHwnd(hWnd);

    this->SetRect(Dimension, true, true);

    this->ShowControl();
}

Oczywiście każda kontrolka dziedziczy z bazowej klasy CControl i wtedy jest dosyć przyjemnie.
Pamiętaj, że właściwie musisz do każdego okna podchodzić oddzielnie, bo tworzenie klasy(WNDCLASSEX) w WinApi nie jest domyślne tak jakby. Można tam ustalić sporo rzeczy, a walenie wszystkiego do argumentów nie jest fajne.

0

Witam mam problem. Otoz napisalem tam troche, okno sie wyswietla ale nie reaguje natomiast WndProc dziala poniewasz po umieszczeniu MessageBoxa wywala go caly czas. Aplikacja tak jakby sie zamraza.
Kod jest bardzo zlozony i korzysta z dziedziczenia oraz wirtualnych funkcji.
Kod:

LRESULT CALLBACK Utils::MsgRouter(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
		CBaseWindow *This = 0;

		if (uMsg == WM_NCCREATE){
			SetWindowLong(hWnd, GWL_USERDATA, long((LPCREATESTRUCT(lParam))->lpCreateParams));
		}

		This = (CBaseWindow *)GetWindowLong(hWnd, GWL_USERDATA);

		if (This){
			return This->WndProc(hWnd, uMsg, wParam, lParam);

		}
}

int CBaseWindow::Destroy()
{
	while (GetMessage(&GetMSG(), NULL, 0, 0))
	{
		TranslateMessage(&GetMSG());
		DispatchMessage(&GetMSG());
	}

	return (int)GetMSG().wParam;
}

bool CMainWindow::Initialize(const std::wstring& text)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = Utils::MsgRouter;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = GetInstance();
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)RGB(0, 0, 0);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = GetWindowClassName();
	wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

	if (FAILED(RegisterClassEx(&wcex)))
		return false;

	this->g_szWindowTitle = text.c_str();

	g_hWnd = CreateWindowEx(
		WS_EX_CLIENTEDGE,
		GetWindowClassName(),
		GetWindowTitle(),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT, 
		NULL,
		NULL,
		GetInstance(),
		this);

	if (!g_hWnd)
	{
		if (g_hWnd == INVALID_HANDLE_VALUE){
			MessageBox(NULL, L"CreateWindowEx failed!", L"Error", MB_OK | MB_ICONERROR);
		}

		MessageBox(NULL, L"CreateWindowEx failed!\nGetLastError" + (int)GetLastError(), L"Error", MB_OK | MB_ICONERROR);
		return false;
	}

	ShowWindow(g_hWnd, SW_NORMAL);
	UpdateWindow(g_hWnd);

	return true;
}

LRESULT CALLBACK CMainWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY: //Po umieszczeniu tutaj MessageBoxa i nacisniecia X w programie nie wywala go
                MessageBox(NULL, L"", L"", NULL);
		DestroyWindow(hWnd);
		break;
	default: //Po umieszczeniu tutaj MessageBoxa wywala tak czesto jak by go diabel opetal
		MessageBox(NULL, L"" + uMsg, L"", NULL);//Wywala dziwaczne znaki a takze i tekst
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
		break;
	}
}

HINSTANCE CBaseWindow::GetInstance()
{
	return (HINSTANCE)GetModuleHandle(NULL);
}

Czy czegos tu brakuje?

0

Wywal DestroyWindow z WM_DESTROY, bo to DestroyWindow właśnie wysyła WM_DESTROY - wpadasz w nieskończoną pętlę.

Sekwencja zamknięcia okna jest taka:
Kliknięcie X albo naciśnięcie Alt+F4, albo inny legalny sposób zamknięcia okna wysyła WM_CLOSE.
Domyślna procedura WM_CLOSE wykonuje DestroyWindow().
We własnej obsłudze WM_CLOSE można np. wyświetlić message boksa typu "Czy na pewno?" albo "Czy zapisać zmiany?". Po czym wywołać DestroyWindow albo nie.

Funkcja DestroyWindow zamyka okno. Zanim okno zostanie zniszczone, wysyłany jest komunikat WM_DESTROY.
Domyślne WM_DESTROY nie robi nic. Własne - może zwalniać jakieś zasoby, pamięć - przydzielone w WM_CREATE.
Po obsłużeniu WM_DESTROY okno przestaje istnieć i nie można już temu zapobiec.

0

Log:

'A.exe' (Win32): Loaded 'C:\Users\TheAifam5\Documents\Visual Studio 2013\Projects\A\Debug\A.exe'. Symbols loaded.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ntdll.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\kernel32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\KernelBase.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\user32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Program Files (x86)\Visual Leak Detector\bin\Win32\vld_x86.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msvcp120d.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msvcr120d.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\gdi32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\advapi32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Program Files (x86)\Visual Leak Detector\bin\Win32\dbghelp.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msvcrt.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\sechost.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\rpcrt4.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\sspicli.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\cryptbase.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\bcryptprimitives.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\imm32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msctf.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\nvinit.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Program Files (x86)\NVIDIA Corporation\coprocmanager\detoured.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Program Files (x86)\NVIDIA Corporation\coprocmanager\Nvd3d9wrap.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\setupapi.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\cfgmgr32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Program Files (x86)\NVIDIA Corporation\coprocmanager\nvdxgiwrap.dll'. Cannot find or open the PDB file.
Visual Leak Detector Version 2.4RC2 installed.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\uxtheme.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\combase.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\dwmapi.dll'. Cannot find or open the PDB file.
CreateWindowEx failed!teWindowEx failed!'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ole32.dll'. Cannot find or open the PDB file.
'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\kernel.appcore.dll'. Cannot find or open the PDB file.
rorndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!ndowEx failed!teWindowEx failed!The program '[8188] A.exe' has exited with code 0 (0x0).

Kod:

LRESULT CALLBACK CMainWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	OutputDebugString(L"" + uMsg);
	switch (uMsg)
	{
	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
		break;
	}
}

Nadal to samo. Nie mam pojecia. Parametr

uMsg
w
CMainWindow::WndProc
jak by wyciek pamieci mial. Program jest, ale jakby martwy, nie mozna nim ruszac, zmienaic rozmiaru.

Do analizy moze sie przydac: http://prntscr.com/4k2yli
Zdj zrobione podczas wywolywania procedury WndProc, klikania, proby ruszania oknem oraz proby zamkniecia. Aby tylko widac klikanie.
Wykonuje sie podczas klikania to: WM_NCHITTEST oraz WM_SETCURSOR
Proba zamkniecia to: WM_SETCURSOR

Stworzylem takze przycisk lecz...nadal nic.

0

'A.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ntdll.dll'. Cannot find or open the PDB file.

http://msdn.microsoft.com/en-us/library/b8ttk8zy%28v=vs.100%29.aspx

    if (!g_hWnd)
    {
        if (g_hWnd == INVALID_HANDLE_VALUE){

Jeśli g_hWnd wynosi NULL, no to nie wynosi INVALID_HANDLE_VALUE.

L"CreateWindowEx failed!\nGetLastError" + (int)GetLastError()

Tak się na pewno c-stringów nie łączy.

0

Ok. Siedzialem prawie do 5 rana myslac co jest nie tak.. Z tego co wyczytalem potrzeba uzyc SetWindowSubclass, pozniej poprzez SUBCLASSPROC odczytywac komunikaty, lecz co z WndProc ktora dostaje lParam z CreateWindowEx?

1
this->g_szWindowTitle = text.c_str();

Jakiego typu jest g_szWindowTitle?

0

Przesle moze to co zrobilem bo naprawde nie wiem co jest nie tak..
W zalaczniku kody zrodlowe.

Tak wyglada main.cpp

#include "stdafx.h"
#include "Utils.h"
#include "CMainWindow.h"

int APIENTRY WinMain(_In_ HINSTANCE hInstance,
					 _In_opt_ HINSTANCE hPrevInstance,
					 _In_ LPSTR    lpCmdLine,
					 _In_ int       nCmdShow)
{
	srand((unsigned int)(time(NULL)));

	//UNREFERENCED_PARAMETER(hPrevInstance);
	//UNREFERENCED_PARAMETER(lpCmdLine);

	

	CMainWindow main;
	if (!main.Initialize(L"Test"))
		return 1;
		
	main.Show();

	return main.Destroy();
}

///Edit:
Usunalem "virtual" z MainWindow "bool CreateControls(HWND hWnd);"

1
std::wstring* GetWindowClassName();

Nie zwracaj wstring*, zwracaj wstring. Nie po to miałeś przejść na kontenery, by się znowu bawić we wskaźniki.

Zresztą ta metoda jest niepotrzebna.

int CBaseWindow::Destroy()
{
	while (GetMessage(&GetMSG(), NULL, NULL,NULL))
	{
		TranslateMessage(&GetMSG());
		DispatchMessage(&GetMSG());
	}

	return (int)GetMSG().wParam;
}

Już pomijając fakt, że ta metoda absolutnie nie powinna nazywać się Destroy(), tylko np. Run(), to przejechałeś się na manii robienia akcesorów, tam gdzie nie są potrzebne, albo gdzie - tak jak tutaj - są szkodliwe.

Wywal GetMSG, wywal g_msg. To ma być zmienna lokalna:

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

Brawo @Azarien udalo sie :) troche pozmienialem, przepisalem, zastosowalem twoje uwagi i dziala ;)
Jak beda jakies problemy to jeszcze napisze, bo na pewno na tym nie koniec :)

0

Czy moge pobierac tekst w taki sposob?

LPWSTR buff = L"";
::GetWindowText(g_hWnd,buff,::GetWindowTextLength(g_hWnd));
return std::wstring(buff);

czy lepiej zrobic LPWSTR buff[512]; ?

I jesli mozna to prosze wytlumaczyc dlaczego inaczej a nie tak ;) Bylbym wdzieczny.

1

Musi być tablica, ale nie LPWSTR[], tylko WCHAR[]. Wszystko co ma na początku LP jest wskaźnikiem.

0

Witam ponownie. Jak utworzyc okno nie blokujac calej aplikacji? Czy zostalo mi tylko stworzenie watku a w nim:

while (GetMessage(&g_msg, NULL, 0, 0))
	{
		TranslateMessage(&g_msg);
		DispatchMessage(&g_msg);
	}

Hmm?

0

Sama pętla nie wystarczy, okno też musi być stworzone w wątku.

0
LPWSTR buff[256]; // musi być rozmiar tablicy!
::GetWindowText(g_hWnd,buff,ARRAYSIZE(buff)); // i tu podajemy rozmiar tej tablicy
return std::wstring(buff);

Jak utworzyc okno nie blokujac calej aplikacji? Czy zostalo mi tylko stworzenie watku a w nim:

Dziwny pomysł. Co chcesz właściwie osiągnąć? Mieć kilka okien na raz? (bez problemu, robisz kilka razy CreateWindow, a pętlę jedną). Mieć okno i jakąś operację działającą w tle? (to ta operacja powinna być w osobnym wątku).

1 użytkowników online, w tym zalogowanych: 0, gości: 1