5
votes

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

2
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
So i can't add a .rc file to my solution and have Visual Studio's resource compiler compile it?Ian Boyd
Well, sure, you can add a C++ project. You seem too underwhelmed with the difficulty of reading the resources.Hans Passant
@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
Yes, you have one, Visual Studio. Haven't tried that C++ project then?Hans Passant

2 Answers

5
votes

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.

1
votes

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