2009-03-25 9 views
1

est ici un simple problème que je dois résoudre, mais il me fait sentir mes cheveux grisonnants que toutes mes tentatives sont me retourner la même erreur:Appel fonction dll C++ de C#: Des struct, des chaînes et des tableaux wchar_t

"Tentative de lecture ou d'écriture de la mémoire protégée, ce qui indique souvent que d'autres mémoires sont corrompues."

J'ai un exemple d'application écrite en C++ qui appelle la DLL. Voici le code correspondant:

//function I need to call 
bool convertHKID_Name(char *code,RECO_DATA *o_data); //hkid 

//struct definition 
struct RECO_DATA{ 
    wchar_t FirstName[200]; 
    wchar_t Surname[200]; 
}; 

//how it is used in C++ code 
CString code; 
RECO_DATA data; 
GetDlgItemText(IDC_CODE,code); 
char _code[200]; 
WideCharToMultiByte(CP_UTF8, 0, code, -1, (char *)_code, 200, NULL, NULL); 
ocr->convertHKID_Name(_code,&data) 

Maintenant, quand je déboguer le code C++, il fait la bonne chose - écrit des données Unicode dans la structure de données.

Voici ma tentative de faire la même chose en C#

//my C# wrapper class 
public class cnOCRsdk 
{ 
    [StructLayout(LayoutKind.Sequential, Size=400, CharSet=CharSet.Unicode), Serializable] 
    public struct RECO_DATA 
    { 
     [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)] 
     public string FirstName; 
     [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)] 
     public string Surname; 
    }; 

    [DllImport(@"cnOCRsdk.dll", CharSet=CharSet.Auto, EntryPoint = "[email protected]@@[email protected]@@Z")] 
    public static extern bool convertHKID_Name(ref string num, ref RECO_DATA o_data); 

    [DllImport("Kernel32.dll")] 
    public static extern int WideCharToMultiByte(uint CodePage, uint dwFlags, 
     [In, MarshalAs(UnmanagedType.LPWStr)]string lpWideCharStr, 
     int cchWideChar, 
     [Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder lpMultiByteStr, 
     int cbMultiByte, 
     IntPtr lpDefaultChar, // Defined as IntPtr because in most cases is better to pass 
     IntPtr lpUsedDefaultChar // NULL 
     ); 
} 

//my attempt to call the function from the dll 
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA(); 
string num = "262125355174"; 
StringBuilder sb = new StringBuilder(200, 200); 
cnOCRsdk.WideCharToMultiByte(65001, 0, num, -1, sb, 200, IntPtr.Zero, IntPtr.Zero); 
string sbTostring = sb.ToString(); 
//the next line generates the 'Attempted to read or write protected memory' error 
bool res = cnOCRsdk.convertHKID_Name(ref sbTostring, out recoData); 

Je pense que je ne suis pas Marshaling la structure RECO_DATA correctement, car il est ce struct qui obtient écrit par la fonction convertHKID_Name. Mais comment dois-je le réparer?

Répondre

2

je crois qu'il devrait fonctionner si vous

  1. Modifier la déclaration sur convertHKID_Name-CharSet.Ansi
  2. supprimer le « ref » de la chaîne paramètre
  3. passer le string num directement à convertHKID_Name à la place de l'appel WideCharToMultiByte
+0

N'a pas travaillé encore, je pense toujours qu'il doit y avoir un problème avec la structure marshaling. Quelle est la raison en passant la chaîne directement sans ref, la déclaration de la fonction C++ accepte le code char *, et je suppose qu'un pointeur char signifie que la valeur doit être passée par référence? – Evgeny

+0

Une chaîne est toujours transmise par adresse. "Par référence" signifie que vous allez mettre à jour la valeur et attendre que la valeur modifiée soit renvoyée au programme appelant. –

+0

Oh, et essayez de déclarer le paramètre RECO_DATA comme "out" au lieu de "ref" - encore une fois, vous ne voulez que marshaled dans une direction. –

Questions connexes