C chiamata DLL in C#

Sto cercando di chiamare una DLL C, C#, ma io non avendo alcuna gioia. La documentazione per la DLL fornisce un esempio di funzione delaration per VB che sembra;

Declare Function TransGeogPt Lib "c:\DLLS\GDAit.dll" (ByVal sGridFile As String, ByVal lDirection As
Long, ByVal dLat As Double, ByVal dLong As Double, pdLatNew As Double, pdLongNew As Double,
pdLatAcc As Double, pdLongAcc As Double) As Long

Declare Function TransProjPt Lib "c:\DLLS\GDAit.dll" (ByVal sGridFile As String, ByVal lDirection As
Long, ByVal dLat As Double, ByVal dLong As Double, ByVal lZone As Long, pdLatNew As Double,
pdLongNew As Double, pdLatAcc As Double, pdLongAcc As Double) As Long

Ho quindi fatto le seguenti;

public class GDAIt
{
    public static string gridFileName = @"C:\Nat84.gsb";

    [DllImport(@"c:\GDAit.dll")]
    public static extern long TransGeogPt(string sGridFile, long lDirection, double dLat, double dLong, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc);

    [DllImport(@"c:\GDAit.dll")]
    public static extern long TransProjPt(string sGridFile, long lDirection, double dLat, double dLong, long lZone, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc);

    public static long CallTransGeogPt(string sGridFile, long lDirection, double dLat, double dLong, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc)
    {
        return TransGeogPt(sGridFile, lDirection, dLat, dLong, ref pdLatNew, ref pdLongNew, ref pdLatAcc, ref pdLongAcc);
    }

    public static long CallTransProjPt(string sGridFile, long lDirection, double dLat, double dLong, long lZone, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc)
    {
        return TransProjPt(sGridFile, lDirection, dLat, dLong, lZone, ref pdLatNew, ref pdLongNew, ref pdLatAcc, ref pdLongAcc);
    }


    public static void Process()
    {
        double latitude = 0.0;
        double longitude = 0.0; 
        double latAcc = 0.0; 
        double longAcc = 0.0;

        long result = 0;
        result = CallTransProjPt(gridFileName,
                                        1,
                                        394980,
                                        7619799,
                                        51,
                                        ref latitude,
                                        ref longitude,
                                        ref latAcc,
                                        ref longAcc);
        Console.WriteLine(string.Format("Result was {0}, Lat: {1}, Long: {2}", result, latitude, longitude));

        int error = Marshal.GetLastWin32Error();

        Console.WriteLine(string.Format("Last error recieved was {0}", error));

    }

}

Io ancora non sto avendo molta fortuna e hanno provato varie altre impostazioni nel DLLImport statment come;
SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)

L’output mi da il codice;

Result was 4690529317195612196, Lat: 0, Long: 0
Last error recieved was 6

Se ho ragione, guardando le info per Win32 errori, penso che si riferisce;
ERROR_INVALID_HANDLE L’handle non valido.

6 (0 x 6)

La mia ipotesi è che c’è un problema con il passaggio nel nome del file come una stringa o il modo in cui sto passando doppie da ref? Tuttavia, non so davvero, e io sono in perdita su come indagare il problema.

Tutte le idee sono molto apprezzati.

Grazie.

Non c’è bisogno di passare per il doppio da ref.
Nell’intestazione del file fornito, alcuni dei parametri di output sono definiti come puntatori a doppie; // extern “C” lungo CCONV TransGeogPt(LPSTR, long, double, double, double*, double*, double*, double*); //extern “C” lungo CCONV TransProjPt(LPSTR, long, double, double, long, double*, double*, double*, double*); che ti fanno pensare che dovrebbero essere da riferimento? Ho provato senza, ma ho ancora lo stesso risultato. Ho provato anche il suggerimento di [MarshalAs(UnmanagedType.LPStr)] davanti al nome di file, ma senza fortuna.

OriginaleL’autore Mr Moose | 2011-04-14

4 Replies
  1. 6

    Ho trovato il motivo del mio tentativi utilizzando uno strumento chiamato;
    Microsoft(R) P/Invoke Assistente Di Interoperabilità come suggerito da una risposta su questo thread.

    Ho utilizzato questo strumento per input di alcuni dei C prototipi di funzione e arrivare a generare il C# prototipo sul mio conto. Il prototipo C sembrava essere la seguente;

    long __stdcall TransProjPt(LPSTR psGridFile, long lDirection, double dEasting, double
    dNorthing, long lZone, double* pdEastNew, double* pdNorthNew, double* pdEastAcc,
    double* pdNorthAcc) 

    Quando entrando in questo in assistente di Interoperabilità, lo strumento ha mostrato che, anziché utilizzare long (come avevo fatto nella mia domanda originale), questi dovrebbero essere dichiarata come int. Ha prodotto il seguente risultato, che significava il mio codice qui sopra, ora ha funzionato come speravo. Yay.

        ///Return Type: int
        ///psGridFile: LPSTR->CHAR*
        ///lDirection: int
        ///dEasting: double
        ///dNorthing: double
        ///lZone: int
        ///pdEastNew: double*
        ///pdNorthNew: double*
        ///pdEastAcc: double*
        ///pdNorthAcc: double*
        [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="TransProjPt", CallingConvention=System.Runtime.InteropServices.CallingConvention.StdCall)]
    public static extern  int TransProjPt([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] System.Text.StringBuilder psGridFile, int lDirection, double dEasting, double dNorthing, int lZone, ref double pdEastNew, ref double pdNorthNew, ref double pdEastAcc, ref double pdNorthAcc) ;

    Grazie per l’aiuto di tutti, con questo.

    +1 Contenta di vedere che hai trovato una soluzione!

    OriginaleL’autore Mr Moose

  2. 3

    Si possono definire in c# firme tramite il marshalling di attributi per la stringa di parametri.

    [DllImport(@"c:\GDAit.dll")]
    public static extern long TransGeogPt([MarshalAs(UnmanagedType.LPStr)] string sGridFile, long lDirection, double dLat, double dLong, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc);
    
    [DllImport(@"c:\GDAit.dll")]
    public static extern long TransProjPt([MarshalAs(UnmanagedType.LPStr)] string sGridFile, long lDirection, double dLat, double dLong, long lZone, ref double pdLatNew, ref double pdLongNew, ref double pdLatAcc, ref double pdLongAcc);

    Io anche piggy-back Mark Sowul la risposta di dire provare a chiamare con StdCall invece di Cdecl.

    Anche, come precauzione, probabilmente sarei doppio controllo per assicurarsi che il compilatore è impostato per compilare il codice x86, in caso di compilazione a 64-bit.

    StdCall è la convenzione di chiamata predefinita, che egli sarebbe utilizzando implictly secondo il suo esempio.
    Grazie per la risposta. Ero molto eccitato che questa potrebbe essere la risposta di cui avevo bisogno, ma, ahimè, non mi sembra di aver aiutato. Ho anche provato entrambi StdCall e Cdecl, ma senza alcun risultato.
    +1 come questo ha finito per essere parte della soluzione globale.

    OriginaleL’autore villecoder

  3. 2

    Provare a cambiare string sGridFile per StringBuilder sGridFile

    C++ ha così tanti diversi tipi di stringhe di marshalling di stringhe tra la gestione e il codice non gestito può essere difficile.

    Grazie per il tuo suggerimento, ma non mi sembra di aver aiutato.
    +1 come questo ha finito per essere solo uno dei molti problemi con il mio tentativo 🙂

    OriginaleL’autore Mark Arnott

Lascia un commento