c# - 从 C# 调用 C DLL

标签 c# c dll pinvoke dllimport

我正在尝试从 C# 调用 C DLL,但我并不高兴。 DLL 的文档为 VB 提供了一个示例函数声明,如下所示;

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

    }

}

我仍然不太走运,并且尝试了 DLLImport 语句中的各种其他设置,例如; SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)

我从代码中得到的输出是;

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

如果我在查看有关 Win32 错误的信息时是正确的,我认为它指的是; ERROR_INVALID_HANDLE 句柄无效。
6 (0x6)

我的猜测是将文件名作为字符串传递有问题,还是我通过 ref 传递 double 值的方式有问题?但是,我真的不知道,而且我不知道如何进一步调查这个问题。

非常感谢任何想法。

谢谢。

最佳答案

我通过使用一个名为的工具找到了尝试失败的原因; Microsoft(R) P/Invoke Interop Assistant正如 an answer on this thread 所建议的那样.

我利用这个工具输入了一些 C 函数原型(prototype),并让它为我生成所需的 C# 原型(prototype)。 C 原型(prototype)如下所示;

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

将此输入到 Interop 助手工具时,它表明不应使用 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) ;

感谢大家对此的帮助。

关于c# - 从 C# 调用 C DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5664737/

相关文章:

python - 在 Python 中使用 .NET dll

c++ - 如何将 Crypto++ 库移植到 AIR Native Extension for Windows?

c# - 从 Task.Run 获取返回值

c - 哪一个更好?做{}而(0);或转到 xy;

c - 最好的方法(是/否)

android - 指示 gnu make 仅使用静态库

python - Windows 上的 ctypes : depending dlls not found

c# - 在 RavenDb 中建立一对多模型以获得更好的性能

c# - CA1309 是否仍然对针对 .NET 4.5.1 编译的源代码有效?

c# - C# 中的欧拉项目 8