3

I wrote a c++ program and I want to execute my second program inside it, which is a exe file. The problem is I want to share my program to others as one single file.

When I search on the internet, I found this solution.

Just store the second .exe file as a binary resource inside the main .exe using an .rc file at compile-time. At run-time, you can access it using FindResource(), LoadResource(), and LockResource(), and then write it out to a temp file on disk before passing it to system().

But I don't understand how to "store the .exe file as a binary resource"

I am currently using CreateProcess() to start my second program which working greatly. Can anyone write some example for me?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Jason Lam
  • 43
  • 1
  • 6
  • Storing it should not be different from storing any other binary resource. You will likely need to extract the file to some place on your hard drive to use it however. – drescherjm Jun 15 '20 at 15:19
  • 1
    Are you using Visual Studio? Do you have a resource script (`.rc` file) in your project? Do you understand how to use the resource editor? We need more info if we are to properly offer helpful solutions. – Adrian Mole Jun 15 '20 at 15:20
  • @drescherjm Hello, thanks for your help. So I can just rename the .exe into .rc?.. – Jason Lam Jun 15 '20 at 15:21
  • ***So I can just rename the .exe into .rc?*** No but in your .rc file you can add the binary resource. – drescherjm Jun 15 '20 at 15:23
  • @AdrianMole Hi, I am using Cygwin since I use some Linux library in my program. I have no clue how to use the resource editor. – Jason Lam Jun 15 '20 at 15:23
  • I can't help with cygwin. – drescherjm Jun 15 '20 at 15:23
  • Maybe you just want to use an installer program like nsis to package your files in a single executable. [https://nsis.sourceforge.io/Main_Page](https://nsis.sourceforge.io/Main_Page) – drescherjm Jun 15 '20 at 15:25
  • Is there a file or files with an `.rc` or `.rc2` extension anywhere in your project? (I also don't use Cygwin, but if there's a resource script, it can be edited to include a binary resource.) – Adrian Mole Jun 15 '20 at 15:25
  • @AdrianMole I use an .rc file to add an icon for my program. I need to compile the .rc file to .res file first then I compile the .res with my main program. – Jason Lam Jun 15 '20 at 15:27

1 Answers1

6

In your project's resource script (the .rc file in which icons, dialogs, etc. are defined), you can add a binary resource with a line like the following:

IDB_EMBEDEXE    BINARY      "<path>\\EmbedProgram.exe"

Where the IDB_EMBEDEXE token/macro should be defined in a header file that is included by both that resource script and any C++ source(s) that use(s) it; this will be the lpName argument given to the FindResource() call, which you can form using MAKEINTRESOURCE(IDB_EMBEDEXE). Specify "BINARY" (or L"BINARY" for Unicode builds) for the lpType argument.

Like this:

#define IDB_EMBEDEXE 13232 // Or whatever suitable value you need
//...
// In the C++ code:
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(IDB_EMBEDEXE), _TEXT("BINARY"));
HGLOBAL hGlobal = LoadResource(NULL, hResource);
size_t exeSiz = SizeofResource(NULL, hResource); // Size of the embedded data
void*  exeBuf = LockResource(hGlobal);           // usable pointer to that data

// You can now write the buffer to disk using "exeBuf" and "exeSiz"

The specified executable file will then be completely embedded (as a binary) resource in your built executable, and can be extracted, written to disk and executed as described in the article you quote.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Thank you very much for the answer, I am trying to understand it. – Jason Lam Jun 15 '20 at 15:49
  • By changing `RT_RCDATA` to `"BINARY"`, `FindResource()` returns a handle so it works. – Jason Lam Jun 15 '20 at 16:43
  • `MAKEINTRESOURCE(RT_RCDATA)` gives me error: cast from ‘LPSTR’ {aka ‘char*’} to ‘WORD’ {aka ‘short unsigned int’} – Jason Lam Jun 15 '20 at 16:49
  • No I was wrong when I said I was wrong! `RT_RCDATA` is already defined as `MAKINTRESOURCE(10)`. I think I need some strong drink. Stick with using the `"BINARY"` name!! – Adrian Mole Jun 15 '20 at 16:51
  • Now things become complicated. After changing `RT_RCDATA` to `"BINARY"`, the program crash when `GlobalSize(hGlobal)`. – Jason Lam Jun 15 '20 at 17:00
  • @JasonLam Yeah, of course it will (my fault, again). You can't use `GlobalSize()` here, but should use the `SizeofResource()` function (see edit). More strong drink! – Adrian Mole Jun 15 '20 at 17:05
  • @JasonLam Me wrong; you right (again)! Now I'm running out of strong drink. See edit. – Adrian Mole Jun 15 '20 at 17:13
  • Alright, everything is working like a charm. One more question, after I run the exe by `CreateProcess()`, how can I terminate it? – Jason Lam Jun 15 '20 at 17:26
  • @JasonLam That would depend on the nature of the created program. It's also probably a new question in its own right. And I have no more strong drink left. ‎ – Adrian Mole Jun 15 '20 at 17:27
  • 1
    Hi, thank you so much for your help. It runs smoothly on my Windows 10 PC. Recently, I tried the same program on a Windows 7 computer, it crashes when `WriteFile( hFile, exeBuf, exeSiz, NULL , NULL);` . How is this happening? I didn't encounter any problem on Windows 10. Thx – Jason Lam Jun 23 '20 at 11:13
  • Have you made sure your Windows 7 PC has the latest updates and relevant run-time support packages. I don't know how CygWin uses these, but it probably targets the machine you're building on. – Adrian Mole Jun 23 '20 at 11:21
  • 1
    I fixed the problem by changing `NULL` to `&at` [Reference](https://stackoverflow.com/questions/17130532/writefile-causes-crash-with-access-violation). Thank you btw – Jason Lam Jun 23 '20 at 11:57