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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With