2010-12-13 5 views
2

Je suis en train d'écrire dll plugin qui doit mettre en œuvre la fonction suivante:Comment marshaler un pointeur vers un tableau de pointeurs vers des structures de code managé à non managé?

int GetFunctionTable(FuncDescStruct **ppFunctionTable); 

donc mon code plugin en C# déclare ceci:

public static unsafe int GetFunctionTable(IntPtr functionTablePtr); 

Cette fonction sera appelée et devrait remplir functionTablePtr avec pointeur sur un tableau de structures décrivant l'ensemble des fonctions de rappel.

En plaine C/C++, il ressemble à quelque chose comme:

// declare func table 
// VExampleF1, VExampleF2 - are function pointers 
FuncDescStruct funcTable[] = { 
    "ExampleF1", { VExampleF1, 0, 0, 0, 0, NULL }, //filling descriptions. 
    "ExampleF2", { VExampleF2, 1, 0, 1, 0, NULL } 
    }; 

int GetFunctionTable(FuncDescStruct **ppFunctionTable) 
{ 
*ppFunctionTable = funcTable; // how to do this correctly in C#? 

// must return the number of functions in the table 
return funcTableSize; 
} 

Je suis en train de faire ce qui suit:

static unsafe FunctionTag[] funcTable; 
    static List<IntPtr> allocatedMemory; 
    public static unsafe int GetFunctionTable(IntPtr functionTablePtr) 
    { 

     //create just one test callback description 
     funcTable = new FunctionTag[1]; 

     funcTable[0].Name = "VExampleF1"; 
     funcTable[0].Description.Function = VExampleF1; 
     funcTable[0].Description.ArrayQty = 0; 
     funcTable[0].Description.FloatQty = 0; 
     funcTable[0].Description.StringQty = 0; 
     funcTable[0].Description.DefaultQty = 0; 
     funcTable[0].Description.DefaultValues = null; 

     // saving allocated memory for further cleanup 
     allocatedMemory = new List<IntPtr>(); 

     int intPtrSize = Marshal.SizeOf(typeof(IntPtr)); 
     IntPtr nativeArray = Marshal.AllocHGlobal(intPtrSize * funcTable.Length); 
     for (int i = 0; i < funcTable.Length; i++) 
     { 
      IntPtr nativeFD = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FunctionTag))); 
      allocatedMemory.Add(nativeFD); 
      Marshal.StructureToPtr(funcTable[i], nativeFD, false); 

      Marshal.WriteIntPtr(nativeArray, i * intPtrSize, nativeFD); 
     } 

     Marshal.WriteIntPtr(functionTablePtr, nativeArray); 

     return funcTable.Length; 
    } 

Ce code ne fonctionne pas, et la question est de savoir comment envoyer un pointeur vers un tableau de structures gérées pour une utilisation par du code non managé? Dans quelle direction dois-je aller?

Répondre

0

Vous devez utiliser la construction de fixation pour fixer le tampon en place, car le C# GC se réserve le droit de le déplacer si vous ne le faites pas, ce qui invalide le pointeur. Je ne sais pas comment réparer un tampon indéfiniment. Vous allez devoir vous inquiéter de la façon dont cette mémoire est gérée, aussi.

2

Nous avons fait beaucoup de ce genre de choses au cours des dernières années. Nous utilisons un ensemble 'pont' en mode mixte pour gérer les appels de fonction de mappage et les données de regroupement entre les environnements gérés et non gérés. Nous utilisons souvent une classe 'mixed-mode' pour envelopper une classe managée, fournissant une interface native pour appeler sa fonctionnalité.

Considérons votre problème. Vous pouvez écrire GetFunctionTable dans C++ géré. Il peut appeler du code C# managé pour obtenir les informations de la fonction dans une structure gérée, puis le "marshall" dans la structure native.

In (C#) une version gérée de la fonction GetFunctionTable:

delegate void FunctionDelegate(); 

public struct FuncDescStructManager 
{ 
    public string Name; 
    public FunctionDelegate Function; 
    //... 
} 

public static List<FuncDescStructManager> GetFunctionTableManaged() 
{ 
    List<FuncDescStructManager> list = new List<FuncDescStructManager>(); 
    list.Add(new FuncDescStructManaged() {"ExampleF1", VExampleF1}); 
    return list; 
} 

Dans l'ensemble de pont en mode mixte, vous pouvez mettre en œuvre la fonction native GetFunctionTable, appelant la fonction gérée et marshalling les données:

int GetFunctionTable(FuncDescStruct **ppFunctionTable) 
{ 
    // Call the managed function 
    List<FuncDescStructManaged>^ managedList = GetFunctionTableManaged(); 

    nativeArray = malloc(managedList.Length * sizeof(FuncDescStruct)); 
    int i=0; 
    foreach (FuncDescStructManaged managedFunc in managedList) 
    { 
     // Marshall the managed string to native string could look like this: 
     stringPtr = Marshal::StringToHGlobalUni(managedFunc.Name); 
     nativeArray[i].Name = ((wchar_t*)stringPtr.ToPointer()); 
     Marshal::FreeHGlobal(stringPtr); 

     // Marshall a delegate into a native function pointer using a 
     // wrapper class: 
     WrapDelegateAsPtr funcPtr = new WrapDelegateAsPtr(managedFunc.Function); 
     // funcPtr will need to be deleted by caller 
     nativeArray[i].Function = funcPtr.NativeFunction; 
     i++; 
    } 
    return i; 
} 

// Mixed mode wrapper class 
// Member is a reference to a managed delegate. 
// Because we need to reference this from native code, the wrapped 
// delegate will be stored as a void*. 
class WrapDelegateAsFPtr 
{ 
    public: 
    WrapDelegateAsNativeFunctionPointer(FunctionDelegate _delegate) 
    { 
     delegate = _delegate; 
     // Tell the garbage handler not to remove the delegate object yet 
     GCHandle gch = GCHandle::Alloc(svgContents); 
     managedDelegatePtr = GCHandle::ToIntPtr(gch).ToPointer();  
    } 

    ~WrapDelegateAsNativeFunctionPointer 
    { 
     // Tell the garbage collector we are finished with the managed object 
     IntPtr temp(managedDelegatePtr;); 
     GCHandle gch = static_cast<GCHandle>(temp); 
     gch.Free(); 
    } 

    void NativeFunction() 
    { 
    } 

    private: 
     void* managedDelegatePtr; 
} 

Espérons que cela aide - Pour toute question il suffit de demander!

1

C'est une réponse plutôt tardive, mais je me suis heurté exactement au même problème. J'ai implanté un DATA PLUGIN en utilisant le framework de Kostya, et je l'ai fait fonctionner parfaitement, puis en essayant d'implémenter un plugin AFL, j'ai rencontré le problème ci-dessus. J'ai réussi à obtenir itworking sans utiliser une classe de rappeur C++. Le problème provient du pointeur/de la référence/de l'adresse de fonction transmis par FUnctionTable. AS ces fonctions ont été déclarées STATIC à des fins EXPORT, elles sont incompatibles avec l'implémentation de délégué C++ dans la méthode GETFUNCTIONTABLE.SI vous DDO ce qui suit, il devrait fonctionner: -

Ajouter les 2 signatures: -

[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 
static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
internal static extern IntPtr LoadLibrary(string lpFileName); 

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
internal static extern bool SetDllDirectory(string lpPathName); 
  • la définition de référence de fonction dans la structure GetFunctionTable doit être modifiée: IntPtr Fonction;

  • Ajoutez les instructions suivantes pour obtenir l'adresse de fonction exportée: -

    IntPtr dllHandle = LoadLibrary(fullPath); 
    IntPtr fptr = GetProcAddress(dllHandle, "VfmExample1"); 
    

et enfin initialiser la variable de fonction dans la structure GetFunctionTable, par exemple

functable[0].Description.function = fptr; 

et qui devrait le faire

Questions connexes