Problem mit dem Auslesen von Resourcendaten aus Resourcenblöcken einer Binärdatei,...

03/03/2009 - 10:12 von Kerem Gümrükcü | Report spam
Hallo,

vielleicht kennt sich der eine oder andere besser als ich
auf diesem gebiet aus, da ich hier etwas steckengeblieben
bin. Nun ich habe eine exe datei, die eine bitmapresource
mit der ID 130 hat. das laden der resourcen und die rückgabe
eines bytearrays sind kein problem, mache ich alles mit pinvoke
und kenne ich auch aus C und windows api noch. nur musste ich
bis heute keine bitmap auslesen,...und da geht das problem los.
ich habe mir mal mit einem resourcenanalyser die bitmap aus der
exe rauslesen lassen und habe die mit einem hex-editor geöffnet.
anbei bemerkt, habe ich die bmp mal mit paint und anderen
programmen geöffnet und der resourceneditor hat nen guten job
gemacht. die extrahierte bmp ist gültig und lesbar. nun kommt mein
code ins spiel. ich lese die resource voll aus, dachte, das ich gleich
ne fertige bmp in bytes habe, aber das war nix. das erzeugen
einer bmp mit "Bitmap.FromStream(MemoryStream);", wobei
hier für den MemoryStream gilt, das dieser aus dem resourcen byte
array erzeugt wird. Aber die Methode ruft eine Exception hervor
die sagt, das der stream ungültig wàre. ich habe mir dann die zwei daten,
also das vom resourcen editor und das eigens extrahierte mal angesehen.
erkennen kann man, das da irgendwie ein Kopfteil fehlt. allerdings liegt
das nicht an meinem code (in C/MFC ist das resultat das selbe!),sondern
es wird ohne diesen einen teil extrahiert. es scheint eine art bitmap
header zu sein. wenn ich jetzt diesen prolog "künstlich" im code
generiere und vor den byte stream lege, dann ist die bmp gültig
und absolut identisch mit der extrahierten vom resourcen editor. der
fehlende kopfteil ist das problem. hier mal code:

private void button1_Click(object sender, EventArgs e)
{
try
{
int LanguageId = 0;

Exception Error = null;

byte[] bmp_header = new byte[] { 66, 77, 54, 27, 0, 0, 0, 0,
0, 0, 54, 0, 0, 0 }; //künstlicher header

byte[] buffer =
GetResourceFromBinaryFileById("resource_container.exe", 130,
BinaryResourceTypes.RT_BITMAP, ref LanguageId, out Error);

byte[] bmp_final = new byte[bmp_header.Length +
buffer.Length];

Array.Copy(bmp_header, bmp_final,bmp_header.Length);
Array.Copy(buffer, 0, bmp_final, bmp_header.Length,
buffer.Length);

string desktop_path =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
Path.DirectorySeparatorChar + new Random().Next().ToString() + ".bmp";

FileStream fs = File.Open(desktop_path,
FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
fs.Write(bmp_final, 0, bmp_final.Length);
fs.Flush();
fs.Close();

if (Error != null)
{
throw Error;
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString(), this.Text,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

Die funktion "GetResourceFromBinaryFileById(...)" ist marke eigenbau
und funktioniert problemlos, allerdings fehlen da immer die kopfteile,
auch für Icons, für andere Daten allerdings nicht. Also liegt es definitv
nicht an meinem code, da ich das gleiche problem mit nativem Windows
API und einem MFC/C Beispiel habe, das ich mal parallel dazu geschrieben
habe,...

Habe ich da was in der Doku übersehen, oder was mache ich falsch?
Dieser Prolog kann nicht für alle bmp dateien gültig sein, oder irre
ich mich hier. leider hatte ich keine zeit, die dokus zu der datenstruktur
von bmp zu lesen. vieleicht hat jemand eine schnelle antwort für mich,...

Danke für jeden Tip,...

Grüße

Kerem

Beste Grüsse / Best regards / Votre bien devoue
Kerem Gümrükcü
Latest Project: http://www.pro-it-education.de/soft...iceremover
Latest Open-Source Projects: http://entwicklung.junetz.de
"This reply is provided as is, without warranty express or implied."
 

Lesen sie die antworten

#1 Kerem Gümrükcü
04/03/2009 - 08:46 | Warnen spam
Hallo,

ich habe mittlerweile eine Lösung für das Problem gefunden,
das sicher dem einen oder anderen auch eine große Hilfe sein
wird. Der Weg über das klassiche Laden mit folgenden Funktionen
zum Laden eines Icons oder Bitmaps ist viel zu kompliziert:

LoadLibraryEx
FindResource
LoadResource
LockResource
SizeOfResource
CopyMemory
FreeLibrary

Zwar bekommt man die rohen Daten der Resourcen, aber diese
sind de-facto, nicht vollstàndig und der Rest muss aus dem PE
sehr kompliziert und mit viel Speicher/Zeigergeschiebe kopiert werden.
Wenn man diesen Weg geht, dann muss man die PE Datei komplett
zerlegen um an die Header und Sektionsdaten zu kommen, was
ziemlich aufwendig und kompliziert sein kann. Es geht viel einfacher,..;-)

Zum laden eines Icons oder eines Bitmaps benötigt man nur eine
einzige Funktion: LoadImage(...)

[LoadImage Function]
http://msdn.microsoft.com/en-us/lib...48045.aspx

Damit kann man sich gleich ein Icon, eine Bitmap, oder einen
Cursor aus einer Binàrdatei holen. Intern sind diese Daten in
bestimmten Sektionen abgespeichert, z.b. ICON für Icons,
BITMAP für Bitmaps, etc,...wer mehr wissen will, der kann mal
eine native EXE/DLL schreiben, diese mit Icons, Cursor, Bitmaps
vollpacken und sich dann mit einem Resource-Viewer ansehen.
Natürlich kann die Datei auch benutzerdefinierte Resourcen haben,
aber das ist dann ein Fall für den klassichen, komplizierten Weg
oben, den ich nicht einschlagen will, zumindest für den Fall hier.

Um ein Icon zu laden, z.b. ein Icon aus der Shell32.dll, sagen wir
mal das Icon mit der Ordinalnummer "2049" benötigen wir den
"Icon Group". All diese Informationen bekommen wir mit den zwei Funktionen
EnumResourceNames (...) und EnumResourceTypes(...).

[EnumResourceNames Function]
http://msdn.microsoft.com/en-us/library/ms648037(VS.85).aspx

[http://msdn.microsoft.com/en-us/library/ms648039(VS.85).aspx]

Pinvokes dazu gibt es hier: www.pinvoke.net
Das erst mal am Rande erwàhnt.

Die Hauptfunktion ist die LoadImage(...)

[LoadImage Function]
http://msdn.microsoft.com/en-us/lib...48045.aspx

Jetzt kommt der Trick:

Schaut man sich die Funktion an und würde man diese
gemàß den Pinvoke/Marshalling Konventionen übersetzen,
dann würde die so aussehen:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType,
int cxDesired, int cyDesired, uint fuLoad);

Das ist auch richtig, aber wenn wir die ID, also die ID für das Groupicon
haben,
dann nicht mehr, denn wenn man sich die Doku ansieht zu der Funktion ist
da ein Satz, der ziemlich unscheinbar aussieht, aber sehr wichtig ist:

"If the image resource is to be loaded by ordinal from the module, use the
MAKEINTRESOURCE macro to convert the image ordinal into a form that can
be passed to the LoadImage function."

Schauen wir uns das Makro an, so erkennen wir, das die LoadImage(...)
in wirklichkeit einen WORD erwartet, der in .NET konventionen einen
"UInt16" darstellt, bzw. einen "ushort":

Hier das Makro:

LPTSTR MAKEINTRESOURCE(
WORD wInteger
);

Übertragen wir das auf die LoadImage in der .NET Version, so
bekommen wir diese Funktion:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr LoadImage(IntPtr hinst, ushort lpszName, uint uType,
int cxDesired, int cyDesired, uint fuLoad);

So können wir nun ein Icon, einen Cursor, oder eine Bitmap mit der
Ordinalzahl ohne Probleme laden. Der Rückgabewert ist ein HANDLE
also ein IntPtr das, jeh nach geladenem Typ, entweder ein Icon handle,
Cursor Handle, oder ein Bitmap Handle ist. Nun kann man mit den
.NET Klassen ganz einfach ein Icon/Bitmap/Cursor daraus erzeugen:

Icon icon = Icon.FromHandle(IconHandle);
Cursor cursor = new Cursor(CursorHandle);
Bitmap bitmap = Bitmap.FromHbitmap(BitmapHandle);


Das wars,...und ich habe mich wieder in den Tiefen der Bits
und Bytes verloren, :-D

Naja, ich hoffe, das hilft dem einen oder anderen,...


Hier sind noch die Pinvoke Übersetzungen, die ich
gemacht habe:

public enum LoadImageImageType : ushort
{
IMAGE_BITMAP = 0,
IMAGE_ICON = 1,
IMAGE_CURSOR = 2,
IMAGE_ENHMETAFILE = 3
}

[DllImport("user32.dll", SetLastError = true, CharSet =
CharSet.Unicode)]
public static extern IntPtr LoadImage(IntPtr hinst, ushort
resourceId, LoadImageImageType ImageType,
int cxDesired, int cyDesired, uint fuLoad);

Mehr Informationen zu den Parametern der LoadImage(...) in der MSDN. Da geht
noch einiges, was man da noch von der Funktion "anfordern" kann,...


Grüße

Kerem


Beste Grüsse / Best regards / Votre bien devoue
Kerem Gümrükcü
Latest Project: http://www.pro-it-education.de/soft...iceremover
Latest Open-Source Projects: http://entwicklung.junetz.de
"This reply is provided as is, without warranty express or implied."

Ähnliche fragen