2012-02-05 18 views
1

私はd3dで作業している間、基本的なWin32機能をクラスにラップすることを実験していましたが、CreateWindowEx関数が失敗してクラスが存在しないと言われていない理由を困惑しています。の:\。私は何かばかげた小さなことを逃している気がしますが、私はそれを見つけることができません。ここでは、コードの一部です:登録が成功したにもかかわらず、CreateWindowExがエラー1407で失敗しましたか?

それはクラス名と簡略化され、コンストラクタの通常のstd ::文字列を持つように私は、このようWNDCLASSEXを拡張するクラスを持っている:

#ifndef WINDOWCLASS_H 
#define WINDOWCLASS_H 

#include <Windows.h> 
#include <string> 
#include "WindowAbstract.h" 
using namespace std; 

class WindowClass : public WNDCLASSEX 
{ 
public: 
    WindowClass(string className, WindowAbstract * window); 
    ~WindowClass(); 

    bool Register(); 
    string ClassName() {return m_className;} 

    friend class WindowAbstract; 

private: 
    string m_className; 
}; 

#endif 

そしてここにはありますクラスのコンストラクタ:

WindowClass::WindowClass(string className, WindowAbstract * window) 
{ 

    cbSize  = sizeof(WNDCLASSEX); 
    style   = 0; 
    lpfnWndProc = window->WndProc; 
    cbClsExtra = 0; 
    cbWndExtra = 0; 
    hInstance  = hInstance; 
    hIcon   = LoadIcon(NULL, IDI_APPLICATION); 
    hCursor  = LoadCursor(NULL, IDC_ARROW); 
    hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 
    lpszMenuName = NULL; 
    lpszClassName = className.c_str(); 
    hIconSm  = LoadIcon(NULL, IDI_APPLICATION); 

    m_className = className; 
} 

ここでは、それが構築されています後に呼び出されるレジスタ機能である:

bool WindowClass::Register() 
{ 
    if(RegisterClassEx(this) == 0) 
     return false; 

    return true; 
} 

WindowAbstractクラスにはウィンドウプロシージャが含まれており、その関数へのポインタをWindowClassオブジェクトに渡すために最初に作成されます。

#ifndef WINDOWABSTRACT_H 
#define WINDOWABSTRACT_H 

#include <Windows.h> 
#include <string> 
using namespace std; 

class WindowAbstract 
{ 

public: 
    WindowAbstract(); 
    ~WindowAbstract(); 

    bool Create(string windowTitle, string className, DWORD styles, DWORD extendedStyles, int top, int left, int bot, int right, HWND parent, HMENU id); 
    void Show(); 

    friend class WindowClass; 

private: 
    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 
    HWND m_hwnd; 

}; 

#endif 

そして、ここで関数を作成します

bool WindowAbstract::Create(string windowTitle, string className, DWORD styles, DWORD extendedStyles, int top, int left, int bot, int right, HWND parent, HMENU id) 
{ 
    m_hwnd = CreateWindowEx(extendedStyles, className.c_str() , windowTitle.c_str(), styles, top, left, bot, right, parent, id, GetModuleHandle(NULL), NULL); 
    if(!m_hwnd) 
     return false; 

    return true; 
} 

ので、すべてのことを見た後、ここに私はそれをテスト実際のWinMain関数である:そう

#include "WindowAbstract.h" 
#include "WindowClass.h" 


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
LPSTR lpCmdLine, int nCmdShow) 
{ 
    DWORD error; 
    bool result; 
    char buffer[100]; 

    WindowAbstract * window = new WindowAbstract(); 
    WindowClass * myClass = new WindowClass("myClass", window); 

    result = myClass->Register(); 
    if(!result) 
    { 
     error = GetLastError(); 
     sprintf_s(buffer, "error: %i", error); 
     MessageBox(NULL, buffer, "Registration Failed!", MB_OK); 
    } 

    result = window->Create("my Window", myClass->ClassName(), WS_OVERLAPPEDWINDOW, WS_EX_CLIENTEDGE, 20, 20, 200, 200, NULL, NULL); 
    if(!result) 
    { 
     error = GetLastError(); 
     sprintf_s(buffer, "error: %i", error); 
     MessageBox(NULL, buffer, "Window Creation Failed!", MB_OK); 

    } 

    window->Show(); 

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

    if(window) 
    { 
     delete window; 
     window = 0; 
    } 

    if(myClass) 
    { 
     delete myClass; 
     myClass = 0; 
    } 

    return msg.wParam; 
} 

、結論では、これは非常に混乱しているので、WindowClassオブジェクトのRegister関数は正常に戻りますが、その名前の有効なクラス(エラー1407)がないため、WindowAbstractオブジェクトでcreate関数が失敗します。どう?

答えて

5

私はこの問題はlpszClassName = className.c_str()で、WindowClassコンストラクタだと思います。一般的に、c_str()から返された値は、長時間にわたって使用できないようにしてください。

この場合、RegisterClassExに電話をするまでに存在しなくなった可能性のあるローカル変数のアドレスを(効果的に)取得しています。だからRegisterClassExは成功していますが、見ている名前は誰が知っていますか?

lpszClassName = m_className.c_str()(おそらく最初にm_classNameを割り当てた場合)でもそれはまだスケッチです。 RegisterClassExに電話する直前にc_str()に電話するほうがよいでしょう。

+1

ああ、そうした:P。コンストラクタ内でc_str()関数を呼び出すと、コンストラクタのスコープ内にある限り、メンバーが正しく有効であると仮定します。したがって、コンストラクタが終了し、Registerメンバを呼び出すときに間違っていました。今私はレジスタメンバーを完全に去って、コンストラクタの最後にRegisterClassExを呼び出し、私のウィンドウはうまく作成されました(YAY!)。あなたの提案をありがとう!:P – FatalCatharsis

+0

私は実際にあなたのアドバイスを受け取りました。lpszClassName = className.c_str();を省略して、以前のようにm_classNameメンバに渡された文字列を割り当てました。ステートメントをコンストラクタに挿入し、lpszClassName = m_className.c_str();を入力します。私がRegister会員にクラスを登録する直前に。それは魅力的に機能していたので、今でもRegisterClassExが失敗しているかどうかを確認できます。 WOOT:P。結論として、私は今、string :: c_str()によって返されたchar *がローカルであり、現在のスコープに対してのみ有効であることを知りました。 – FatalCatharsis

+2

'string :: c_str()'によって返される 'char *'は有効です(文字列の次の非constメソッド呼び出し(または文字列が破壊される)まで)](http://www.cplusplus.com/参照/文字列/文字列/ c_str /)。 –

3

ライン

hInstance  = hInstance; 

を達成するために意図されているものは明らかではありません。実際には、hInstance自体を初期化するので、効果的に初期化されません。この初期化されていない値は、おそらくCreateWindowExに渡された同じ値ではありません。

+0

ああ、実際には事故でした。なぜなら、hInstanceは関数に渡されるパラメータであり、もともとはWNDCLASSEXメンバを含むクラスを作成していたからです。今私はhInstance = GetModuleHandle(NULL)で置き換える必要があります。 キャッチのおかげで、それは私の最初の問題を解決しませんでした:\ – FatalCatharsis

+2

実際のモジュールのインスタンスハンドルを使用します。 ['GetModuleHandle(NULL)'を使うことはID窃盗のようなものです](http://blogs.msdn.com/b/oldnewthing/archive/2011/07/15/10186685.aspx)。 –

関連する問題