C # BeginUpdateResource

I want to add a string resource to an executable programmatically. Just as an example, let's say I'm trying to add a string called "String SO" that contains the value "stringVal"

If this helps anyone - if I did it through VS.net, I could just right-click on my project => Resources => Add a new row resource, etc.

I use the following Win32 APIs:

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);

So, I found a couple of pages on the Internet, but none of them seem to help me with what I'm trying to do. If any of you find anything, I will be very grateful.

Otherwise, I would appreciate any snippets that might help. Thanks Evan

+3
source share
4 answers

github.

-api- UpdateResource(...) ..

, .

+2

[] . , , :

class AddResource
{
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr BeginUpdateResource(string pFileName,
       [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
private static IntPtr ToPtr(object data)
{
    GCHandle h = GCHandle.Alloc(data, GCHandleType.Pinned);
    IntPtr ptr;
    try
    {
        ptr = h.AddrOfPinnedObject();
    }
    finally
    {
        h.Free();
    }
    return ptr;

}

public static bool InjectResource(string filename, byte[] bytes, string resourceName)
{
    try
    {
        IntPtr handle = BeginUpdateResource(filename, false);
        byte[] file1 = bytes;
        IntPtr fileptr = ToPtr(file1);
        bool res = UpdateResource(handle, resourceName,
            //"RT_RCDATA",
            "0", 0, fileptr, Convert.ToUInt32(file1.Length));
        EndUpdateResource(handle, false);
    }
    catch
    {
        return false;
    }
    return true;

}

public static void CopyStream(Stream input, Stream output,long sz)
{
    // Insert null checking here for production
    byte[] buffer = new byte[sz];

    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

}

:

using (Stream input = Assembly.GetExecutingAssembly().GetManifestResourceStream("AppLicensing.Resources.SAppStarter.exe"))
                        using (Stream output = File.Create(outputFilePath))
                        {
                            long sz = input.Length;
                            AddResource.CopyStream(input, output, sz);
                        }
                        //inject crypted bytes
                        AddResource.InjectResource(outputFilePath, Encryptor.cryptedbytes, "RT_RCDATA");

( "RT_RCDATA" → ):

   class ReadResource 
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);

        [DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
        private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);

        [DllImport("Kernel32.dll", EntryPoint = "LoadResource", SetLastError = true)]

        private static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResource);


       public static  byte[] GetFromResource(String resourceName)
    {
        try
        {
            IntPtr hModule = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
            IntPtr loc = FindResource(hModule, "0", resourceName);
            uint size = SizeofResource(hModule, loc);
            IntPtr x = LoadResource(hModule, loc);
            byte[] bPtr = new byte[size];
            Marshal.Copy(x, bPtr, 0, (int)(size));
            return bPtr;
        }
        catch (Exception e)
        {
            System.Windows.Forms.MessageBox.Show(e.ToString());
            System.Environment.Exit(0);
            return null;
        }        
    }            
  }

  byte[] encryptedData = ReadResource.GetFromResource("RT_RCDATA");

... , .

+1
0

The code from Samson works with String lpType, which means that you cannot actually add the RT_RCDATA resource, or read it, it only creates and reads only lpType with the name "RT_RCDATA". If you want it to read real RT data, you need to change lpType from the string to uint, and this is the RT API table:

private const uint RT_CURSOR = 0x00000001;
private const uint RT_BITMAP = 0x00000002;
private const uint RT_ICON = 0x00000003;
private const uint RT_MENU = 0x00000004;
private const uint RT_DIALOG = 0x00000005;
private const uint RT_STRING = 0x00000006;
private const uint RT_FONTDIR = 0x00000007;
private const uint RT_FONT = 0x00000008;
private const uint RT_ACCELERATOR = 0x00000009;
private const uint RT_RCDATA = 0x0000000a;
private const uint RT_MESSAGETABLE = 0x0000000b;
0
source

All Articles