Click here to Skip to main content
11,412,578 members (74,419 online)
Click here to Skip to main content

A Simple Way to Pack your .NET Code into a Single Executable

, 19 Feb 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
C# and C++ source code for .NET application packer tool

Introduction

Applications built for .NET tend to be composed of a large number of assemblies and it's not a secret that .NET code can be easily decompiled using dissasemblers. It might be useful to pack all application assemblies into a single native executable, thus reducing application size and providing some degree of code protection. In this article, we'll look into a simple way of creating a .NET application packer tool. The complete source code and documentation of the tool is free to download at the Cellbi Web site.

Native Executable Template

First of all, we need to create a native executable, which we will use as a container for a target .NET application. We'll use C++ language for this purpose.

Since our template is a native application, we'll need to start .NET runtime manually from our code, then create a default AppDomain and then load our assemblies there. Only after that, it's OK to transfer execution to the managed code. Let's define the NativeLauncher class to handle this.

Here is the NativeLauncher definition:

class NativeLauncher
{
public:
  NativeLauncher();
  int Launch(LPWSTR runtime, LPTSTR cmdLine);
};

NativeLauncher class contains only one method: Launch, it has two parameters runtime - to specify target .NET runtime version, and cmdLine - command line string passed.

Below is the code for the main method of our executable template:

#define NET11 L"v1.1.4322";

HINSTANCE hInst;

int APIENTRY _tWinMain(HINSTANCE hInstance, 
    HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
  hInst = hInstance;

  LPWSTR runtime = NET11;

  NativeLauncher* launcher = new NativeLauncher();
  int result = launcher->Launch(runtime, lpCmdLine);
  delete launcher;
  launcher = NULL;
  return result;
}

We just create an NativeLauncher instance and call its Launch method, passing .NET runtime version and command line string.

Starting .NET Runtime

To start .NET runtime from NativeLauncher, we will use the CorBindToRuntimeEx function available from the mscorlib.tlb library. This function will bind to the specified .NET runtime and return a pointer to the ICorRuntimeHost interface. ICorRuntimeHost interface exposes the Start method, which we will use to start the .NET runtime.

Below is the sample code:

  CComPtr<ICorRuntimeHost> pHost;
  HRESULT hr = CorBindToRuntimeEx(runtime, 
      NULL, 
      NULL,
      CLSID_CorRuntimeHost, 
      IID_ICorRuntimeHost, 
      (void **)&pHost);
  if (FAILED(hr))
    return hr;

Note that CLSID_CorRuntimeHost, IID_ICorRuntimeHost are defined in the mscorlib.tlb library.

In order to use the CorBindToRuntimeEx function, we need to import the mscorlib.tlb library. Here is how to do this:

#import <mscorlib.tlb> raw_interfaces_only

using namespace mscorlib;

Loading .NET Assemblies

Once we started the .NET runtime host, it is fine to load any .NET assembly into the default AddDomain and then execute our managed code. ICorRuntimeHost interface has the GetDefaultDomain method which can be used to obtain a pointer to the default AppDomain.

Below is the code illustrating this:

  CComPtr<IUnknown> pUnk;
  hr = pHost->GetDefaultDomain(&pUnk);
  if (FAILED(hr))
    return hr;

  CComPtr<_AppDomain> appDomain;
  hr = pUnk->QueryInterface(&appDomain.p);
  if (FAILED(hr))
    return hr;

Now we can load the .NET assembly into the default AppDomain using any of the Load methods exposed by _AppDomain.

Here is the code:

  CComSafeArray<unsigned char> *rawAssembly = new CComSafeArray<unsigned char>();
  rawAssembly->Add(packerApiLibLength, packerApiLib);

  CComPtr<_Assembly> assembly;
  hr = appDomain->Load_3(*rawAssembly, &assembly);
  if (FAILED(hr))
    return hr;

At the code above, we load our assembly from an array or bytes. The array is stored in the packerApiLib variable.

Executing Managed Code

The next step is to create a .NET class and obtain its pointer. This is easy to do via the CreateInstance method exposed by the _Assembly interface. We just pass the full name of the class to create a pointer to result value:

  CComVariant launcher;
  hr = assembly->CreateInstance(_bstr_t("Cellbi.AppPacker.Api.NetLauncher"), &launcher);
  if (FAILED(hr))
    return hr;

  if (launcher.vt != VT_DISPATCH)
    return E_FAIL;

We use CComVariant to store the pointer to newly created managed instance.

Ok, it's now time to call methods defined on the created instance, but we need to find the right method first:

  CComPtr<IDispatch> disp = launcher.pdispVal;
  DISPID dispid;
  OLECHAR FAR* methodName = L"Launch";
  hr = disp->GetIDsOfNames(IID_NULL, &methodName, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
  if (FAILED(hr))
    return hr;

And now we call the method found. The Invoke method defined on the IDispatch interface does this:

  TCHAR szPath[MAX_PATH];
  if (!GetModuleFileName(NULL, szPath, MAX_PATH))
    return E_FAIL;

  CComVariant *path = new CComVariant(szPath);
  CComVariant *cmdLineArg = new CComVariant(cmdLine);
  CComVariant FAR args[] = {*cmdLineArg, *path};
  DISPPARAMS noArgs = {args, NULL, 2, 0};
  hr = disp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, 
    &noArgs, NULL, NULL, NULL);
  if (FAILED(hr))
    return hr;

After the method is executed, we need to stop the .NET runtime:

  hr = pHost->Stop();
  if (FAILED(hr))
    return hr;

That's all, I hope this article will be useful. Please let me know if there are any problems.

In this article, we didn't cover managed code used to pack .NET assemblies into the native executable template. The complete source code can be obtained at Cellbi.AppPacker.

History

  • December 5th, 2007 : Initial release
  • February 19th, 2008 : 1.0.0.20 build - Runtime version support added

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

SteveLi-Cellbi
Web Developer
United States United States
I'm excited about computers and programming, since my school days. I have master's degree in software development and at the moment I'm a software developer at Cellbi Software.

Comments and Discussions

 
Questionhelp Pin
arby77 at 4-Oct-13 9:05
memberarby774-Oct-13 9:05 
GeneralThanks , and one question Pin
_Armen at 19-Aug-09 23:16
member_Armen19-Aug-09 23:16 
GeneralRe: Thanks , and one question Pin
_Armen at 20-Aug-09 2:45
member_Armen20-Aug-09 2:45 
General.NET 3.5 not working Pin
battlemodetwo at 11-May-09 19:59
memberbattlemodetwo11-May-09 19:59 
GeneralRe: .NET 3.5 not working Pin
cdengler at 18-May-09 13:16
membercdengler18-May-09 13:16 
GeneralSmall Problem Pin
mk20 at 28-Mar-08 12:33
membermk2028-Mar-08 12:33 
GeneralRe: Small Problem Pin
SteveLi-Cellbi at 1-Apr-08 11:23
memberSteveLi-Cellbi1-Apr-08 11:23 
GeneralGood work, but... Pin
MFaithful at 12-Mar-08 7:20
memberMFaithful12-Mar-08 7:20 
GeneralRe: Good work, but... Pin
SteveLi-Cellbi at 12-Mar-08 8:51
memberSteveLi-Cellbi12-Mar-08 8:51 
GeneralRe: Good work, but... Pin
MFaithful at 12-Mar-08 23:44
memberMFaithful12-Mar-08 23:44 
GeneralRe: Good work, but... Pin
JohnDev at 6-Apr-09 8:50
memberJohnDev6-Apr-09 8:50 
GeneralCustomizing the Microsoft dot NET Framework CLR Pin
Bill Seddon at 25-Feb-08 14:37
memberBill Seddon25-Feb-08 14:37 
GeneralGreat Idea Pin
merlin981 at 20-Feb-08 5:29
membermerlin98120-Feb-08 5:29 
GeneralRe: Great Idea Pin
SteveLi-Cellbi at 20-Feb-08 10:46
memberSteveLi-Cellbi20-Feb-08 10:46 
GeneralThe application Icon disappear Pin
ksboy at 19-Feb-08 17:49
memberksboy19-Feb-08 17:49 
GeneralRe: The application Icon disappear Pin
SteveLi-Cellbi at 20-Feb-08 10:36
memberSteveLi-Cellbi20-Feb-08 10:36 
GeneralNot working Pin
tonyt at 18-Dec-07 10:57
membertonyt18-Dec-07 10:57 
GeneralRe: Not working Pin
SteveLi-Cellbi at 19-Dec-07 7:19
memberSteveLi-Cellbi19-Dec-07 7:19 
GeneralTarget native DLL rather than EXE Pin
tonyt at 18-Dec-07 0:13
membertonyt18-Dec-07 0:13 
GeneralRe: Target native DLL rather than EXE Pin
SteveLi-Cellbi at 19-Dec-07 7:21
memberSteveLi-Cellbi19-Dec-07 7:21 
GeneralAppPacker project does not build on VC2005 Pin
tonyt at 18-Dec-07 0:05
membertonyt18-Dec-07 0:05 
QuestionIs this just for Desktop Apps? Pin
Dewey at 16-Dec-07 12:29
memberDewey16-Dec-07 12:29 
AnswerRe: Is this just for Desktop Apps? Pin
SteveLi-Cellbi at 17-Dec-07 7:03
memberSteveLi-Cellbi17-Dec-07 7:03 
General.NET 3.0 / 3.5 Pin
DomiOh at 13-Dec-07 10:14
memberDomiOh13-Dec-07 10:14 
GeneralRe: .NET 3.0 / 3.5 Pin
SteveLi-Cellbi at 16-Dec-07 8:00
memberSteveLi-Cellbi16-Dec-07 8:00 
GeneralRe: .NET 3.0 / 3.5 Pin
DomiOh at 7-Jan-08 12:29
memberDomiOh7-Jan-08 12:29 
GeneralRe: .NET 3.0 / 3.5 Pin
SteveLi-Cellbi at 7-Jan-08 12:50
memberSteveLi-Cellbi7-Jan-08 12:50 
GeneralRe: .NET 3.0 / 3.5 Pin
DomiOh at 7-Jan-08 20:23
memberDomiOh7-Jan-08 20:23 
GeneralRe: .NET 3.0 / 3.5 Pin
SteveLi-Cellbi at 19-Feb-08 13:27
memberSteveLi-Cellbi19-Feb-08 13:27 
GeneralRe: .NET 3.0 / 3.5 Pin
Ri Qen-Sin at 22-Feb-09 15:21
memberRi Qen-Sin22-Feb-09 15:21 
Generalobservation Pin
merovingian18 at 13-Dec-07 5:06
membermerovingian1813-Dec-07 5:06 
GeneralRe: observation Pin
SteveLi-Cellbi at 16-Dec-07 8:03
memberSteveLi-Cellbi16-Dec-07 8:03 
QuestionProblems? Pin
jung-kreidler at 12-Dec-07 23:40
memberjung-kreidler12-Dec-07 23:40 
AnswerRe: Problems? Pin
Member 4352778 at 13-Dec-07 0:39
memberMember 435277813-Dec-07 0:39 
GeneralRe: Problems? Pin
SteveLi-Cellbi at 16-Dec-07 8:07
memberSteveLi-Cellbi16-Dec-07 8:07 
AnswerRe: Problems? Pin
SteveLi-Cellbi at 16-Dec-07 8:06
memberSteveLi-Cellbi16-Dec-07 8:06 
AnswerRe: Problems? Pin
SteveLi-Cellbi at 19-Feb-08 13:24
memberSteveLi-Cellbi19-Feb-08 13:24 
GeneralRe: Problems? Pin
jung-kreidler at 20-Feb-08 5:44
memberjung-kreidler20-Feb-08 5:44 
GeneralRe: Problems? Pin
Tuakisan at 9-Mar-08 9:32
memberTuakisan9-Mar-08 9:32 
GeneralRe: Problems? Pin
SteveLi-Cellbi at 12-Mar-08 8:48
memberSteveLi-Cellbi12-Mar-08 8:48 
GeneralVery neat trick BUT link to Cellbi.AppPacker is Not working Pin
AnandChavali at 6-Dec-07 17:21
memberAnandChavali6-Dec-07 17:21 
GeneralRe: Very neat trick BUT link to Cellbi.AppPacker is Not working Pin
SteveLi-Cellbi at 6-Dec-07 18:42
memberSteveLi-Cellbi6-Dec-07 18:42 
GeneralVery cool Pin
Patrick Sears at 6-Dec-07 10:23
memberPatrick Sears6-Dec-07 10:23 
GeneralGood trick but.. Pin
Nathan Evans at 6-Dec-07 10:07
memberNathan Evans6-Dec-07 10:07 
GeneralRe: Good trick but.. Pin
The JZ at 7-Dec-07 6:43
memberThe JZ7-Dec-07 6:43 
GeneralRe: Good trick but.. Pin
pikipoki at 8-Dec-07 7:42
memberpikipoki8-Dec-07 7:42 
GeneralRe: Good trick but.. Pin
stixoffire at 12-Dec-07 21:19
memberstixoffire12-Dec-07 21:19 
GeneralNeat Trick Pin
Ri Qen-Sin at 6-Dec-07 8:32
memberRi Qen-Sin6-Dec-07 8:32 
GeneralRe: Neat Trick Pin
SteveLi-Cellbi at 6-Dec-07 8:41
memberSteveLi-Cellbi6-Dec-07 8:41 
GeneralRe: Neat Trick Pin
ti-oh at 21-Dec-07 18:17
memberti-oh21-Dec-07 18:17 
yeah, this is trully interesting...

considering its bye2x to third-party softwares that can do .NET abstraction...

looking forward to using this...
think fast, be brave and dont stop.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150427.1 | Last Updated 19 Feb 2008
Article Copyright 2007 by SteveLi-Cellbi
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid