在LoadImage返回的句柄上调用Image.FromHBitmap时出现GDI +错误

时间:2016-09-16 11:35:21

标签: c# gdi+ loadimage

所以我尝试从dll文件加载图像资源。为此,我创建了方法

static Bitmap GetImageResource(IntPtr handle, string resourceId)
{
    IntPtr img_ptr = NativeMethods.LoadImage(handle, "#" + resourceId, IMAGE_ICON, 16, 16, 0);

    if (img_ptr == IntPtr.Zero)
        throw new System.ComponentModel.Win32Exception((int)NativeMethods.GetLastError());

    return Image.FromHbitmap(img_ptr);
}

在给定句柄和资源ID的情况下,从dll加载图像资源。根据{{​​3}},我必须在ID之前加上#,我做了。现在,LoadImage返回的句柄不再为零,但是当我尝试使用此句柄创建位图图像时 Image.FromHbitmap我得到System.Runtime.InteropServices.ExternalException

  

GDI +中发生了一般错误

(或类似的东西,我没有用英语得到消息,所以我大致翻译了它)

我已经阅读了this question I asked yesterdaythis问题,但他们没有帮助我。

这是为什么?提前致谢

1 个答案:

答案 0 :(得分:0)

如果Dll是.NET程序集,您可以调用Assembly.GetManifestResourceStream,如下所示:

public static Bitmap getBitmapFromAssemblyPath(string assemblyPath, string resourceId) {
    Assembly assemb = Assembly.LoadFrom(assemblyPath);
    Stream stream = assemb.GetManifestResourceStream(resourceId);
    Bitmap bmp = new Bitmap(stream);
    return bmp;
}

如果是原生dll(不是程序集),则必须使用Interop。您有一个解决方案here,可归纳如下:

[DllImport("kernel32.dll", SetLastError = true)] 
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

[DllImport("kernel32.dll")] 
static extern IntPtr FindResource(IntPtr hModule, int lpID, string lpType); 

[DllImport("kernel32.dll", SetLastError = true)] 
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); 

[DllImport("kernel32.dll", SetLastError = true)] 
static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);

[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);

static const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;

public static Bitmap getImageFromNativeDll(string dllPath, string resourceName, int resourceId) {
    Bitmap bmp = null;
    IntPtr dllHandle = LoadLibraryEx(dllPath, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE);
    IntPtr resourceHandle = FindResource(dllHandle, resourceId, resourceName);
    uint resourceSize = SizeofResource(dllHandle, resourceHandle); 
    IntPtr resourceUnmanagedBytesPtr = LoadResource(dllHandle, resourceHandle);

    byte[] resourceManagedBytes = new byte[resourceSize]; 
    Marshal.Copy(resourceUnmanagedBytesPtr, resourceManagedBytes, 0, (int)resourceSize); 
    using (MemoryStream m = new MemoryStream(resourceManagedBytes)) {
        bmp = (Bitmap)Bitmap.FromStream(m);
    }

    FreeLibrary(dllHandle);

    return bmp;
}

未添加错误处理,这是生产就绪代码。

注意:如果需要Icon,可以使用接收流的Icon构造函数:

    using (MemoryStream m = new MemoryStream(resourceManagedBytes)) {
        bmp = (Icon)new Icon(m);
    }

您应该相应地更改返回类型。