2013-08-23 5 views
1

Я сделал свое исследование, но не смог найти ответ. Самое близкое, что я нашел, это «Cannot create window», но это меня не помогло. Итак, вот оно!Окно Win32 не удается создать?

Базовая информация

У меня есть статические библиотеки и приложения, используя статическую библиотеку. Я правильно подключил приложение к статической библиотеке (включите каталоги, библиотечные каталоги, фактические зависимости библиотек и т. Д.). В статической библиотеке у меня есть 1 файл: IWindow.h. В приложении у меня есть 3 файла: Main.cpp, WindowMain.h и WindowMain.cpp. IWindow.h определяет абстрактный класс окна:

#ifndef IWINDOW_H 
#define IWINDOW_H 

#include <Windows.h> 

namespace NamespaceName 
{ 
    template<class T> 
    class IWindow 
    { 
    public: 
     static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 

     virtual ~IWindow(){} 

     virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0; 
     virtual VOID paint(HDC hDC) = 0; 

     VOID create(HINSTANCE hI, LPCWSTR title, LPCWSTR className, DWORD dwStyle, DWORD dwExStyle = 0, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT, HWND hWndParent = 0, HMENU hMenu = 0); 

     HWND getHWND(); 
     BOOL isCreated(); 
    protected: 
     HWND m_hWnd; 
     BOOL created; 
    }; 

    template<class T> 
    LRESULT CALLBACK IWindow<T>::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     T* pThis = NULL; 

     if(uMsg == WM_NCCREATE) 
     { 
      CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam; 
      pThis = (T*)pCreate->lpCreateParams; 
      SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis); 
     } 
     else 
     { 
      pThis = (T*)GetWindowLongPtr(hWnd, GWLP_USERDATA); 
     } 

     if(pThis) 
     { 
      return pThis->handleMessage(uMsg, wParam, lParam); 
     } 
     else 
     { 
      return DefWindowProc(hWnd, uMsg, wParam, lParam); 
     } 
    } 

    template<class T> 
    VOID IWindow<T>::create(HINSTANCE hI, LPCWSTR title, LPCWSTR className, DWORD dwStyle, DWORD dwExStyle = 0, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int nWidth = CW_USEDEFAULT, int nHeight = CW_USEDEFAULT, HWND hWndParent = 0, HMENU hMenu = 0) 
    { 
     WNDCLASS windowClass = {0}; 
     windowClass.hInstance = hI; 
     windowClass.lpszClassName = className; 
     windowClass.style = CS_HREDRAW | CS_VREDRAW; 
     windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
     windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); 
     windowClass.lpfnWndProc = IWindow::windowProc; 

     RegisterClass(&windowClass); 

     m_hWnd = CreateWindowEx(dwExStyle, className, title, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this); 

     created = (m_hWnd ? TRUE : FALSE); 
    } 

    template<class T> 
    HWND IWindow<T>::getHWND() 
    { 
     return m_hWnd; 
    } 

    template<class T> 
    BOOL IWindow<T>::isCreated() 
    { 
     return created; 
    } 
} 

#endif 

Затем

WindowMain.h определяет подкласс IWindow.h

Код:

#ifndef WINDOWMAIN_H 
#define WINDOWMAIN_H 

#include <FolderName\Video\GUI\IWindow.h> 

class WindowMain : public NamespaceName::IWindow<WindowMain> 
{ 
public: 
    ~WindowMain(){} 

    LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); 
    VOID paint(HDC hDC); 
}; 

#endif 

И

это сопровождающий файл .cpp

завершает его:

#include "WindowMain.h" 

LRESULT WindowMain::handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    HDC hDC; 
    PAINTSTRUCT ps; 

    switch(uMsg) 
    { 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 
    case WM_PAINT: 
     { 
      hDC = BeginPaint(m_hWnd, &ps); 

      FillRect(hDC, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1)); 
      paint(hDC); 

      EndPaint(m_hWnd, &ps); 
     } 
     return 0; 
    } 

    return DefWindowProc(m_hWnd, uMsg, wParam, lParam); 
} 

VOID WindowMain::paint(HDC hDC) 
{ 
} 

И, наконец,

Main.cpp

Код:

#include <Windows.h> 
#include <tchar.h> 
#include <GdiPlus.h> 
#include "WindowMain.h" 

#pragma comment(lib, "Gdiplus.lib") 

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) 
{ 
    WindowMain window; 
    MSG msg; 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdiplusToken; 

    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    window.create(hInstance, L"Test Window", L"Test Window Class", WS_OVERLAPPEDWINDOW); 

    if(!window.isCreated()) 
     return 1; 

    ShowWindow(window.getHWND(), nCmdShow); 
    UpdateWindow(window.getHWND()); 

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

    Gdiplus::GdiplusShutdown(gdiplusToken); 

    return 0; 
} 

window.isCreated() всегда возвращает false, что делает if заявление в Main.cpp инвертирует его до true и всегда возвращает 1 и выходит из приложения. Если я опускаю оператор if от Main.cpp, окно не отображается, и приложение продолжается вечно, пока я не закрою его в среде IDE.

Дополнительные вопросы (ответ в комментариях, если вы хотите, они не являются обязательными и не касаются первого вопроса в любом случае)

Мне не нравится Visual Studio на всех. Я предпочитаю использовать NetBeans намного больше. Я попытался использовать его для программирования Windows, но я потерпел неудачу. Должен ли я использовать программу Visual Studio для Windows? Есть ли у него какой-то магический компилятор, который может скомпилировать программы Win32 особым образом? Или я просто делаю что-то неправильно?

Что представляют собой эти жетоны Gdiplus и ввод в эксплуатацию? Ссылка на то, что объясняет это, было бы потрясающе.

Наконец

Спасибо за ваше время, чтобы прочитать это, и, возможно, пытается помочь мне. Если вам нужна дополнительная информация, я буду рад предоставить ее. Если вопрос был плохо сконструирован, пожалуйста, дайте мне знать, как его улучшить, и я это сделаю.;)

Редактировать # 1

Нашел: "Win32 API window won't open", только для записи, это не помогло мое дело тоже.

Edit # 2

В IWindow.h, когда я создавал WNDCLASS, для процесса окна, я пытался использовать T::windowProc вместо IWindow::windowProc, но это не помогло.

Edit # 3

Найдено "WinAPI window doesn't appear", но не помогло.

Редактировать # 4

"Попробуйте установить windowClass.cbWndExtra на SizeOf (LONG_PTR) перед регистрацией класса." - из комментариев. Пробовал тоже, а также не помог.

Редактировать # 5

Пробовал заменить WNDCLASS с WNDCLASSEX и RegisterClass с RegisterClassEx и добавил windowClassEx.cbSize = sizeof(WNDCLASSEX) (я изменил имя переменной из windowClass в windowClassEx тоже), но не помогло ...

+4

Я не использую VS для программирования Windows слишком часто, поэтому нет. – chris

+0

Хорошо, спасибо за информацию, тогда я сделаю еще несколько исследований. Я так рад, что мне не нужно его использовать: P –

+0

Перед регистрацией класса попробуйте установить windowClass.cbWndExtra на sizeof (LONG_PTR). – user1233963

ответ

5

Я вижу по крайней мере две ошибки.

Во-первых, зарегистрировать класс с

windowClass.hInstance = hI; 

, но при создании окна, вы передаете другой HINSTANCE:

m_hWnd = CreateWindowEx(dwExStyle, className, title, dwStyle, x, y, 
      nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this); 
//           ^^^^^^^^^^^^^^^^^^^^^ 

В HINSTANCE параметры должны совпадать для класса, чтобы быть найденный. Вы должны использовать hI в обоих местах.

Во-вторых, ваш код использует элемент m_hWnd до его инициализации.

return DefWindowProc(m_hWnd, uMsg, wParam, lParam); 

Когда окно получает сообщение WM_NCCREATE, m_hWnd еще не был инициализирован. Он не инициализируется до тех пор, пока не вернется CreateWindowEx. Вы должны получить правильный дескриптор окна до DefWindowProc. Один из способов - передать параметр hWnd с windowproc до handlemessage. Другим является добавление

m_hWnd = hWnd; 

в вашем if(uMsg == WM_NCCREATE).

Обратите внимание, что в вашем коде предполагается, что если GWLP_USERDATA отличное от нуля, тогда действует m_hWnd. Однако вы ничего не сделали, чтобы сделать это предположение действительным. Между получением сообщения WM_NCCREATE и завершением CreateWindowEx у вас есть ненулевой GWLP_USREDATA, но m_hWnd не инициализирован.

Способ отладки заключается в том, чтобы установить точку останова в процедуре окна и пройти через нее. Когда вы переходите к обработке сообщения WM_NCCREATE, вы должны заметить, что m_hWnd не инициализирован.

В этом коде есть третья ошибка, с которой вы в конце концов столкнетесь, как только получите окно: никогда не устанавливайте m_hWnd на NULL, когда окно будет уничтожено.

+0

Большое спасибо! Это помогло решить проблему, и я понятия не имею, как я пропустил эти вещи! В будущем я должен уделить больше внимания: P –

Смежные вопросы