【问题标题】:How to export a global variable from a C++ DLL?如何从 C++ DLL 导出全局变量?
【发布时间】:2015-03-26 17:17:28
【问题描述】:

问题是我试图从 C# 程序访问在 C++ DLL 中声明的全局变量。即使我在重复调用的函数(本例中为减法)中将变量设置为 15,但每次调用 getter(本例中为除法)时,返回值为零。 所以这是我的代码。头文件:

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

namespace MathFuncs
{
    class MyMathFuncs
    {
    public: 
        static MATHFUNCSDLL_API double Add(double a, double b); 

        static MATHFUNCSDLL_API double Subtract(double a, double b); 

        static MATHFUNCSDLL_API double Multiply(double a, double b); 

        static MATHFUNCSDLL_API double Divide(double a, double b); 
    };
}

C++ 代码:

__declspec(dllexport) double signID; //this is my variable

__declspec(dllexport) double __cdecl MyMathFuncs::Subtract(double a, double b){
   //.. some code
   signID = 15; //this function is the setter
}

__declspec(dllexport) double __cdecl MyMathFuncs::Divide(double a, double b)
{
    return signID; //this function is the getter, it return zero when called from C#
}

在我的 C# 代码中,我使用了此处找到的方法:http://www.quantcode.com/modules/smartfaq/faq.php?faqid=95 我不断从 getter 函数获得零返回值,为什么,以及如何解决这个问题?

编辑:C# 代码:

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;


static class NativeMethods
{

    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}

public class SignDetector : MonoBehaviour
{

    //Lets make our calls from the Plugin
    [DllImport("CVDetectorDLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?Add@MyMathFuncs@MathFuncs@@SANNN@Z")]

    private static extern double add(double a, double b);
    [DllImport("CVDetectorDLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?Subtract@MyMathFuncs@MathFuncs@@SANNN@Z")]

    private static extern double subtract(double a, double b);
    [DllImport("CVDetectorDLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?Multiply@MyMathFuncs@MathFuncs@@SANNN@Z")]

    private static extern double multiply(double a, double b);
    [DllImport("CVDetectorDLL", CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?Divide@MyMathFuncs@MathFuncs@@SANNN@Z")]

    private static extern double divide(double a, double b);

    double myvariable;

    void Start(){
        subtract(0, 0); //here we invoke the setter

        IntPtr mydll = NativeMethods.LoadLibrary("CVDetectorDLL.dll");

        //get a pointer to unmanaged heap address
        IntPtr addrUnmanagedHeap = NativeMethods.GetProcAddress(mydll, "signID");

        if (addrUnmanagedHeap != IntPtr.Zero)
        {
            //convert and read memory from unmanaged pointer 
            myvariable = Marshal.ReadInt32(addrUnmanagedHeap);

        }
    }

    void Update(){

        Debug.Log("Found = " + myvariable); //prints zero
        Debug.Log("Found = " + divide(0,0));  //getter
    }
}

【问题讨论】:

  • 请您添加您的 C# 代码

标签: c# c++ variables dll unity3d


【解决方案1】:

我猜(没有看到问题出在调用约定中的 C# 代码。如 MSDN __cdecl 所述,__cdecl 是 C++ 的默认值)

这意味着调用函数负责堆栈。在这种情况下,您的 .net 程序。 c# 默认使用 __stdcall 的调用约定。这对于接受或返回参数的方法非常重要,因为它决定了堆栈的行为方式。

我已经包含了应该向您展示如何完成这项工作的代码。

c++代码头

#define DLLEXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C" { //Used to prevent name mangling on dll export
#endif //__cplusplus

double signID;

DLLEXPORT void __stdcall SetDoubleValue();
DLLEXPORT double __stdcall ReturnDoubleValue(double dummyone, double dummytwo);

#ifdef __cplusplus
}
#endif //__cplusplus

c++

void __stdcall SetDoubleValue()
{
    signID = 15;
}

double __stdcall ReturnDoubleValue(double dummyone, double dummytwo)
{
    return signID;
}

c#导入代码

[DllImport("DllExport.dll")]
public static extern void SetDoubleValue();

[DllImport("DllExport.dll")]
public static extern double ReturnDoubleValue(double dummyone, double dummytwo);

请注意,如果您不能或不想从 __cdecl 更改,您也可以将您的 c# 定义更改为

[DllImport("DllExport.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetDoubleValue();

[DllImport("DllExport.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern double ReturnDoubleValue(double dummyone, double dummytwo);

【讨论】:

    【解决方案2】:

    看起来我的原始代码和发布的解决方案确实可以工作 - 我似乎误认了实际上不在 DLL 中的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-10
      • 1970-01-01
      • 2018-12-06
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多