2016-09-16 2 views
0

Donc, j'essaie de charger une ressource image à partir d'un fichier dll. Pour ce faire j'ai créé la méthodeErreur GDI + lors de l'appel de Image.FromHBitmap sur le handle renvoyé par LoadImage

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); 
} 

Qui charge la ressource d'image à partir de la DLL, étant donné un handle et l'ID de ressource. Selon this question I asked yesterday je dois préfixer un # à l'id, ce que j'ai fait. Maintenant, la poignée retournée par LoadImage est zéro plus, mais lorsque je tente de créer une image bitmap de cette poignée à l'aide Image.FromHbitmap je reçois un System.Runtime.InteropServices.ExternalException dire

Une erreur générique est produite dans GDI +

(ou quelque chose de similaire, je ne reçois pas le message en anglais, donc je l'ai traduit à peu près)

J'ai déjà lu this et this question mais ils ne m'a pas aidé.

Pourquoi est-ce? Merci à l'avance

+0

C'est tout à fait normal, vous chargez une icône, pas une image. Utilisez Icon.FromHandle() à la place. Vous devrez détruire l'icône à nouveau avec DestroyIcon, plus tard, après vous être assuré que l'objet Icon ne peut plus être utilisé. –

Répondre

0

Si le dll est un ensemble de .NET, vous pouvez appeler Assembly.GetManifestResourceStream, comme ceci:

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; 
} 

Si elle est un dll natif (pas de montage), vous devrez utiliser Interop à la place . Vous avez une solution here, et pourrait se résumer comme suit:

[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; 
} 

Aucune manipulation d'erreur a été ajouté, c'est pas code prêt à la production.

NOTE: Si vous avez besoin d'une icône, vous pouvez utiliser le constructeur d'icône qui reçoit un flux:

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

Et vous devez changer le type de retour en conséquence.

+0

Qu'est-ce que 'bptr' exactement? –

+1

Une faute de frappe. J'ai changé le code avec le bon nom de variable. –

+0

Je n'ai que l'ID de la ressource, que dois-je utiliser pour le paramètre 'resourceName'? –