Laden...

Marshal.FreeHGlobal() funktioniert nicht (GetLastError = 998)

Letzter Beitrag vor 13 Jahren 11 Posts 2.137 Views
Marshal.FreeHGlobal() funktioniert nicht (GetLastError = 998)

Hallo, ich greife per P/Invoke auf eine DLL zu um dort eine Funktion auszuführen.
Dazu reserviere ich mir zuerst Speicher mit Marshal.AllocHGlobal() und kopiere anschließend mit Marshal.Copy() ein Byte Array in den Unverwalteten Speicher. Dann übergebe ich der Funktion aus der DLL einen IntPtr mit der Adresse zu diesen Daten. Diese Funktion gibt mir anschließend ebenfalls einen Pointer zu den bearbeiteten Daten zurück die ich ebenfalls wieder mit Marshal.Copy() zurück in den Verwalteten Speicher lade (ein Verwaltetes Byte Array).

Soweit ist auch alles kein Problem, die Daten die ich bekomme sind OK.
Jetzt geht es aber darum den Unverwalteten Speicher mit der Methode Marshal.FreeHGlobal() wieder frei zu geben:
Mit dem von mir selbst mittels Marshal.AllocHGlobal() reservierten Speicher funktioniert das auch, allerdings nicht mit dem Speicher die die DLL Funktion reserviert hat. Dort bekomme folgende Exception:

_COMPlusExceptionCode = -532459699

Um mehr Infos zu bekommen habe ich einen DLL Import auf die Windows Funktion "LocalFree" gemacht, dort bekomme ich diese Fehlermeldung:> Fehlermeldung:

Win32 Error: 998

Die MSDN sagt dazu folgendes:

ERROR_NOACCESS: 998 (0x3E6)
Invalid access to memory location.

Wo daran kann das liegen?

Mein Hostsystem ist Windows 7 x64, die DLL wurde aber für x86 kompiliert und mein Projekt ist auch auf x86 eingestellt.
Wie gesagt funktioniert auch alles korrekt, nur die die Speicherfreigabe macht Probleme. Ob ich es als Administrator oder nicht ausführe macht keinen unterschied.

Was ist das für eine Dll? Ist sie von dir, hast du den Quellcode? Ist irgendwie dokumentiert was sie macht, wie sie zu benutzen ist?

Hallo flippy08,

du musst den Speicher mit der Funktion freigeben, die zu der Funktion passt, mit der der Speicher allokiert wurde. Dazu musst du natürlich erstmal wissen, welche Funktion das ist, oder zumindest mit welcher Funktion die Funktion aus der DLL der Speicher allkoiert. Wenn du als Aufrufer der Funktion dafür zuständig bist, den Speicher selbst freizugeben, sollten aus der Dokumentation der Funktion bzw. der DLL die nötigen Informationen zu entnehmen sein. FreeHGlobal ist offensichtlich nicht die richtige Funktion.

herbivore

Ich habe mich nochmal durch den Source gewühlt und dabei folgendes Kommentar gefunden:

The code that calls any of these functions must delete the data buffer (uint8_t*) returned by these functions with free().

Also müsste ich ja nur dir free() Funktion Invoken:

[DllImport("msvcrt.dll", SetLastError = true)]
static extern void free(IntPtr memblock);

Das kann ich auch ohne Fehler ausführen, aber kann ich auch irgendwie überprüfen ob der Aufruf erfolgreich war? Die Funktion gibt mir ja dummerweise nichts zurück...

GetlastWin32Error mal ausprobiert?

Joa klar, voll verpeilt:
Also das funktioniert leider auch nicht, gibt Win32 Error 87:> Fehlermeldung:

ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.

EDIT:
Ich habe jetzt mal die Funktion GlobalFree probiert, jetzt ist zwar GetlastWin32Error = 0, allerdings ist der Rückgabewert nicht wie in der MSDN beschrieben NULL sondern dort steht immer noch die Speicheradresse was laut MSDN heißt das der Vorgang nicht erfolgreich war:

If the function succeeds, the return value is NULL.
If the function fails, the return value is equal to a handle to the global memory object. To get extended error information, call GetLastError.

Bin ich jetzt ein wenig irritiert...

Hallo flippy08,

wenn da steht free, dann musst du schon free benutzen. Keine Ahnung, warum es nicht geht. Probier doch mal testweise mal von native C aus, obs überhaupt geht.

BTW: [****CODE]-Tags sind nur für (Nicht-C#-)Code, für Fehlermeldungen gibts [****ERROR], für Zitate [****QUOTE], auch für Zitate aus der Doku. Bitte benutze bitte immer die passenden Tags.

herbivore

Ich habe jetzt nochmal ein wenig rumprobiert und dabei ist mit folgendes aufgefallen:
Statt Error 87 bekomme ich jetzt seit gestern immer Error 1008 nach dem Aufruf von free() geliefert:

ERROR_NO_TOKEN
1008 (0x3F0)
An attempt was made to reference a token that does not exist.

Das komische ist aber das ich das auch bekomme wenn ich SetLastError auf false setzte. Das würde ja bedeuten das dieser Fehler nicht direkt durch den aufruf von free() produziert wird sondern von irgend einer Unterfunktion die dabei aufgerufen wird? Oder liege ich da total falsch?

Ich bin mir nicht sicher, weil ich GetLastError in .NET noch nie benutzt habe. Aber ich könnte mir vorstellen, dass es intern durch P/Invoke verursacht wird. Ich denke, da kann man sich nicht direkt drauf verlassen.
Funktioniert das freigeben denn, wenn du es aus C/C++ machst?

Ich benutze jetzt eine andere Funktion bei der ich den Speicher jetzt auch selbst reserviere und dann den Pointer dahin übergebe. Funktioniert genau so und ich kann ihn auch sauber mit FreeHGlobal() freigeben.

Hallo flippy08,

auch wenn du das Problem jetzt schon gelöst hast und egal, ob das im konkreten Fall eine Rolle gespielt hat, hier noch mal zur Sicherheit der folgenden generell wichtigen Hinweis:

You should never PInvoke to GetLastError. Call Marshal.GetLastWin32Error instead!

herbivore