Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UpdateResource doesn't work with lpType as string

P/Invoke declarations:

[DllImport("kernel32.dll")]
static extern bool UpdateResource(IntPtr hUpdate, IntPtr lpType, IntPtr lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll")]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, int lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll")]
static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);
[DllImport("kernel32.dll")]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);

My code:

var hUpdate = BeginUpdateResource(FilePath, false);
var BMP = File.ReadAllBytes(BmpPath);
UpdateResource(hUpdate, "2", 123, 1033, BMP, (uint)BMP.Length);
UpdateResource(hUpdate, "#2", 123, 1033, BMP, (uint)BMP.Length);
UpdateResource(hUpdate, "RT_BITMAP", 123, 1033, BMP, (uint)BMP.Length);
UpdateResource(hUpdate, "BITMAP", 123, 1033, BMP, (uint)BMP.Length);
EndUpdateResource(hUpdate, false);

None of the above UpdateResource calls work. They add the new resource under a new resource type named #2, RT_BITMAP, BITMAP instead of updating the existing resource.

In the P/Invoke declaration of UpdateResource, if I overload string lpType to IntPtr lpType and pass it a new IntPtr(2), everything works but I don't want to use this solution because sometimes I also need string lpType for custom resource types and overloading will require too many changes in my current code design.

MSDN:

lpType [in]

Type: LPCTSTR

The resource type to be updated. Alternatively, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is an integer value representing a predefined resource type. If the first character of the string is a pound sign (#), then the remaining characters represent a decimal number that specifies the integer identifier of the resource type. For example, the string "#258" represents the identifier 258.

Any idea why can't I update the existing bitmap by passing lpType a string? I am doing exactly what's stated in MSDN.

PS: I absolutely need to pass lpType a string, can't use IntPtr by overloading because of the reason stated above (too many changes required for current code design).

like image 838
user3666697 Avatar asked Oct 20 '22 08:10

user3666697


1 Answers

Most likely MSDN is wrong.

The documentation for the lpName parameter says "when creating a new resource do not use a string that begins with a '#' character for this parameter". I imagine the same restriction applies to lpType.

You can fix this without altering the structure of the rest of your code.

Define both overloads of UpdateResource but make them private and rename them (maybe to UpdateResourceW).

Then define your own public UpdateResource function in C#. This should inspect the lpType parameter. If the type begins with a # convert it to an integer and call the IntPtr lpType overload, otherwise use the string lpType overload.

Thus you can use strings for resource types throughout your code, and handle this detail in a single place.

like image 124
arx Avatar answered Oct 23 '22 09:10

arx