2009-02-16 11 views
0

J'essaie d'utiliser une DLL non managée dans VB.NET. L'exemple de code source fourni avec la DLL est en VB6 et ci-dessous est ma tentative de le convertir en .NET. Lorsque la DLL tente d'effectuer un rappel, j'obtiens une exception «Tentative de lecture ou d'écriture de mémoire protégée». Je ne me soucie pas vraiment de la fonction de rappel appelée. Mon code:Fonction de rappel à partir d'une DLL non gérée dans VB .NET

<DllImport("AlertMan.dll")> _ 
Public Shared Function AlertManC(_ 
    ByVal CallbackAddr As AlertManCallbackDel) As Long 
End Function 

Public Delegate Sub AlertManCallbackDel(ByVal data As Long) 

Public Sub AlertManCallback(ByVal data As Long)  
End Sub 

Public mydel As New AlertManCallbackDel(AddressOf AlertManCallback) 
'protected memeory exception here 
Dim IStat as Long = AlertManC(mydel) 

exemple de code original VB6:

Declare Function AlertManC _ 
    Lib "AlertMan.dll" _ 
    Alias "AlertManC" (ByVal CallbackAddr As Long) As Long 

Private Sub AlertManCallback(ByVal data As Long) 
End Sub 

' calling code 
Dim IStat As Long 
IStat = AlertManC(AddressOf AlertManCallBack) 

tête dll originale

typedef void TACBFUNC(char *); 
int AlertManC(TACBFUNC *WriteCaller cHANDLEPARM); 

Répondre

2

Pouvez-vous poster le definiton natif original pour AlertManC? Je suppose cependant que le paramètre de données de la fonction de rappel est en fait un entier par rapport à un long. En VB6, je crois que ceux de Long n'étaient en réalité que de 32 bits contre VB.Net où ils sont en 64 bits. Essayez cette

<DllImport("AlertMan.dll")> _ 
    Public Shared Function AlertManC(ByVal CallbackAddr As AlertManCallbackDel) As Long 
    End Function 

    Public Delegate Sub AlertManCallbackDel(ByVal data As IntPtr) 


    Public Sub AlertManCallback(ByVal data As IntPtr)  
    End Sub 

Modifier

Je mis à jour le code basé sur la signature native que vous avez publié. Pouvez-vous essayer cela?

+0

Merci, vous bercez! Changer de long en nombre était le problème! Votre solution originale aurait aussi bien fonctionné. il y a en fait 7 autres paramètres sur la méthode que j'ai enlevé pour la brièveté (honte à moi). Les changer en entiers était l'astuce. – Michael

0

Votre rappel devrait ressembler à ceci:

Public Delegate Sub AlertManCallbackDel(ByRef data As Byte) 

La raison de cet être que vous passez une valeur unique octet par référence.

En ce qui concerne la déclaration de la fonction non gérée, il devrait ressembler à ceci:

<DllImport("AlertMan.dll")> _ 
Public Shared Function AlertManC(_ 
    ByVal CallbackAddr As AlertManCallbackDel) As Integer 
End Function 

Notez que le type de retour est un nombre entier, qui VB.NET est une valeur 32 bits. En VB6, un Long était une valeur de 32 bits, d'où la nécessité d'un changement dans VB.NET.

La définition de rappel est également importante pour être correcte, btw.

+0

L'ajout d'un octet ByRef est potentiellement dangereux. Imaginez ce qui se passe si le code natif passe NULL. Je pense que le CLR générera une exception dans ce cas car par défaut, un ByRef est géré dans les deux sens. – JaredPar

+0

@Jared: Je suis d'accord, tout dépend de la documentation et de la garantie du code qui est implémenté. Cependant, dans la plupart des cas, cela suffira. – casperOne

0

Si la convention d'appel du rappel est cdecl, vous ne pouvez pas le faire directement dans C# ou VB.NET.

Vous devrez modifier l'IL du délégué pour qu'il se comporte correctement.

Vous pouvez effectuer une recherche sur CodeProject pour un article détaillé.

Mise à jour:

Je devine pas la bonne réponse :) Mais laissera ma réponse.