2012-01-04 14 views
6

ho dichiarato un'importazione DLL nel mio programma C# che assomiglia a questo:funzione più chiamate da C# per C++ codice non gestito provoca AccessViolationException

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
      CallingConvention = CallingConvention.Cdecl)] 
static extern IntPtr generateKeyCode(char[] serial, char[] option, char c_type); 

Si fa riferimento alla funzione generateKeyCode() interno del mio DLL.

Qui è il codice che sta causando un errore (punti di interruzione utilizzati):

const char* generateKeyCode(char serial[], 
       char option[], 
       char c_type) 
{ 
returnBufferString = ""; 
SHA1_CTX context; 
int optionLength = 0; 
#ifdef WIN32 
unsigned char buffer[16384] = {0}; 
#else 
unsigned char buffer[256] = {0}; 

#endif 
//char output[80]; 
char keycode[OPTION_KEY_LENGTH+1]  = ""; 
int digest_array_size = 10; //default value for digest array size 
unsigned char digest[20] = {0}; 
char optx[24] = {0}; 
char c_type_upper; 
// Combine serial # and Option or Version number 

char str1[30] = {0}; 
int i; 
int size = 0; 
int pos = 0; 


... 
... 
} 

Fondamentalmente, ho importato questa DLL in modo da poter passare i parametri di funzione e potrebbe fare il suo algoritmo e semplicemente mi restituire un risultato . Ho usato questa funzione di marshalling ...

public static string genKeyCode_marshal(string serial, string option, char type) 
{ 
    return Marshal.PtrToStringAnsi(generateKeyCode(serial.ToCharArray(), 
      option.ToCharArray(), type)); 
} 

... così ho potuto effettuare correttamente la chiamata. All'interno del mio file di intestazione C++, ho definito una stringa, come indicato è utile nella risposta a questo question (è la variabile returnBufferString presente nella parte superiore della funzione C/C++).

Faccio questa chiamata di funzione più volte mentre utilizzo un controllo NumericUpDown per passare da 1,0 a 9,9 con incrementi di 0,1 (ciascuno verso l'alto o verso il basso accompagna un'altra chiamata di funzione), quindi di nuovo indietro. Tuttavia, ogni volta che provo a farlo, il programma si aggancia dopo un numero apparentemente impostato di chiamate di funzione (si ferma a 1,9 sulla via del ritorno se procedo semplicemente su e giù, o prima se mi alternano su e giù un po ') .

Si prega di notare che funziona e mi dà il valore che voglio, non ci sono discrepanze lì.

Ho cambiato la dimensione del buffer in un numero più piccolo (5012) e quando ho provato a eseguire il programma, alla prima chiamata di funzione ha gettato l'AccessViolationException. Tuttavia, raddoppiando la dimensione del buffer a due volte (32768) l'originale non ha avuto alcun effetto rispetto all'originale - salendo direttamente a 9,9 da 1,0 e in basso di nuovo, si ferma a 1,9 e genera l'eccezione.

MODIFICA: l'impostazione predefinita è ANSI, quindi ANSI. Nessun problema lì. È un problema di allocazione della memoria ??

+0

Dopo ulteriori test, sembra che la funzione abbia problemi di memoria indipendentemente da quando o dove viene chiamata in quel momento, le mie stampe di debug mostrano che ci sono un sacco di valori spazzatura nello stream, e così genera la chiave sbagliata. Sento che questo è probabilmente correlato. –

+0

Un carattere in C# è largo 2 byte. In C, char è solo 1 byte (penso che avresti bisogno di essere un wchar_t per essere 2 byte a seconda delle opzioni del compilatore). Vorrei iniziare da lì. –

risposta

0

So che questo può non essere soddisfacente, ma una volta che ho tolto il reindirizzamento uscita stavo usando per eseguire il debug da dentro il mio C/C++ DLL, il problema si fermò . Tutto funziona ora, quindi credo che sia essenzialmente equivalente a rispondere alla mia domanda. Grazie a tutti per le risposte.

2

vorrei suggerire di provare la seguente:

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
     CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern IntPtr generateKeyCode(string serial, string option, char c_type); 

Nota il nuovo CharSet campo dell'attributo DllImport.

idea successiva è quella di utilizzare MarshalAs attributo esplicitamente:

[DllImport("C:\\c_keycode.dll", EntryPoint = "generateKeyCode", 
     CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] 
static extern IntPtr generateKeyCode([MarshalAs(UnmanagedType.LPTStr)] string serial, [MarshalAs(UnmanagedType.LPTStr)] string option, char c_type); 
+0

Ciao Krizz. Mi ha preso .1 ulteriormente (mi ha portato a 1,9 invece di 2,0 sulla via del ritorno verso il basso). Ci avevo pensato ma non pensavo che sarebbe stato d'aiuto. Grazie per la risposta però. –

+0

Hai provato entrambi? Ho aggiunto una modifica. – Krizz

+0

potrebbe essere, ma il punto è anche fare affidamento su CLR per eseguire il marshall 'stringa' invece di usare' char [] '. Lo hai cambiato anche tu? – Krizz

Problemi correlati