2012-05-04 11 views
3

Windowsアプリケーションの場合、CreateWindow()WndProc()(または私のバージョン)を作成するシングルトンクラスの一部として取得しようとしています。 _tWinMain()の先頭にありますが、機能をGameHandler.hGameHandler.cppにシフトしようとしているので、「未解決の外部シンボル_WinMain @ 16」が続きます。彼らはもともとmain.cppのグローバル関数であり、すべてがうまくコンパイルされていましたが、私はそれらをGameHandlerに移動することにしました。それはmain.cppに戻そうとしても未解決の外部です。WndProcを別のcppファイルに移動すると「未解決の外部_WinMain @ 16」

私はVS2010でこれをやっていますが、プロジェクトはWindowsアプリケーションとして作成されており、プロパティには特定のエントリポイントが設定されていません(これまでコンソールのapp - これはそうではありません)。

私が現在持っているコードを以下に示します。実際のプロジェクトには、数千行のコードがありますが、私はそれが適切ではないと思っています。しかし、実際にはウィンドウの作成コードは関連していますが、コードそのもの実際のウィンドウ作成コードはNeHe's tutorialから取られています。次のコードをコンパイルしようとすると、次のコードだけが表示されます。 。前述の未解決の外部

main.cppに:GameManager.hで

#include <Windows.h> 
#include "GameManager.h" 

#ifndef USEGMGR 
bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag); 
LRESULT CALLBACK GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
#endif 

int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, 
         LPTSTR lpCmdLine, int nCmdShow) 
{ 
    GameManager::Startup(); 
    GameManager* GMgr = GameManager::GetInstance(); 

    GMgr->SetProgramState(GAME_MODE); 
    while(GMgr->GetProgramState() != GAME_MODE) // Normally this would be if (State != GAME_QUIT) 
    { /* do game related stuff */ } 

    GameManager::Shutdown(); 
    return 0; 
} 

#ifndef USEGMGR 
bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag) 
{ 
    // Fairly complex but flexible creation code, taken from NeHe's tutorials. Of relevant interest is: 
    WNDCLASS  wc;        // Windows Class Structure 
    wc.lpfnWndProc = (WNDPROC) GameWindowProc; // WndProc Handles Messages 
    if (!RegisterClass(&wc))       // Attempt To Register The Window Class 
    { 
     MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION); 
     return false; 
    } 
    return true; 
} 

LRESULT CALLBACK GameWindowProc(HWND hWnd,   // Handle For This Window 
    UINT uMsg,   // Message For This Window 
    WPARAM wParam,   // Additional Message Information 
    LPARAM lParam)   // Additional Message Information 
{ 
    // various custom message handling, if not processed: 
    return DefWindowProc(hWnd,uMsg,wParam,lParam); 
} 
#endif 

GameManager.cppで
#ifndef GAMEMANAGER_H 
#define GAMEMANAGER_H 
#define USEGMGR // makes CreateGameWindow() and GameWindowProc() methods in GameManager instead of global 

#include <Windows.h> 

enum ProgramState 
{ 
    GAME_MODE, 
    GAME_QUIT, 
}; 

class GameManager 
{ 
public: 
    static void    Startup(); 
    static void    Shutdown(); 
    static GameManager*  GetInstance(); 
    void     Update(); // code not shown, check quit key etc 
#ifdef USEGMGR 
    const bool    CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag); 
    static LRESULT CALLBACK GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
#endif 
    void     KillGameWindow(void); 
    const int    GetProgramState() const; 
    void     SetProgramState(const int& newMode); 
private: 
    GameManager(); 
    ~GameManager(); 
    GameManager(const GameManager&); 
    GameManager& operator=(const GameManager&); 
    HINSTANCE    m_hInstance; 
    HWND     m_hWnd;   
    HDC      m_hDC;   
    static GameManager*  s_instance; 
    int      m_programState; // uses ProgramState enum 
}; 
#endif 

#include "GameManager.h" 
#include <Windows.h> 
#include <assert.h> 

#ifndef USEGMGR 
extern bool CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag); 
#endif 
GameManager*  GameManager::s_instance = NULL; 
GameManager::GameManager(){} 
GameManager::~GameManager(){} 


void GameManager::Startup() 
{ 
    assert(s_instance == NULL); 
    s_instance = new GameManager; 
#ifdef USEGMGR 
    if (! (s_instance->CreateGameWindow("Game Window", 800, 600, 32, true))) 
#else 
    if (! (CreateGameWindow("Game Window", 800, 600, 32, true))) 
#endif 
     assert("CreateGameWindow failed! Need an error here"); // Quit If Window Was Not Created - clean this up later  
} 

void GameManager::Shutdown() 
{ 
    assert(s_instance != NULL); 
    delete s_instance; 
    s_instance = NULL; 
} 

GameManager* GameManager::GetInstance(){return s_instance;} 

void GameManager::Update(){/* msg handling, watch for quit key, etc */} 
const int GameManager::GetProgramState() const{return s_instance->m_programState;} 
void GameManager::SetProgramState(const int& newState){s_instance->m_programState = newState;} 

#ifdef USEGMGR 
const bool GameManager::CreateGameWindow(char* title, int width, int height, int bits, bool fullScreenFlag) 
{ 
    // Fairly complex but flexible creation code, taken from NeHe's tutorials. Of relevant interest is: 
    WNDCLASS  wc;        // Windows Class Structure 
    wc.lpfnWndProc = (WNDPROC) GameManager::GameWindowProc; // WndProc Handles Messages 
    if (!RegisterClass(&wc))       // Attempt To Register The Window Class 
    { 
     MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION); 
     return false; 
    } 
    return true; 
} 

LRESULT CALLBACK GameManager::GameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    // various custom message handling, if not processed: 
    return DefWindowProc(hWnd,uMsg,wParam,lParam); 
} 
#endif  

あなたが見ることができるように、私はmain.cppにある厄介な関数間またはGameManagerの一部として切り替えるために、いくつかのプリプロセッサの条件を設定しました。 #define USEGMGRGameManager.hの先頭にコメントアウトして、グローバル機能としてmain.cppに設定します。

私が間違っていることを教えてもらえますか?

編集:は、実行すると終了できないというコメントを削除しました。

答えて

2

main.cppの先頭に

#include <tchar.h> 

を追加します。

マクロ定義をしていないと、オブジェクトファイルに_tWinMain()という名前の関数(または[email protected]@[email protected]@[email protected]()のような名前のある程度変形されたバージョン)がありますが、リンカとランタイムの初期化コードが見えていますWinMain()またはwWinMain()です。彼らはそれを見つけることはありません。

<tchar.h>は、名前_tWinMain()を他のものが探している2つの名前のいずれかに変換するマクロを定義します。リファクタリングを開始する前に(かなり間接的に)ヘッダーを含む何かを持っていて、何とかそれを失っているはずです。

マクロ版を使用せずに、関数WinMainまたはwWinMain(UNICODE用に構築しているかどうかに関わらず)の名前を付けることもできます。それを行う場合は、選択したパラメーターに合わせてLPTSTRパラメーターの宣言を変更してください。

+0

私はこれについて知りませんでしたが、嫌なことに何かになるのではないかと心配しました(私はWinAPIを学ぼうとしています)ので、何か新しいことを学びました。明確な説明をありがとう。 '_tWinMain'を' WinMain'に変更すると動作します。何らかの理由で一方通行かもう一方通貨が望ましいですか? – Malorion

+1

@Malorion:自分の好みでは、 '_tWinMain()'ではなく、 'WinMain()'(または 'unWindow ')という名前の関数を単純に持つことになります。しかし、ちょうどあなたが逃げ出した混乱以外の強力な技術的理由はありません。 –

5

WinMain関数は、「シングルトン」クラスであっても、クラスのメンバー関数であってはなりません。

従来のC++アプリケーションで見つけられるmain関数を置き換えることで、プログラムの「エントリポイント」として機能するので、それは自由なグローバル関数である必要があります。

メッセージUnresolved external [email protected]は、WinMainという名前の予想されるエントリポイントを見つけることができないというコンパイラの秘密の方法です。 _tWinMainマクロが適切に定義されますように

+0

興味のある点として、.defファイルでエクスポートした場合、静的メンバーになる可能性がありますか?私は本当の問題は、システムのエントリポイントは、このポインタのパラメータを隠して期待できないということです。 – Benj

+0

@Benjいいえ、考えなかった。私はあなたがそれをしたいと思う理由を想像することはできません... –

+0

私はあなたが思う、それが可能かどうかだけ考えています。 – Benj

関連する問題