I have an mfc project which is process spawned by a windows service. For some reason the process dies before it starts. Global values get created but the process would not start the _tmain. This issue raised while moving from VC6 to VS2012.
Here is a code sample, I can place a break point and stop at this line CWinApp theApp; but I can't stop at the first line of _tmain. The program just can't find the entry point and exists.
// prog.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
try {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
nRetCode = 1;
}
else
{
//Some propietry code which runs here
}
return nRetCode;
}
catch(...) {
return 147;
}
}
initially I thought this issue is caused due to the MFC which accompanies VS2012. I noticed however that our development version just before the move has the same affect. This seems strange enough because the previous version has the same code and it finds the entry point just fine.
I was able to start the program by doing the following:
// prog.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
using namespace std;
class MyApp : public CWinApp {
public:
MyApp() : CWinApp(_T("VCP")){}
int init(LPTSTR CommandLine);
virtual int Run()
{
return init(m_lpCmdLine);
}
};
MyApp theApp;
//int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
int MyApp::init(LPTSTR CommandLine)
{
int argc = 2;
TCHAR* argv[] = {_T(""),_T("")};
argv[1]= CommandLine;
try {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
int nRetCode = 0;
// initialize MFC and print and error on failure
int r=1;
if (r>1)//(!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
nRetCode = 1;
}
else
{
// some propietry code
}
return nRetCode;
}
catch(...) {
return 147;
}
}
To summarize I have 3 versions of code. a release version of code which works just fine. Two development version on different Visual studios which have the same affect of not finding the entry point. a fresh mfc project contains code similar to the faulty code and it finds the _tmain.
My questions are :
Why is this happening?
How can I run with _tmain?
Your original code can only work if the EXE is linked as a console mode app. Pretty unusual for MFC apps, but it is supported. Getting MFC initialized with a call AfxWinInit() is indeed required.
But clearly your EXE isn't being linked as a console mode app or your 2nd snippet would not work. Which relies on the WinMain() implementation embedded inside MFC. The normal way that MFC apps are done.
Linker + System, SubSystem setting. It needs to be set to "Console" if a console mode app is indeed intended and you want your own main() function to be the entrypoint.
Related
I am trying to implement a C++ wrapper alongside my C project.
So, for example, I have "window.h" which has the standard C include guard. It requires <stdlib.h> and <string.h> as well as some third party library includes.
Then, I have "window.hpp" which depends on "window.h", but uses C++ #pragma once and requires <cstdlib> and <string> for the C++ implementations.
I am running into an ambiguity issue where the C/C++ standard implementations are conflicting, and I'm not quite sure what to do about it. You can see I tried to fix this by simply checking if __cplusplus was defined, and only adding the C++ headers if that's the case.
The idea is that you can just do using namespace LittleEngine::utils; and it will include SDL and GLEW for you, as well as add some wrapper features for creating a window, for example; where it uses C++ features like classes instead of the C implemented methods.
For sanity's sake, that's why these are separate files and not just one header file that adds compatibility for both C and C++ with extern "C" { ... }.
"window.h"
#if __cplusplus
#pragma once
#endif
#ifndef LITTLE_ENGINE_UTILS_WINDOW_H_
#define LITTLE_ENGINE_UTILS_WINDOW_H_
#include <SDL2/SDL.h>
#include <GL/glew.h>
#if __cplusplus
# include <cstdio>
# include <string>
#else
# include <stdio.h>
# include <string.h>
#endif
typedef struct {
SDL_Window* window;
SDL_GLContext context;
SDL_Event event;
} Engine_GLWindow_t;
enum Engine_Window_Renderer {
VULKAN,
OPENGL
};
int Engine_CreateGLWindow(const char* title, Engine_GLWindow_t* window)
{
// Initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
fprintf(stderr, "Failed to initialize SDL.\n");
fprintf(stderr, "%s\n", SDL_GetError());
return -1;
}
// Configure window flags
Uint32 flags = 0;
flags |= SDL_WINDOW_OPENGL;
SDL_Window* sdlwin = SDL_CreateWindow(
title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800,
600,
flags
);
if(!sdlwin)
return -1;
window->window = sdlwin;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetSwapInterval(1);
SDL_GLContext context;
if((context = SDL_GL_CreateContext(window->window)) != NULL)
window->context = context;
else
{
SDL_DestroyWindow(window->window);
fprintf(stderr, "Failed to initialize the GL context.\n");
fprintf(stderr, "%s\n", SDL_GetError());
return -1;
}
glewExperimental = GL_TRUE;
GLenum glewCode = glewInit();
if(glewCode != GLEW_OK)
{
SDL_GL_DeleteContext(window->context);
SDL_DestroyWindow(window->window);
fprintf(stderr, "Failed to initialize GLEW.\n");
fprintf(stderr, "%s\n", glewGetErrorString(glewCode));
return -1;
}
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, 800, 600);
SDL_ShowWindow(sdlwin);
return 0;
}
int Engine_DestroyGLWindow(Engine_GLWindow_t* window)
{
SDL_GL_DeleteContext(window->context);
SDL_DestroyWindow(window->window);
SDL_Quit();
return 0;
}
#endif
"windows.hpp"
#pragma once
/*
file included as:
engine.hpp
...
namespace LittleEngine {
namespace utils {
# include "utils.hpp" // -> #include "windows.hpp"
}
}
*/
#include "window.h"
#include <cstdint>
class GLWindow {
public:
GLWindow(std::string title)
{
Engine_CreateGLWindow(title.c_str(), &this->window_data);
}
GLWindow(std::string title, bool& success)
{
if(Engine_CreateGLWindow(title.c_str(), &this->window_data) == 0)
success = true;
}
~GLWindow()
{
Engine_DestroyGLWindow(&this->window_data);
}
Engine_GLWindow_t* getWindowData()
{
return &this->window_data;
}
protected:
Engine_GLWindow_t window_data;
};
main.cpp
#include <LittleEngine/engine.hpp>
int main(int argc, char* argv[], char* envp[])
{
// COMMENTED CODE WORKS BTW
// Engine_GLWindow_t window;
// Engine_CreateGLWindow("LittleBird", &window);
LittleEngine::utils::GLWindow window("LittleBird");
bool should_run = true;
const LittleEngine::utils::Uint8* keys = nullptr;
while (should_run)
{
while (LittleEngine::utils::SDL_PollEvent(&window.getWindowData()->event))
if (window.getWindowData()->event.type == LittleEngine::utils::SDL_QUIT)
should_run = false;
// ensure that SDL2 updated the keyboard state
LittleEngine::utils::SDL_PumpEvents();
// // automatically update window size
// UpdateWindowSize(&window);
// SDL2 should automatically clear this memory after each loop
keys = LittleEngine::utils::SDL_GetKeyboardState(0);
// black background color
LittleEngine::utils::glClearColor(0.00f, 0.00f, 0.00f, 1.00f);
// red background color if pressing W
if(keys[LittleEngine::utils::SDL_SCANCODE_W])
LittleEngine::utils::glClearColor(1.00f, 0.00f, 0.00f, 1.00f);
LittleEngine::utils::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LittleEngine::utils::SDL_GL_SwapWindow(window.getWindowData()->window);
}
return 0;
}
So after some more testing, the answer to my problem was that you have to wrap C header files in extern "C" before trying to include them into namespaces.
namespace LittleEngine {
namespace utils {
extern "C" {
# include "window.h"
}
# include "window.hpp"
}
}
However, even when doing this, it still puts the C-defines at the root namespace, which makes sense I guess.
Edit: Moreover, it does get a lot weirder than just that. In the above example, I can extern-C include the "window.h" file. The second I hop to another file and try to chain impl. this, I get the same error I started out with. TLDR; TIL only C++ includes go in namespaces.
Edit 2: I think it was just GLEW and SDL causing the issue. I hate programming. Why do I do this to myself?
Edit 3: After even more testing.. I think it was. So the biggest changes I made when refactoring is
Not including headers in sub-header files. You can do this because of how the Linker works.
I took out all the extern "C" because all that should theoretically do is disable C++ name wrangling, which doesn't make sense anyway.
I simply moved the SDL and GLEW includes out of scope of the namespace and suddenly it works.
Either way, my point still stands. Don't include C headers in C++ namespaces.
If somebody else wants to answer this in a preferably more detailed manner, I would be happy to mark that as the answer.
I created an MFC project in Visual Studio and tried to run it but it got the error as shown in the picture.
this is the code:
#include "pch.h" #include "framework.h" #include "MFCApplication1.h"
#include "ChildFrm.h"
#ifdef _DEBUG #define new DEBUG_NEW #endif
// CChildFrame
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWndEx)
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWndEx)
ON_COMMAND(ID_FILE_PRINT, &CChildFrame::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CChildFrame::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CChildFrame::OnFilePrintPreview)
ON_UPDATE_COMMAND_UI(ID_FILE_PRINT_PREVIEW, &CChildFrame::OnUpdateFilePrintPreview) END_MESSAGE_MAP()
// CChildFrame construction/destruction
CChildFrame::CChildFrame() noexcept { // TODO: add member initialization code here }
CChildFrame::~CChildFrame() { }
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying the CREATESTRUCT cs if( !CMDIChildWndEx::PreCreateWindow(cs) ) return FALSE;
cs.style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | FWS_ADDTOTITLE | WS_THICKFRAME;
return TRUE; }
// CChildFrame diagnostics
#ifdef _DEBUG void CChildFrame::AssertValid() const { CMDIChildWndEx::AssertValid(); }
void CChildFrame::Dump(CDumpContext& dc) const {
CMDIChildWndEx::Dump(dc); } #endif //_DEBUG
// CChildFrame message handlers
void CChildFrame::OnFilePrint() { if (m_dockManager.IsPrintPreviewValid()) { PostMessage(WM_COMMAND, AFX_ID_PREVIEW_PRINT); } }
void CChildFrame::OnFilePrintPreview() { if (m_dockManager.IsPrintPreviewValid()) { PostMessage(WM_COMMAND, AFX_ID_PREVIEW_CLOSE); // force Print Preview mode closed } }
void CChildFrame::OnUpdateFilePrintPreview(CCmdUI* pCmdUI) {
pCmdUI->SetCheck(m_dockManager.IsPrintPreviewValid()); }
An error dialog appears
[ Unable to start program C:\Users\PC\Desktop\WindownsProject1\Debug\MFCApplication1.exe'. The system cannot find the file specified.]
[1]: https://i.stack.imgur.com/hvCiX.png [2]: https://i.stack.imgur.com/Kib9c.jpg
The program fails to build, so the executable is not created. That's why it can't be started.
From your screenshots it appears that you don't have MFC installed as part of visual studio. So you should launch visual studio installer and install the MFC component, then try again.
Im trying to implement a DLL which displays a non modal QT window, when you call the exported "OpenUI()" function. The "Access violation reading location ..." occurs when the "OpenUI()" function is called a second time, after closing it the first time. To understand what exactly im doing, please look into the short code below.
Im building the DLL with VS Community 2017 Version 15.9.14, Qt VS Tools 2.3.2 and Qt for MSVC 5.13.0.
For now the window shall show only a QWidgetList with items and a QLabel, both with QVBoxLayout. The QLabel is commented out, because it seems, that it doesnt have any impact on the Exception. When no items are inserted into the QWidgetList, then no Exception will occur (first #if to 0). The second possibility to prevent the Exception is, when i dont use any layout (second #if to 0).
#include <iostream>
#include <Windows.h>
#include <QApplication>
#include <QLabel>
#include <QListWidget>
#include <QVBoxLayout>
#include <QWidget>
using namespace std;
inline void operator<(int, ostream& s) { s << endl; }
#define TO_COUT 17 < cout
#define LOG_I TO_COUT
#define DLLEXPORT __declspec(dllexport)
#define C_DLLEXPORT extern "C" DLLEXPORT
HANDLE hWorker = NULL;
DWORD dwWorkerId = 0;
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
LOG_I << "WorkerThread()";
int argc = 0;
char *argv[1];
QApplication app(argc, argv);
//QLabel* label = new QLabel("Choose:");
QListWidget* list = new QListWidget;
#if 1
new QListWidgetItem("a", list);
new QListWidgetItem("b", list);
new QListWidgetItem("c", list);
#endif
#if 1
QVBoxLayout* someLayout = new QVBoxLayout;
//someLayout->addWidget(label);
someLayout->addWidget(list);
QWidget* widget = new QWidget;
widget->setLayout(someLayout);
widget->show();
#else
list->show();
#endif
int ret = app.exec();
LOG_I << "ret: " << ret;
return 0;
}
C_DLLEXPORT UINT32 OpenUI()
{
LOG_I << "OpenUI()";
hWorker = CreateThread(NULL, 0, WorkerThread, 0, 0, &dwWorkerId);
//WaitForSingleObject(hWorker, INFINITE);
//CloseHandle(hWorker);
//hWorker = NULL;
return 0;
}
Question: Is the code missing anything basically?
Trying to run a simple MFC App but closes because the program terminates, assuming I need to run the dialog box in a seperate thread but can't work out how.
Here's the code so far:
CWinApp theApp;
using namespace std;
int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
theApp.InitApplication();
theApp.InitInstance();
theApp.Run();
AfxWinTerm();
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
MyDialog *mdlg = new MyDialog();
mdlg->Create( IDD_MDLG, theApp.m_pMainWnd);
mdlg->ShowWindow( true );
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
There must be something simple I can do to keep the program from terminating, just not sure how?
Instead of calling:
mdlg->ShowWindow( true );
you should do:
mdlg->DoModal();
Also, I dont think you need Create. If you want to stay with modeless dialog, then you should create message loop before returning from main - something like here http://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows
As far as I can see you created a Win32 Console Application and try to add a GUI to it? You should only do that if you really need the console. If not, then better create a new project, select the MFC Application template and choose dialog based application. The wizard will create all you need.
BTW, your
MyDialog *mdlg = new MyDialog();
mdlg->Create( IDD_MDLG, theApp.m_pMainWnd);
mdlg->ShowWindow( true );
should better have been:
MyDialog mdlg;
mdlg.DoModal();
No need for new in your case, so just allocate the object on the stack. And DoModal does what you want.
In my Win32 Console Application with MFC support I was able to show a dialog. But in my wizard generated code these lines were not present, so maybe you should delete them:
theApp.InitApplication();
theApp.InitInstance();
theApp.Run();
AfxWinTerm();
Why does the following program crash?
#include <QApplication>
#include <windows.h>
#include <QFrame>
uint MSGFLT_ADD = 1;
uint WM_COPYGLOBALDATA = 0x0049;
int main(int argc, char *argv[])
{
BOOL (*ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
HINSTANCE hDLL = LoadLibraryA("User32.dll"); // Handle to DLL
if (hDLL != NULL){
ChangeWindowMessageFilter = (BOOL (*)(UINT,DWORD))GetProcAddress(hDLL, "ChangeWindowMessageFilter");
}
if (ChangeWindowMessageFilter != NULL){
if (!(*ChangeWindowMessageFilter)(WM_DROPFILES, MSGFLT_ADD)){
printf("Failed to add exception for WM_DROPFILES\n");
}
if (!(*ChangeWindowMessageFilter)(WM_COPYDATA, MSGFLT_ADD)){
printf("Failed to add exception for WM_COPYDATA");
}
if (!(*ChangeWindowMessageFilter)(WM_COPYGLOBALDATA, MSGFLT_ADD)){
printf("Failed to add exception for WM_COPYGLOBALDATA");
}
printf("Added filters\n");
fflush(0);
}
if (hDLL != NULL){
FreeLibrary(hDLL);
}
QApplication a(argc, argv);
QFrame w; //debug crashes here
w.show();
return a.exec();
}
QFrame::QFrame(QWidget* parent, Qt::WindowFlags f)
: QWidget(*new QFramePrivate, parent, f) //on this line in particular
{
Q_D(QFrame);
d->init();
}
EDIT:
if (!(*ChangeWindowMessageFilter)(WM_COPYDATA, MSGFLT_ADD)){ //if i disable this everything works
printf("Failed to add exception for WM_COPYDATA");
}
BOOL (*ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
Your function pointer declaration is wrong. Winapi functions are always __stdcall. Your compiler no doubt uses the default, __cdecl. The stack imbalance you get when you make the call through the function pointer can have many side effects. If you use MSVC++ and run the Debug build then you'll always get an immediate diagnostic. Fix:
BOOL (WINAPI * ChangeWindowMessageFilter)(UINT,DWORD) = NULL;
Fwiw, if this is meant to enable drag+drop into an elevated program then just remove all this, it won't work. D+D is COM based, it doesn't use messages.