0

I need to use the LoadImage pinvoke in a project. I need to use this so that I get a transparent BMP.The following code works fine, but requires a path.

Dim hbitmap As IntPtr = NativeMethodsEX.LoadImage(Nothing, "C:\Users\username\Desktop\mickey32.bmp", NativeMethodsEX.IMAGE_BITMAP, 0, 0, NativeMethodsEX.LR_LOADFROMFILE Or NativeMethodsEX.LR_CREATEDIBSECTION)

My question is can I do the same thing but with a file that is embedded in my project? Or is the only way that at some stage I copy the file out into the file system for it to be used in the LoadImage method.

Edit: what I'm trying to avoid is to have an image file in the file system, which for example could be deleted by a user.

EDIT - What am i doing? I am inserting a menu item into an existing windows hmenu as I indicate in this question of mine.. I want to add an image with a transparent background.

EDIT - Why am I not using .net to get my image?

It is well documents in this forum that the following does not work. Further I cannot get it to work.

Dim bm As Bitmap = My.Resources.mickey32.bmp
Dim hbitmap As IntPtr = nbm.GetHbitmap

After the comments below in this question as to why I am not using .NET I have even tried the following suggestions which included a format.. Still no luck.

Dim bm As Bitmap = My.Resources.mickey32.bmp
Dim bm1 As Bitmap = New Bitmap(bm)
Dim nbm As Bitmap = bm1.Clone(New Rectangle(0, 0, bm1.Width, bm1.Height), Imaging.PixelFormat.Format32bppArgb)
Dim hbitmap As IntPtr = nbm.GetHbitmap

Edit Using a PNG

This code which uses a PNG file. It loads fine but the transparent background is made white.

Dim bm As Bitmap = My.Resources.mickey32.png
Dim hbitmap As IntPtr = bm.GetHbitmap

My Solution or what I did in the end

My main issue was to get an image that had a transparent background. I thought the only way to do this was to use the LoadImage API with a bitmap image. Thanks to the extensive comments below I revisited trying this with the .net methods and a png file (I incorrectly thought this did not work). I then found this forum question. The solution there is to use this;

hbitmap = bm.GetHbitmap(Color.Black)

And now I have it displayed correctly.

In my searching I also found this forum answer as well. The accepted answer says;

GDI+ has a number of problems related to alpha blending when doing interop with GDI (and Win32). In this case, the call to bmp.GetHbitmap() will blend your image with a black background.

I did not test the code but it at least looks like it might also be a solution for me.

Community
  • 1
  • 1
darbid
  • 2,545
  • 23
  • 55
  • 1
    Wouldn't it be easier to embed a png – David Heffernan Dec 24 '16 at 08:47
  • What do you mean by "embedded"? embedded as a .NET resource or a Win32 resource, or something else? – Simon Mourier Dec 24 '16 at 08:47
  • Embeded as explained here https://msdn.microsoft.com/en-us/library/e2c9s1d7(v=vs.100).aspx – darbid Dec 24 '16 at 09:08
  • David I'm open to anything, but understood that I needed a 32bbp premultiplied bmp file to get transparency in my menu. – darbid Dec 24 '16 at 09:09
  • If you don't pass the `LR_LOADFROMFILE` flag, `LoadImage` will interpret the second argument as a resource identifier. All of this is [documented](https://msdn.microsoft.com/en-us/library/windows/desktop/ms648045.aspx). – IInspectable Dec 24 '16 at 10:05
  • 1
    Depends on what you mean by "embedded". You're using VB.NET, so if you embed the image into the executable using the managed .NET tooling, then no, this will not work. You need to use the .NET functions for this. If you mean embed it as a Win32 resource, then yes, of course you can do this, exactly as documented. The real question is why are you using `LoadImage` in a VB.NET application? Just use the .NET BCL functions. If you need an HBITMAP, you can retrieve one for a Bitmap object. – Cody Gray - on strike Dec 24 '16 at 10:11
  • @CodyGray because .net methods e.g. With the .net Bitmap class do not respect the transparency. – darbid Dec 24 '16 at 10:39
  • Of course the `Bitmap` class supports transparency. But you have to use a [**PixelFormat**](https://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat(v=vs.110).aspx) such as `32bppArgb`. – Visual Vincent Dec 24 '16 at 10:45
  • I see. Well, the obvious solution is to switch to a PNG. If you have to use a bitmap, you can either [jump through a bunch of hoops to embed Win32 resources into your binary](https://blogs.msdn.microsoft.com/astebner/2006/02/28/how-to-build-a-managed-assembly-that-contains-win32-resources-using-visual-studio-2005/), or you can use .NET methods to create a new bitmap, lock its bits, load the raw bytes from a file and write them into the bitmap, and then unlock the bitmap's bits. This will work, because as Visual Vincent says, the Bitmap class supports 32-bpp ARGB, but not *loading* such a BMP. – Cody Gray - on strike Dec 24 '16 at 10:46
  • If you have added an image with transparency to the resources all you have to do is access it using `My.Resources.` and you should get the transparent version. – Visual Vincent Dec 24 '16 at 10:46
  • @CodyGray : It can load PNGs, so why can't it load 32bpp BMPs? I've never experienced that it wouldn't be able to. – Visual Vincent Dec 24 '16 at 10:49
  • 1
    Well, it *can* load a 32-bpp bitmap from a file, and you will get a Bitmap with PixelFormat.32bppArgb, but it sets all of the alpha channel values to 255. I'm sure the reason is because under the hood it is calling an old API that doesn't deal with transparency. Probably the IPicture interface, which is itself implemented on top of the GDI bitmap functions, but I haven't investigated in detail. The code he has now only works because he's forcing a DIB section to be created. Removing that flag would make LoadBitmap behave in exactly the same way. .NET doesn't wrap DIB sections. – Cody Gray - on strike Dec 24 '16 at 10:53
  • Thanks @CodyGray you have got it. I have tried all these things. I really want someone to tell me I am wrong, but it appears the only way to do this with transparency is with a Loadimage and the DIB flag. Question is updated. – darbid Dec 24 '16 at 11:11
  • Why don't you try using a PNG instead? You'll be able to load it into the `Bitmap` class with transparency, and you can still call `GetHbitmap()` on it. There's no requirement that the image loaded into the class must be a BMP. – Visual Vincent Dec 24 '16 at 13:11
  • It makes no difference what it is as Cody has said it is loaded by .net incorrectly. – darbid Dec 24 '16 at 14:03
  • @darbid: Have you verified, that loading a PNG will not give you an alpha channel? Since `LoadImage` cannot load PNG's .NET will have to use some other API. At a guess, it's calling into the Windows Imaging Component, and that is fully capable of loading a PNG, while retaining the full alpha channel. – IInspectable Dec 24 '16 at 14:48
  • @darbid : What he said is that a 32bppArgb _**BMP**_ is loaded incorrectly. I cannot verify that, but **I am certain** that you can load a _**PNG**_ correctly! – Visual Vincent Dec 24 '16 at 15:21
  • @γηράσκωδ'αείπολλάδιδασκόμε : Actually the BMP format does support alpha, but it isn't commonly used. See this [Wikipedia article](https://en.m.wikipedia.org/wiki/BMP_file_format): _"An integrated alpha channel has been introduced with the undocumented BITMAPV3INFOHEADER and with the documented BITMAPV4HEADER (since Windows 95)"_. – Visual Vincent Dec 24 '16 at 16:17
  • No, I specifically said that PNGs are loaded correctly. "The obvious solution is to switch to a PNG". – Cody Gray - on strike Dec 24 '16 at 23:08
  • A 32bppArgb .png image which is embedded into Visual Studio's resources and loaded the .NET way with My.Resources does not keep its backgound. Windows or something makes it white. – darbid Dec 25 '16 at 16:21
  • Thanks everyone for challenging me to do what I thought did not work. @Cody - you are correct, a png does work if you use bm.GetHbitmap(Color.Black) to get the pointer. I have added to my post what I have done and links to what I found out. – darbid Dec 26 '16 at 06:43
  • Yup, that will work. Forgot about the overload that takes a Color parameter. It sets the background color for the transparent areas. The reason it works for you is actually somewhat of an accident, but I'm glad you figured out a solution. One important note is that if you call `Bitmap.GetHbitmap`, it returns an unmanaged handle to a bitmap, and you *absolutely* must P/Invoke the `DeleteObject` method and call it to free this unmanaged memory when you are finished using the bitmap handle. Check pinvoke.net for code. Also, please post your solution as an answer, rather than in the question. – Cody Gray - on strike Dec 28 '16 at 06:59

0 Answers0