I work on a C++/ MFC app on Visual Studio 2013, Win7 32bit. I have a Main application with a dialog where I put a DateTimePicker MFC object. For the initilization I used the DDX_DateTimeCtrl and a m_odtFilterData member variable.
void CClassDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_DateTimeCtrl(pDX, IDC_DATE, m_odtFilterData);
}
BOOL CClassDlg::OnInitDialog()
{
COleDateTime odtCurrDate = COleDateTime::GetCurrentTime();
m_odtFilterData.SetDate(odtCurrDate.GetYear(), 1, 1);
CDialog::OnInitDialog();
//etc etc
UpdateData(FALSE);
return TRUE;
}
After I added a Date Time Change event
BEGIN_MESSAGE_MAP(CClassDlg, CDialog)
ON_NOTIFY(DTN_DATETIMECHANGE, IDC_DATE, &CClassDlg::OnDtnDatetimechange)
END_MESSAGE_MAP()
and
void CClassDlg::OnDtnDatetimechange(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMDATETIMECHANGE pDTChange = reinterpret_cast<LPNMDATETIMECHANGE>(pNMHDR);
if(m_odtExampleODTVarThatIHave > m_odtFilterData)
{
//do stuff
}
*pResult = 0;
}
The problem is that when in the dialog I choose the date with the datetimepicker, sometimes, the app crash with this error:
Windows has triggered a breakpoint in AppName.exe.
This may be due to a corruption of the heap, which indicates a bug in AppName.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while AppName.exe has focus.
The output window may have more diagnostic information.
The output only says:
HEAP[AppName.exe]: HEAP: Free Heap block 279850 modified at 279e1c after it was freed
And the breakpoint is stucked at mfc\appmodul.cpp:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
/*->*/return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
It's very strange and happens only few click on the button of the datetimepicker that shows the months widget. If, instead of the widget, I use the Spin Control all works perfectly... Do you have any idea?
The button that open the month widget
Another thing, if I remove the
if(m_odtExampleODTVarThatIHave > m_odtFilterData)
all works. It seems that for some reason, the m_odtFilterData variabile gets corrupted by month widget. I don't understand where is my error.
The obvious problem that I see is that you forgot to call CDialog::DoDataExchange(pDX); in CClassDlg::DoDataExchange(CDataExchange* pDX) So it should look like:
void CClassDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_DateTimeCtrl(pDX, IDC_DATE, m_odtFilterData);
}
Please also check that Common Controls have been properly initialized in OnInitInstance of your CWinApp-derived class:
INITCOMMONCONTROLSEX iccex = { sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES | ICC_STANDARD_CLASSES };
// Init the common controls.
InitCommonControlsEx ( &iccex );
Please also make sure you have proper manifest:
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Please also check your _WIN32_WINNT definition.
Related
I have a CUI based and GUI based application that is written with CPP language. GUI based application has the following code:
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const TCHAR* title = TEXT("پیام");
const TCHAR* text = TEXT("سلام، من یک پنجره هستم.");
MessageBox(NULL, text, title, MB_OKCANCEL | MB_ICONINFORMATION);
return 0;
}
and CUI based program has the following code:
#include <Windows.h>
#include <iostream>
int main(int argc, const char* argv)
{
const char* cMessage = "Native Windows Development.\n";
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), cMessage, strlen(cMessage), NULL, NULL);
return 0;
}
However, when I debug these programs in WinDBG, I have seen before main and WinMain function, a lot of other functions like mainCRTStartup and invoke_main for CUI based app and WinMainCRTStartup and invoke_main for GUI based app have called.
What are these functions and what they did before executing the main? and also how can I get more information about these two function?
With VS tool, we could see the call stack below:
And if you double-click on each call of the stack, you could see what it did in the code(as comments, the source code was located at ..\VC\Tools\MSVC\14.24.28314\crt\src\vcruntime).
First wWinMainCRTStartup is just to call function __scrt_common_main:
extern "C" int wWinMainCRTStartup()
{
return __scrt_common_main();
}
In __scrt_common_main, the comments contains the detals:
// This is the common main implementation to which all of the CRT main functions
// delegate (for executables; DLLs are handled separately).
static __forceinline int __cdecl __scrt_common_main()
{
// The /GS security cookie must be initialized before any exception handling
// targeting the current image is registered. No function using exception
// handling can be called in the current image until after this call:
__security_init_cookie();
return __scrt_common_main_seh();
}
The function is the common main implementation to which all of the CRT
main functions delegate (for executables; DLLs are handled
separately) and __security_init_cookie is to initialize /GS security cookie
before any exception handling for current image.
Then, it was the __scrt_common_main_seh:
initialize crt, acquire startup lock, check the current native startup state, release startup lock, invoke the dynamically initialized __declspec(thread) variables, register the callback function for thread-local destructors.
After complete the Initialization, call invoke_main, as the name, it invoke main/wWinMain.
static int __cdecl invoke_main()
{
return wWinMain(
reinterpret_cast<HINSTANCE>(&__ImageBase),
nullptr,
_get_wide_winmain_command_line(),
__scrt_get_show_window_mode());
}
I build the code successfully but it does not debug and comes up with this warning in a wizard miscellaneous code.
"Warning: Destroying non-NULL m_pMainWnd\n"
and
"Warning: Temp map lock count non-zero (%ld).\n",
The aim of this is to create a dialog box that allows a user to input car specifications and a track so a lap time can be calculated.
Source File of Main Dialogue box:
#define _WIN32_WINNT 0x0601
// LapTimeSim.cpp : implementation file
//
#include <iostream>
#include "stdafx.h"
#include "LapTimeSim.h"
#include "afxdialogex.h"
#include "SecondDlg.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
using namespace std;
// LapTimeSim dialog
IMPLEMENT_DYNAMIC(LapTimeSim, CDialogEx);
LapTimeSim::LapTimeSim(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_DIALOG1, pParent)
{
}
LapTimeSim::~LapTimeSim()
{
}
void LapTimeSim::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(LapTimeSim, CDialogEx)
ON_BN_CLICKED(IDC_CAR, &LapTimeSim::OnBnClickedCar)
ON_BN_CLICKED(IDGO, &LapTimeSim::OnBnClickedGo)
ON_BN_CLICKED(IDC_TRACK, &LapTimeSim::OnBnClickedTrack)
END_MESSAGE_MAP()
// LapTimeSim message handlers
void LapTimeSim::OnBnClickedCar()
{
// TODO: Add your control notification handler code here
CSecondDlg Dlg;
Dlg.DoModal();
}
void LapTimeSim::OnBnClickedGo()
{
// TODO: Add your control notification handler code here
}
void LapTimeSim::OnBnClickedTrack()
{
// TODO: Add your control notification handler code here
}
A Large Header; Header file of main dialog box
==============
#pragma once
// LapTimeSim dialog
class LapTimeSim : public CDialogEx
{
DECLARE_DYNAMIC(LapTimeSim)
public:
LapTimeSim(CWnd* pParent = NULL); // standard constructor
virtual ~LapTimeSim();
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_DIALOG1 };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedCar();
afx_msg void OnBnClickedGo();
afx_msg void OnBnClickedTrack();
};
Source File of Main Dialogue box:
// SecondDlg.cpp : implementation file
//
#define _WIN32_WINNT 0x0601
#include <iostream>
#include "stdafx.h"
#include "LapTimeSim.h"
#include "afxdialogex.h"
#include "SecondDlg.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CSecondDlg dialog
IMPLEMENT_DYNAMIC(CSecondDlg, CDialog)
CSecondDlg::CSecondDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_DIALOG2, pParent)
{
}
CSecondDlg::~CSecondDlg()
{
}
void CSecondDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CSecondDlg, CDialog)
END_MESSAGE_MAP()
// CSecondDlg message handlers
A Large Header; Header file of second dialog box
==============
#pragma once
// CSecondDlg dialog
class CSecondDlg : public CDialog
{
DECLARE_DYNAMIC(CSecondDlg)
public:
CSecondDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CSecondDlg();
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_DIALOG2 };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
};
Source File : appmodule.cpp writeen by the wizard
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "sal.h"
/////////////////////////////////////////////////////////////////////////////
// export WinMain to force linkage to this module
extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow);
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
/////////////////////////////////////////////////////////////////////////////
// initialize app state such that it points to this module's core state
BOOL AFXAPI AfxInitialize(BOOL bDLL, DWORD dwVersion)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_bDLL = (BYTE)bDLL;
ASSERT(dwVersion <= _MFC_VER);
UNUSED(dwVersion); // not used in release build
#ifdef _AFXDLL
pModuleState->m_dwVersion = dwVersion;
#endif
#ifdef _MBCS
// set correct multi-byte code-page for Win32 apps
if (!bDLL)
_setmbcp(_MB_CP_ANSI);
#endif //_MBCS
return TRUE;
}
// force initialization early
#pragma warning(disable: 4074)
#pragma init_seg(lib)
#ifndef _AFXDLL
void AFX_CDECL _AfxTermAppState()
{
// terminate local data and critical sections
AfxTermLocalData(NULL, TRUE);
AfxCriticalTerm();
// release the reference to thread local storage data
AfxTlsRelease();
}
#endif
#ifndef _AFXDLL
char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER), atexit(&_AfxTermAppState));
#else
char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER));
#endif
/////////////////////////////////////////////////////////////////////////////
Source File - Wizard code coming up with warning:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "sal.h"
/////////////////////////////////////////////////////////////////////////////
// Standard WinMain implementation
// Can be replaced as long as 'AfxWinInit' is called first
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
/////////////////////////////////////////////////////////////////////////////
(See my answer to this SO: Cannot create main window?, it looks very similar to your issue)
If you have created this project with wizard then you should also have source files for CWinApp implementation. If its some other kind of wizard generated application then you still should somewhere have an InitInstance like method. with following lines of code:
LapTimeSim dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
(I assume here that LapTimeSim is your main entry dialog). If you remove above lines, you will get the exact same trace and behaviour as in your description (I checked this locally).
So you should check if you have by mistake removed them, or recreate project from MFC template wizard.
Code:
#include <tchar.h>
#include <windows.h>
typedef INT (WINAPI * lolMessageBoxA)(HWND,LPCSTR,LPCSTR,UINT);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
lolMessageBoxA UchwytMessageBoxA;
UchwytMessageBoxA = lolMessageBoxA(GetProcAddress(GetModuleHandle("User32.dll"),"MessageBoxA"));
UchwytMessageBoxA(NULL,"TEST WINDOWS","TEXT 2", MB_OKCANCEL | MB_ICONWARNING);
return 0;
}
When i called MessageBoxA normally before making hook the hooking part worked good. But when i erased that part and leaved only the 'hooking' part it fails...
Solved:
#include <tchar.h>
#include <windows.h>
typedef INT (WINAPI * lolMessageBoxA)(HWND,LPCSTR,LPCSTR,UINT);
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
lolMessageBoxA UchwytMessageBoxA;
LoadLibraryA("User32.dll");
UchwytMessageBoxA = lolMessageBoxA(GetProcAddress(GetModuleHandle("User32.dll"),"MessageBoxA"));
UchwytMessageBoxA(NULL,"TEST WINDOWS","TEXT 2", MB_OKCANCEL | MB_ICONWARNING);
return 0;
}
As presented here, there's no reason for the process to have loaded user32.dll. So the call to GetModuleHandle will return NULL. Then the call to GetProcAddress will also fail and return NULL. And well, you can see what happens next.
When you called MessageBoxA directly, the linker would have produced an import table that forced the loader to load user32.dll. But when you removed the call to MessageBoxA, there was no need for it to do so.
You should replace the call to GetModuleHandle with a call to LoadLibrary, and so force the library to be loaded.
Finally, the real reason for you having asked this question is that your code neglects error checking. Don't do that. Check the values returned by the Win32 function calls. Had you done so you would have been able to work this out for yourself.
So the idea is when the user haven't installed DirectX End-User Runtime the program to show message like "DirectX Runtime missing! Download it from here", instead of the windows loader error (eg.: "d3dx9_43.dll is missing!"). So I find a very funky solution of the problem as I used a delay loaded DLL's and an DLL check before any function defined in the module is invoked using LoadLibrary. If the dll is missing the program shows a user-defined dialog box and exits, otherwise it calls FreeLibrary with the HMODULE returned by LoadLibrary and continues executing. This is implemented as a function like follows:
bool CheckResourcesAvailability() //Mainly check for the existence of delay loaded DLL's
{
HMODULE hMod; //Resourse handle
if((hMod = LoadLibraryEx(_T("d3d9.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) == NULL)
{
DialogBox(hProgramInstance, MAKEINTRESOURCE(IDD_DX_RE), 0, (DLGPROC)&DxRedistMissingDlg);
return false;
}
FreeLibrary(hMod);
if((hMod = LoadLibraryEx(_T("D3DX9_43.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) == NULL)
{
DialogBox(hProgramInstance, MAKEINTRESOURCE(IDD_DX_RE), 0, (DLGPROC)&DxRedistMissingDlg);
return false;
}
FreeLibrary(hMod);
return true;
}
*As DxRedistMissingDlg and MAKEINTRESOURCE(IDD_DX_RE) creates the user-defined error message dialog.
And In WinMain it's called as follows:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hProgramInstance = hInstance;
#ifndef _DEBUG
SetErrorMode(SEM_FAILCRITICALERRORS); //Don't display windows error messages
#endif
//Check for missing delay - loaded dependencies and inform the user
if(!CheckResourcesAvailability())
return -1;
//Some other code.........
}
But I don't think this is the cleanest way to do it. First we aren't sure that d3dx9.lib really inherits from D3DX9_43.dll (I know that because I used IDA PRO) and also the LoadLibrary function is called twice - one time at the CheckResourcesAvailability() function and second when the DLL is delay-loaded. Any ideas for a better implementation?
Use delay load hooks to let the delay loader notify you whenever a given DLL or a specific exported function is missing. Not only does that tell you which DLL/function is missing, but also lets you specify a substitute DLL/function if desired.
For a Windows application I'm trying to get CreateWindow() and WndProc() (or my versions of them) to be part of a singleton class that is created at the beginning of _tWinMain() but since trying to shift the functions to GameHandler.h and GameHandler.cpp I keep getting "unresolved external symbol _WinMain#16". They were originally global functions in main.cpp and everything was compiling fine then I decided to move them to GameHandler and ever since all I get is the unresolved external, even if I try to move them back to main.cpp.
I'm doing this in VS2010, the project was created as a Windows Application and there's no specific entry point set in properties (I double checked as every solution I've found so far says that it's because it's a console app - this isn't).
The code I currently have is shown below. The actual project has a couple of thousand lines of other code that I've left out as I don't think it's relevant (but will happily proved wrong. While the actual window creation code is related, I don't think the code itself is the problem (apart from what I left in), it's the location of GameWindowProc() &/or CreateGameWindow() or how they're called. The actual window creation code is taken from NeHe's tutorial. Trying to compile the following code only gives the aforementioned unresolved external.
main.cpp:
#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
in GameManager.h:
#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
in GameManager.cpp:
#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
As you can see, I've set up some preprocessor conditionals to switch between the troublesome functions being in main.cpp or as part of GameManager. Comment out #define USEGMGR at the beginning of GameManager.h to have them as global funcs in main.cpp.
Can someone please tell me what I'm doing wrong?
Edit: removed comment about not being able to quit if you get it to run.
The WinMain function cannot be a member function of a class, even a "singleton" class.
Since it functions as the "entry point" for the program, essentially replacing the main function you'd find in a traditional C++ application, it needs to be a free global function.
The message Unresolved external _WinMain#16 is simply the compiler's cryptic way of telling you that it cannot locate the expected entry point, named WinMain (plus some name mangling).
Add
#include <tchar.h>
to the top of main.cpp so that the _tWinMain macro gets defined properly.
What happens if you don't have the macro definition is that you end up with a function named _tWinMain() (or some mangled version of the name like ?_tWinMain##YGHPAUHINSTANCE__##0PADH#Z()) in the object file, but the linker and runtime initialization code are looking for WinMain() or wWinMain(). They don't find it.
<tchar.h> defines a macro that transforms the name _tWinMain() into one of the two names everything else is looking for. You must have had something including that header before you started your refactoring (quite possibly indirectly), and lost it somehow.
Or you can dispense with the macro version and name the function WinMain or wWinMain (either one should work, regardless of whether you're building for UNICODE or not). If you do that, just remember to change the LPTSTR parameter declaration to match the one you choose.