2010-11-18 18 views
1

version courte:drapeaux GlobalAlloc pour Marshal.PtrToStructure

pourrait passer la poignée de GlobalAlloc (GMEM_MOVEABLE, Taille) à Marshal.PtrToStructure() et Marshal.FreeHGlobal() cause de la corruption de la mémoire?

Version longue:

J'utilise l'allocation de mémoire global Windows pour passer une structure de données et-vient entre Delphi et application C# (le fait qu'il est Delphi est pas vraiment significatif à cette question, parce qu'il est juste des appels API Win32).

Du côté Delphi, je passe dans un dossier, il alloue l'espace, verrouille la mémoire, copie la structure de en mémoire, et les déverrouille la mémoire:

function MarshalRec(SourceRec: TInteropItemRec): THandle; 
var 
    Size: integer; 
    Buffer: Pointer; 
begin 
    Size := sizeof(SourceRec); 
    result := GlobalAlloc(GMEM_MOVEABLE and GMEM_ZEROINIT, Size); 
    Buffer := GlobalLock(result); 
    try 
    CopyMemory(Buffer, @SourceRec, Size); 
    finally 
    GlobalUnlock(result); 
    end; 
end; 

Du côté C#, il obtient que THandle (qui est essentiellement un entier non signé) dans un IntPtr et utilise Marshal.PtrToStructure pour copier les données dans la structure C#:

public void FromMemory(IntPtr Source) 
{ 
    Marshal.PtrToStructure(Source, this); 
    Marshal.FreeHGlobal(Source); 
} 

le problème que je suis en cours d'exécution dans, est très rarement (comme en 4 fois plus de 6 mois pour moi), l'ensemble de l'application tombe en panne (cette application a en contré une erreur et doit fermer). Si j'essaie d'interrompre l'exécution dans Visual Studio, j'obtiens "Une erreur fatale s'est produite et le débogage doit être interrompu.Pour plus de détails, veuillez consulter le site Web d'aide et de support de Microsoft.HRESULT = 0x80131c08." De toute façon, nous avons réussi à obtenir quelques journaux de ce qui se passe, et dans les deux cas, il a montré un appel récent à cette fonction "MarshalRec" ci-dessus, quelques autres appels de fonction, puis un certain traitement des messages Windows sur le boucle d'événement sur le thread Delphi (oui, il a son propre thread et boucle d'événement pour faire face à un pilote de périphérique sensible au temps).

Donc, ma suspicion tombe sur l'indicateur GMEM_MOVEABLE à GlobalAlloc. Je n'ai rien trouvé dans la classe Marshal qui s'occupe des éléments GlobalLock et GlobalUnlock, donc j'avais supposé qu'il était géré en interne par PtrToStructure().

PtrToStructure traite-t-il correctement un handle ou a-t-il besoin d'un pointeur réel obtenu à partir de GlobalLock()? Est-il possible que dans de très rares cas, Windows arrive à déplacer la mémoire que j'ai allouée, ce qui signifie que j'ai besoin d'appeler GlobalLock() pour obtenir un pointeur réel à passer? Que FreeHGlobal libère réellement quelque chose qu'il ne devrait pas avoir, ce qui fait tomber toute l'application la prochaine fois que cette ressource est accessible?

Et si tel est le cas, est-ce que le fait de remplacer GMEM_MOVABLE par GMEM_FIXED empêcherait que cela se reproduise? Ou ai-je besoin de DllImport GlobalLock() et GlobalUnlock()?

Je suis tenté de faire ces changements aveuglément, mais étant donné la non-reproductibilité de ce problème, il n'y a aucun moyen de savoir s'il est corrigé jusqu'à ce qu'il se reproduise. Je cherche donc à savoir si ce code peut mener aux symptômes que je vois ou si j'ai besoin de commencer à proposer d'autres théories.

Répondre

2

Eh bien, vous violez explicitement le contrat pour GlobalAlloc(). Votre espoir que Marshal.PtrToStructure() appellera GlobalLock est infondé, il n'a aucun moyen de dire si le IntPtr passé est un handle ou un pointeur.

GlobalAlloc est une fonction héritée obsolète de l'ère Windows 3.x. Oui, il est fort probable que l'adresse soit retournée en tant que valeur de handle avec GlobalLock() étant une opération non-op. Mais il n'est certainement pas documenté pour le faire. CoTaskMemAlloc() est le meilleur piège à souris.

+0

Merci pour la confirmation. Sur la base du code des exemples sur lequel je me base, j'imagine qu'il y a quelques autres applications qui ne fonctionnent pas bien. Je souhaite que le commentaire XML pour Marshal.AllocHGlobal a précisé que CoTaskMem est préféré à HGlobal, étant donné le choix. –