22

I need to change the functionality of an application based on the executable name. Nothing huge, just changing strings that are displayed and some internal identifiers. The application is written in a mixture of native and .Net C++-CLI code.

Two ways that I have looked at are to parse the GetCommandLine() function in Win32 and stuffing around with the AppDomain and other things in .Net. However using GetCommandLine won't always work as when run from the debugger the command line is empty. And the .Net AppDomain stuff seems to require a lot of stuffing around.

So what is the nicest/simplest/most efficient way of determining the executable name in C++/CLI? (I'm kind of hoping that I've just missed something simple that is available in .Net.)

Edit: One thing that I should mention is that this is a Windows GUI application using C++/CLI, therefore there's no access to the traditional C style main function, it uses the Windows WinMain() function.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Dominik Grabiec
  • 10,315
  • 5
  • 39
  • 45

8 Answers8

42

Call GetModuleFileName() using 0 as a module handle.

Note: you can also use the argv[0] parameter to main or call GetCommandLine() if there is no main. However, keep in mind that these methods will not necessarily give you the complete path to the executable file. They will give back the same string of characters that was used to start the program. Calling GetModuleFileName(), instead, will always give you a complete path and file name.

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
16

Ferruccio's answer is good. Here's some example code:

TCHAR exepath[MAX_PATH+1];

if(0 == GetModuleFileName(0, exepath, MAX_PATH+1))
    MessageBox(_T("Error!"));

MessageBox(exepath, _T("My executable name"));
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
Adam Pierce
  • 33,531
  • 22
  • 69
  • 89
  • 3
    From msdn: `If the function fails, the return value is 0 (zero)` so yeah... you may want to use `==` instead of `!=` in your conditional statement – Ivan Nikolchov Jan 06 '12 at 22:24
8

Use the argv argument to main:

int main(int argc, char* argv[])
{
    printf("%s\n", argv[0]);  //argv[0] will contain the name of the app.
    return 0;
}

You may need to scan the string to remove directory information and/or extensions, but the name will be there.

nobody
  • 19,814
  • 17
  • 56
  • 77
4

Use __argv[0]

computinglife
  • 4,321
  • 1
  • 21
  • 18
  • The simpliest and the best answer. –  Oct 12 '14 at 20:14
  • Only if the program started with `main` or `WinMain`, and not `wmain`, `wWinMain`. If "w" main is entry point, then `__wargv` has to be used. The other "argv" would remain null. – Ajay Aug 30 '17 at 12:12
3

There is a static Method on Assembly that will get it for you in .NET.

Assembly.GetEntryAssembly().FullName

Edit: I didn't realize that you wanted the file name... you can also get that by calling:

Assembly.GetEntryAssembly().CodeBase

That will get you the full path to the assembly (including the file name).

Brian ONeil
  • 4,229
  • 2
  • 23
  • 25
  • While this seemed the way to go initially, it actually does not work in practice, as the assembly name is the same regardless of what the executable name gets set to. – Dominik Grabiec Sep 24 '08 at 03:43
0

I can confirm it works under win64/visual studio 2017/ MFC

TCHAR szFileName[MAX_PATH + 1];
GetModuleFileName(NULL, szFileName, MAX_PATH + 1);
auto exe = CString(szFileName);

exe contains full path to exe.

ingconti
  • 10,876
  • 3
  • 61
  • 48
0

According to MSDN:

The global variable _pgmptr is automatically initialized to the full path of the executable file, and can be used to retrieve the full path name of an executable file.

Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
0

I guess I like to make it a habit to add answers to really old questions. Let's do it again!

The very simplest way to get the current running .exe on a Windows system is to use the SDK defined global variable _pgmptr. However, it's considered "unsafe", so you use _get_pgmptr() instead.

So...

char *exe;
_get_pgmptr(&exe);
std::cout << "This executable is [" << exe << "]." << std::endl;

If you have a "wide" (UTF16) entrypoint, such as wmain or wWinMain, use this instead:

wchar_t* wexe;
_get_wpgmptr(&wexe);
std::wcout << L"This executable is [" << wexe << L"]." << std::endl;

If you really, really insist on using the simpler version, here's how to do it:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>

int main(int argc, char** argv)
{
    std::cout << "This executable is [" << _pgmptr << "]." << std::endl;
}

Just don't get yourself pwned by hax0rs!

Jamie
  • 1,754
  • 16
  • 34