Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从C调用C DLL#_C#_C_Dll_Pinvoke_Dllimport - Fatal编程技术网

C# 从C调用C DLL#

C# 从C调用C DLL#,c#,c,dll,pinvoke,dllimport,C#,C,Dll,Pinvoke,Dllimport,我正试图从C#调用一个C DLL,但我没有任何乐趣。DLL的文档为VB提供了一个示例函数delaration,如下所示: 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 Doub

我正试图从C#调用一个C DLL,但我没有任何乐趣。DLL的文档为VB提供了一个示例函数delaration,如下所示:

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
因此,我做了以下工作:

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));

    }

}
long __stdcall TransProjPt(LPSTR psGridFile, long lDirection, double dEasting, double
dNorthing, long lZone, double* pdEastNew, double* pdNorthNew, double* pdEastAcc,
double* pdNorthAcc) 
我仍然没有太多的运气,并尝试了各种其他设置在德林波特station,如; SetLastError=true,CharSet=CharSet.Auto,CallingConvention=CallingConvention.Cdecl)

我从代码中得到的输出是

Result was 4690529317195612196, Lat: 0, Long: 0
Last error recieved was 6
如果我在查看Win32错误信息方面是正确的,我认为这是指; 错误\u无效\u句柄无效。
6(0x6)

我猜可能是文件名作为字符串传递有问题,或者是我通过ref传递double的方式有问题?然而,我真的不知道,我不知道如何进一步调查这个问题

任何想法都非常感谢


谢谢

看起来你不是唯一遇到这个问题的人,你试过StdCall吗?这对这个家伙起到了作用:

您可能希望使用字符串参数的编组属性来定义您的c#签名

[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);
我还将借鉴马克·索乌尔的答案,说试试用StdCall而不是Cdecl打电话


另外,作为预防措施,我可能会再次检查以确保编译器设置为编译x86代码,以防编译为64位。

尝试将
string sGridFile
更改为
StringBuilder sGridFile


C++有太多不同类型的字符串,因此在托管代码和非托管代码之间封送字符串可能很棘手。

我使用一个名为; 正如我的建议

我使用这个工具输入一些C功能原型,并让它代表我生成所需的C#原型。C原型如下所示:

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));

    }

}
long __stdcall TransProjPt(LPSTR psGridFile, long lDirection, double dEasting, double
dNorthing, long lZone, double* pdEastNew, double* pdNorthNew, double* pdEastAcc,
double* pdNorthAcc) 
当将其输入Interop assistant工具时,它表明,与使用long(正如我在最初的问题中所做的那样)不同,long应该被声明为int。它产生了以下输出,这意味着我上面的代码现在可以像我所希望的那样工作。耶

    /// 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) ;
///返回类型:int
///psGridFile:LPSTR->CHAR*
///方向:int
///卸货:双倍
///多倍
///lZone:int
///pdEastNew:双人*
///pdNorthNew:双人*
///pdEastAcc:双人*
///PDACC:双倍*
[System.Runtime.InteropServices.DllImportAttribute(“”,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-pdeastc,ref-double-pdNorthAcc);

感谢大家的帮助。

您不需要通过ref传递double。在提供的头文件中,一些输出参数被定义为指向double的指针;//外部“C”长CCONV TransGeogPt(LPSTR,长,双,双,双*,双*,双*,双*)//外部“C”长CCONV TransProjPt(LPSTR、长、双、双、长、双*、双*、双*、双*);这会让你认为他们应该被引用吗?我尝试了一下,但还是得到了同样的结果。我也尝试过在文件名前面使用[Marshallas(UnmanagedType.LPStr)]的建议,但也没有成功。
StdCall
是默认的调用约定,他将根据自己的示例隐式使用该约定。感谢您的回复。我很兴奋,这可能是我需要的回应,但唉,这似乎也没有帮助。我也尝试过StdCall和Cdecl,但都没有用。谢谢你的建议,但似乎没有什么帮助。+1因为这只是我尝试的众多问题之一:)