6

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


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

Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 1
    Pretty big impedance mismatch, managed resources work very differently. You can still add a .res file to the project with Project + Properties, Application tab, Resource file. You'll get no help whatsoever reading them. Pinvoke required. – Hans Passant Nov 08 '11 at 21:27
  • 1
    So i can't add a `.rc` file to my solution and have Visual Studio's resource compiler compile it? – Ian Boyd Nov 08 '11 at 22:21
  • 1
    Well, sure, you can add a C++ project. You seem too underwhelmed with the difficulty of reading the resources. – Hans Passant Nov 08 '11 at 22:38
  • 1
    @HansPassant Well fortunately they're not all for me. Some are for programs like Internet Explorer, which require a resource image (i.e. you can't feed an image to a `WebBrowser` control, or its native `IWebBrowser` COM object). But i have no interest in adding a `res` file, as that requires a compiler. i'm used a development tool where you add a `.rc` file to the solution as easily as you add a `.cs` file - and the compiler/linker processes it - doing its job. – Ian Boyd Nov 08 '11 at 23:52
  • 1
    Yes, you have one, Visual Studio. Haven't tried that C++ project then? – Hans Passant Nov 09 '11 at 00:07
  • It's a .NET project i need it built into. – Ian Boyd Nov 09 '11 at 01:13

2 Answers2

5

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.

Justin
  • 84,773
  • 49
  • 224
  • 367
  • He's using *Resource Hacker* to manually add resources to exe after building it. Not really a solution when you have a few dozen resources, and can't run the executable until they've been added. – Ian Boyd Nov 09 '11 at 14:44
  • @IanBoyd I've updated my answer to include some hints on how to do this using the csc `/win32res` option instead - I'm afraid I've never done this before so I don't know the best way of doing this but hopefully this answer should give you some hints. – Justin Nov 09 '11 at 14:58
  • Preface your answer with "While future versions of Visual Studio might support it, Visual Studio 2010 does not support compiling resources in the .NET portable executable." and i'll accept it. It seems to be the correct answer (i.e. *you can't*) – Ian Boyd Nov 09 '11 at 15:05
  • @IanBoyd Found a better article that explains how to do this using a pre-build step. – Justin Nov 10 '11 at 12:22
  • The problem is that i work with other developers. i can't be modifying the solution to hard-code paths that will fail on other developers machines. – Ian Boyd Nov 10 '11 at 13:42
  • @IanBoyd You could also use the RC MSBuild task. This is similar to the way that the Visual C++ MSBuild scripts work and so will work on other developer machines (as long as Visual C++ is installed). – Justin Nov 10 '11 at 13:58
  • Again, i would be breaking the build. – Ian Boyd Nov 10 '11 at 14:01
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4881/discussion-between-justin-and-ian-boyd) – Justin Nov 10 '11 at 14:02
1

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#).

Holistic Developer
  • 2,458
  • 1
  • 18
  • 27