2011-10-12 12 views
10

Così ho una funzione, scritto in C++, che assomiglia a questo ...Perché C# e VB.NET implicano in modo implicito il char * in modo diverso?

extern "C" __declspec(dllexport) int __stdcall SomeFunction(char *theData) 
{ 
    // stuff 
} 

... e sto usando nel mio progetto attuale (scritto in C#). Ci sono altri progetti che utilizzano questa funzione scritta in VB, guardando in questo modo:

Public Declare Function SomeFunction Lib "MyDLL.dll" _ 
    Alias "[email protected]" (ByVal theData As String) As Integer 

Così ho provato a scrivere un equivalente in C#, ma ha trovato che utilizzando il tipo di stringa in realtà non funziona per me - la stringa sarebbe torna con gli stessi dati con cui l'ho passato. Ho provato a utilizzare "ref string" invece di passare la stringa per riferimento e ho ricevuto una violazione di accesso alla memoria.

Dopo aver fatto qualche scavo, ho scoperto che questo era la corretta applicazione in C#:

[DllImport("MyDLL.dll", EntryPoint = "[email protected]")] 
public static extern int SomeFunction(StringBuilder theData); 

Ora so che VB.NET e C# sono molto diverse, ma suppongo che ho sempre dato per scontato che le stringhe sono stringhe . Se una lingua può eseguire il marshalling char* a String implicitamente, perché l'altro non può richiedere una classe diversa del tutto?

(a cura del titolo per chiarezza)

+0

Potrebbe essere interessante dare un'occhiata a entrambe le versioni con JustDecompile o .NET Reflector. –

risposta

6

Ora so che VB.NET e C# sono molto diverse, ma suppongo che ho sempre dato per scontato che le stringhe sono stringhe

stringhe sono immutable in .NET. Chiediti perché è possibile che il passaggio di un tipo di dati immutabile ByVal possa modificare il valore. Ciò non accade per le normali funzioni, solo per Declare.

Suppongo che tutto ciò abbia a che fare con il mantenimento della compatibilità con le versioni precedenti di Declare dal classico VB6 che sono state eseguite in questo modo. A mio parere, la pecora nera qui è il codice VB.net piuttosto che il codice C#.

+0

Inoltre, solo "Dichiarazione" fa questo.'' no (VB fa cose divertenti con i parametri ByRef per permetterti di passare in proprietà e costanti, ma questo non è uno di loro) – Random832

+1

+1. Questo è assolutamente ** per la retrocompatibilità ** con l'istruzione 'Declare' VB6. Nel nuovo codice VB.Net potresti preferire "". Nella loro saggezza, i progettisti di VB6 hanno deciso che 'ByVal As String' in un' Declare 'VB6 sarebbe equivalente a un 'char *'. Dietro le quinte, il runtime VB6 crea una copia della stringa Unicode originale nel formato "ANSI" in base all'attuale code page di Windows e passa l'indirizzo della copia alla DLL. Per completezza, ecco [la documentazione originale di Microsoft VB6] (http://vb.mvps.org/tips/vb5dll.asp) sull'integrazione di DLL con VB6. – MarkJ

3

Perché sono diverse lingue. VB.NET può fare moltissime cose che C# non può per molte ragioni. Non vedo il problema ad essere onesto.

Vorrei aggiungere che avresti potuto semplicemente fare ref char [] e avrebbe funzionato. Un problema che vedo è che le convenzioni di chiamata non corrispondono.

Quindi è anche probabile che si sia verificato un errore di eccezione di memoria.

+0

Le convenzioni di chiamata vanno bene, 'stdcall' in tutto il codice sopra. AV è perché 'ref string' semplicemente non corrisponde a' char * '. Devo usare 'StringBuilder' in C# per quello. Non c'è modo che il codice nativo possa costruire un oggetto .net String valido. –

0

Poiché la stringa è immutabile per cominciare, suppongo che VB in qualche modo esegua la chiamata per consentire al buffer di essere modificato dalla funzione. Forse internamente anche VB sta passando un StringBuilder.

Non sarei sorpreso se si trattasse di una chiamata di progettazione da parte del team VB per rendere le chiamate API più simili a VB6.

Problemi correlati