0

I've read more than a dozen pages explaining how to convert a Win32 console application into a Windows application that will run without briefly opening and closing a console window, but I'm too much of a beginner to get it to work.

For example, in VC2010 I made the two changes in the project properties described here:

convert a console app to a windows app

and changed Main to WinMain but of course got error messages from the compiler.

Following other pages, I also tried creating a console application, then, in the Win32 Application Wizard, and changing the Application Type to a Windows application, but I can't figure out what to do next. I've tried changing int Main to int CALLBACK WinMain, but of course that doesn't work either.

Is there anyone who can help a beginner with this? Here is what I think is the relevant part of my code EDIT: the complete code, for anyone who wonders what this is for, is here:

https://www.dropbox.com/s/1h8x1k2zv0lc5d1/vPasteCPlus.txt?dl=0

#include <stdafx.h>
#include <windows.h>
#include <iostream>
#include <fstream>
#include <codecvt> // for wstring_convert
#include <locale>  // for codecvt_byname
using namespace std;

// helper to get path to this application
string ExePath() {
char buffer[MAX_PATH];
GetModuleFileNameA( NULL, buffer, MAX_PATH );
string::size_type pos = string( buffer ).find_last_of( "\\/" );
return string( buffer ).substr( 0, pos);
}

int main(int argc, char* argv[])
{
    // get the command-line argument if any, and do various things
} 

Again, apologies for this beginner question. The only experience I have with C++ is writing console applications, and any advice will be gratefully received.

Community
  • 1
  • 1
emendelson
  • 416
  • 5
  • 18
  • "application that will run without briefly opening and closing a console window". I understand that there are thousands of legitimate uses for this... but I can't help but wonder... – RyanP Jun 30 '15 at 15:01
  • `and changed Main to WinMain but of course got error messages from the compiler.` What are the errors? Also, you could have started with a Windows application and don't create any windows. – PaulMcKenzie Jun 30 '15 at 15:05
  • Alternatively, you can use [this program](http://www.commandline.co.uk/chp/) to launch your console program using a hidden window. – memo1288 Jun 30 '15 at 15:36

2 Answers2

1

Ok, so you have opened Visual Studio. And you have Solution Explorer (If not, View -> Solution Explorer).

First of all, to make Windows application, you should change entry point from main() (C++ standard) to Windows-specific WinMain(). See msdn for more detailed description. So, you are changing main() to next one (copy-paste from documentation):

int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow)
{
    return 0;
}

Of course, you should include <Windows.h>, because Windows provides it own API for working with system (such as LPSTR type). In a nutshell, you did all that compiler need to compile your program. And you can build your solution (Build -> Build Solution)... This will lead to linker error:

error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup

Again, compiler did everything you want and compiles your source file into .obj, but, because, your project is configured for Console application, linker needs standard entry point for Console application - main and it can't found (resolve) it in our case, because we changed main to WinMain. To make linker happy, you should tell it:

  • Right click on project inside Solution Explorer
  • Then click on Properties: Solution Explorer Properties
  • Go to Configuration Properties -> Linker -> System and set SubSystem to Windows: Linker's SubSystem configuration

Try to build your application again and voila - you have no linker error already because your linker knows now that it need to produce Windows application and found Windows entry point: WinMain() !

About this one:

// get the command-line argument if any, and do various things

you should use lpCmdLine parameter of WinMain(). But be carefully, if you run your program (so.exe, for example) like this one:

so.exe arg1 arg2

lpCmdLine is arg1 arg2 string. There is a lot of stuff of what you can do to get arg1 and arg2 asn an array like in main() argv (with argc), but you can explore:

and relative stuff (such as wchar_t on Windows)

grisha
  • 1,247
  • 1
  • 14
  • 20
  • Apologies for taking so long to reply. I've lost my cable connection here in rural USA and am connecting to the internet through my phone. Will experiment with this very helpful answer and report back. Meanwhile, for anyone who is doubtful about my reasons for doing this, I've edited the original question to include a link to the full code. (It writes the current clipboard contents to a text file in a user-specified code page for use in old DOS applications running under the vDos emulator.) – emendelson Jun 30 '15 at 16:07
  • Thank you! Your extremely clear instructions let me build and run the program successfully. I had to comment out the lines that process the command line argument, and will now look up the technique of getting the arguments into an array. You were exceptionally generous with your time and trouble. – emendelson Jun 30 '15 at 16:24
  • **–1** “you should change entry point from main() (C++ standard) to Windows-specific WinMain()” is ungood advice. It does not great harm but it's a needless Microsoft-ism, and the terminology (entry point) is extremely misleading. Likewise, the “Of course, you should include ”, although quite a bit more likely to do harm, is not *very* harmful, but it's needless complexity, it serves no purpose. – Cheers and hth. - Alf Jun 30 '15 at 16:30
  • This program will only run under Windows because it's designed to work with a Windows-only DOS emulator called vDos. In my original question, I specified that it was for a Win32 application. – emendelson Jun 30 '15 at 17:06
  • 1
    @Cheersandhth.-Alf, hm, I tried to emphasize that this code will no longer portable. `it's a needless Microsoft-ism`, of course - we are talking about writing application for Windows only. By the way, your answer is more misleading, IMHO. – grisha Jun 30 '15 at 18:43
  • @user2451677: There is negative utility in using Microsoft-specific code where standard code will do. LIkewise, there is negative utility in using Microsoft-specific code where no code is needed. I have no idea what you mean by my answer being misleading, if you meant that seriously. I.e. if that's not just a childish allegation. I might help educate you if you would just be more clear & concrete about that. – Cheers and hth. - Alf Jun 30 '15 at 20:58
  • @Cheersandhth.-Alf, thank you for trying to clarify some moments. My answer is for really beginner, in short form. And this mean there are inaccuracies. About your answer, I just think that changing entry point is more tricky for beginner, then just saying "_OK, you want Windows application, please play by the rules of Windows_". Btw, thank you for your answers on SO - they are really clean and professional – grisha Jul 01 '15 at 08:06
0

If this is a Visual Studio project (as the <stdafx.h> strongly indicates) then:

  • Set the subsystem to Windows in the linker settings.
  • Set the entry point to mainCRTStartup (which calls standard main).

But are you sure that you want this?

It sounds more that what you want is a Windows service?

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331