Brandon - Free Palestine
Brandon - Free Palestine

Reputation: 16666

How to embed an MSI in my bootstrapper exe

I wrote a C++ installer bootstrapper for my application (hard requirement as I needed complete control over the format of the file). Now I'm trying to figure out how to embed my MSI in my bootstrap EXE with the least amount of overhead. All of my searching shows me the reverse (how to embed an EXE in an MSI).

This installer must work offline so I cannot have my bootstrapper simply download the file.

I could of course embed it as a bytestream in my source file but that caused a ton of overhead on the size of the file.

Upvotes: 1

Views: 208

Answers (1)

PhilDW
PhilDW

Reputation: 20790

It's fairly common to embed data as a resource in the binary and extract it. This kind of thing:

http://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource

http://www.codeproject.com/Articles/4221/Adding-and-extracting-binary-resources

IIRC, the compiler will embed the data at build time with the right tweaks, so you only need to extract it.

Here is an example of how to extract the data.

#include "stdafx.h"
#include "resource.h"
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
#include <Windows.h>
#include <shellapi.h>

using namespace std;

void extract_bin_resource(std::wstring strCustomResName, int nResourceId, std::string strOutputPath)
{
    HGLOBAL hResourceLoaded;   // handle to loaded resource
    HRSRC   hRes;              // handle/ptr to res. info.
    char    *lpResLock;        // pointer to resource data
    DWORD   dwSizeRes;
    std::string strOutputLocation;
    std::string strAppLocation;

    hRes = FindResource(NULL, MAKEINTRESOURCE(nResourceId), strCustomResName.c_str());

    hResourceLoaded = LoadResource(NULL, hRes);
    lpResLock = (char *)LockResource(hResourceLoaded);
    dwSizeRes = SizeofResource(NULL, hRes);

    std::ofstream outputFile(strOutputPath.c_str(), std::ios::binary);
    outputFile.write((const char *)lpResLock, dwSizeRes);
    outputFile.close();
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // Extract the bundled installer
    extract_bin_resource(L"MSI", IDR_MSI1, "installer.msi");

    // Execute the installer
    SHELLEXECUTEINFO ShExecInfo = { 0 };
    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
    ShExecInfo.hwnd = NULL;
    ShExecInfo.lpVerb = NULL;
    ShExecInfo.lpFile = L"msiexec.exe";
    ShExecInfo.lpParameters = L"/i installer.msi";
    ShExecInfo.lpDirectory = NULL;
    ShExecInfo.nShow = SW_SHOW;
    ShExecInfo.hInstApp = NULL;
    ShellExecuteEx(&ShExecInfo);
    WaitForSingleObject(ShExecInfo.hProcess, INFINITE);

    // Delete the installer
    DeleteFile(L"installer.msi");

    return 0;
}

Upvotes: 2

Related Questions