Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to embed a resource in a .NET PE executable?

How can i include a resource in a .NET PE (Portable Executable) in Visual Studio 2010?

In the olden days we would create a resource script file:

wumpa.rc:

 jqueryjs      RCDATA    "jquery.js"
 SplashLogo    PNG          "Hello world.png"
 ReportLogo    RCDATA    "ReportLogo.png"
 Users         ICON         "User XP.ico"
 Toolbar       BITMAP       "StandardToolbar24_32bpp.bmp"

Add that file to the project, and the compiler would compile the .rc file; including resources in the final executable image.

What is the managed/.NET/Visual Studio mechanism to include resources?

See also

  • MSDN: Resource Files (Visual Studio)
  • MSDN: res Protocol
  • MSDN: Using Resources in MCML
  • SO: What is res://*/ in .net?
  • creating HTML content using resx:// protocol and embedded resources
  • How to build a managed assembly that contains Win32 resources using Visual Studio 2005

These have to be standard resources; you know the kind that everyone can read as resources:

  • Resource Hacker would show as resources
  • PEView would show as resources
  • Internet Explorer can read using the res protocol (e.g. res://c:\foo\MyProgram.exe/PNG/SplashLogo)

Things i've tried that don't work:

  1. Adding resources to the Resources.resx file:

    enter image description here

  2. Adding resources to the Resources.resx file, and specifying a build action of Resource:

    enter image description here

    (also tried Build actions: Embedded Resource, as was suggested to me in 2008)


Update: What didn't work

i tried adding a file (wumpa.rc) to the project:

wumpa.rc:

SplashPNG   PNG   "Splash.png"

By default it didn't work. i tried changing the Build Action of wumpa.rc:

  • Content (the default): didn't work
  • Compile: "A namespace cannot directly contain members such as fields or methods"
  • Embedded Resource: didn't work
  • Resource: didn't work

What i get (nothing):

enter image description here

What i expect (something):

enter image description here

And then when you point Internet Explorer at the resource (using its res protocol):

res://C:\Develop\Avatar\LocaleInfo\LocaleInfo.exe\PNG\SplashPNG

IE can find it:

enter image description here

like image 838
Ian Boyd Avatar asked Nov 08 '11 21:11

Ian Boyd


2 Answers

Managed resources are embedded into assemblies in a different way from Win32 resources - the "Embedded resource" option will embed your resource into the output assembly, but not in a way that is accessible using things like the "res" protocol.

You can either use a tool to embed a Win32 into an existing resource as described here: Embed Win32 resources in C# programs (CodeProject).

Alternatively you can use the /win32res csc.exe compiler option to embed a compiled .res resource. This option is not currently exposed as an option in Visual Studio 2010 however there is a series of instructions here that explains how you can do this. You simply need to compile your resource as normal using rc.exe (e.g. as a pre-build step):

<Target Name="BeforeBuild" Inputs="my_resource_file.rc" Outputs="my_resource_file.res">
    <Exec Command="&quot;C:\Program Files\Microsoft Visual Studio 8\VC\bin\rc.exe&quot; /r my_resource_file.rc" />
</Target>

And then supply the Win32Resource property to specify the output .res file:

<Win32Resource>my_resource_file.res</Win32Resource>

Update: As an alternative you can use the RC MSBuild task as long as you don't mind editing MSBuild your .csproj file. A simple example:

<UsingTask TaskName="RC" AssemblyName="Microsoft.Build.CppTasks.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<PropertyGroup>
    <Win32Resource Condition="'$(Win32Resource)' != ''">@(ResourceCompile->'%(RelativeDir)%(filename).res')</Win32Resource>
</PropertyGroup>
<ItemGroup>
    <ResourceCompile Include="test.rc" />
</ItemGroup>
<Target Name="ResourceCompile" BeforeTargets="BeforeCompile" Condition="'@(ResourceCompile)' != ''">
    <RC Source="@(ResourceCompile)" />
</Target>

This will only work if Visual C++ is installed.

like image 194
Justin Avatar answered Oct 17 '22 20:10

Justin


Here is an alternative pre-build event for Visual Studio 2010 that is less dependent on specific directory locations:

@echo.
set RCDIR=
IF EXIST "$(FrameworkSDKDir)Bin\rc.exe" (set RCDIR="$(FrameworkSDKDir)Bin\rc.exe")
IF EXIST "$(DevEnvDir)..\..\VC\Bin\rc.exe" (set RCDIR="$(DevEnvDir)..\..\VC\Bin\rc.exe")
IF EXIST "$(DevEnvDir)..\..\SDK\v2.0\Bin\rc.exe" (set RCDIR="$(DevEnvDir)..\..\SDK\v2.0\Bin\rc.exe")
IF EXIST "$(DevEnvDir)..\..\SDK\v3.5\Bin\rc.exe" (set RCDIR="$(DevEnvDir)..\..\SDK\v3.5\Bin\rc.exe")
IF EXIST "$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v6.0a\bin\rc.exe" (set RCDIR="$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v6.0a\bin\rc.exe")
IF EXIST "$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v7.0a\bin\rc.exe" (set RCDIR="$(DevEnvDir)..\..\..\Microsoft SDKs\Windows\v7.0a\bin\rc.exe")
if not defined RCDIR (echo "Error!  Unable to find rc.exe.") ELSE (%RCDIR% /r "$(ProjectDir)MyResources.rc")
if not defined RCDIR (Exit 1)
@echo.

Of course, change MyResources.rc to the appropriate file name.

If you use this pre-build event, you can tell Visual Studio to use the corresponding .RES file in the Project Properties dialog under Application > Resources (for C#).

like image 1
Holistic Developer Avatar answered Oct 17 '22 21:10

Holistic Developer