3

我在 c++ 文件中有此代码,并编译为 dll。

#include "stdafx.h"

#include "WHUU.h"

#include "stdafx.h"

typedef int (__stdcall * Callback)(const int text);

static int x , y= 0;

Callback Handler = 0;

int getX()
{
    return x;
}

void setX(int i)
{
    x = i;
}

void setY(int i)
{
    y = i;
}
int getY()
{
    return y;
}
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
  Handler = handler;
}


extern "C" __declspec(dllexport)
void __stdcall addX(int x) {
    setX(x);
}

extern "C" __declspec(dllexport)
void __stdcall addY(int y) {
    setY(y);


}


extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
    int z = getX() + getY();
  int retval = Handler(z);
}

我的 c# 应用程序现在必须在运行时加载这个 dll。添加到回调并调用函数。我不想使用课程。我可以加载课程并使用

 Type[] types = moduleAssembly.GetTypes();

但这太过分了!c++ 也不受管理。

我的意思是它太小了!(是的,这是一个例子,但“真实”和这个例子一样大)。

我怎么做?

谢谢你的帮助!

添加:

  • 我不喜欢框架(比如 pinvoke / assembly)

  • 函数名称/类型是固定的,永远不会改变(想想 driver.dll 读写)

  • 此 dll 由客户编写,因此应尽可能简单!

4

5 回答 5

1

您也可以通过 p/invoke 执行此操作,例如:

[DllImport("unmanaged.dll", CharSet = CharSet.Ansi)]
private extern static int yourFunction(int var1, int var2);
于 2012-08-09T12:42:20.813 回答
1

我不喜欢框架(比如 pinvoke / assembly)

无论如何,我都会建议 P/Invoke。我认为没有任何合理的选择。也许在托管 C++ 中编写托管包装器,但真的吗?

当您使用 P/Invoke 时,.NET 运行时将动态加载您指定的 DLL(这在您第一次调用该函数时完成)。没有理由先使用 P/Invoke 调用LoadLibrary

于 2012-08-09T12:42:22.900 回答
1

您可以使用 P/Invoke 直接调用 dll,也可以为其创建 C++/CLI 包装器。

以下是使用 P/Invoke 的方法:
将编译后的 dll 添加到 C# 项目中,将其“复制到输出目录”属性设置为“始终复制”。并这样称呼它:

class Program
{
    [DllImport("cppdll.dll")]
    private static extern void addX(int x);

    [DllImport("cppdll.dll")]
    private static extern void addY(int y);

    static void Main(string[] args)
    {
        addX(5);
        addY(7);
    }
}
于 2012-08-09T13:57:30.647 回答
0

一种方法是通过 API。在下面的示例中查找 setX 和 getX 方法的示例。

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
    internal static extern IntPtr LoadLibraryEx(string libraryPath, IntPtr fileHandle, int actionFlag);

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
    internal static extern bool FreeLibrary(IntPtr libraryHandle);

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
    internal static extern IntPtr GetProcAddress(IntPtr dllPointer, string functionName);

    IntPtr ptr = IntPtr.Zero;
    private delegate void setX (int i);
    private delegate int getX();

    private setX setXDel;
    private getX getXDel;

    public Constructor()
    {
        loadLib();
    }

    public void YourMethod()
    {
        setXDel(100);
        int y = getXDel();
        Console.WriteLine(y.ToString());
    }

    private void loadLib()
    {
        string path = "your dll path";
        ptr = LoadLibraryEx(path, IntPtr.Zero, 0);

        if (ptr == IntPtr.Zero)
            throw new Exception("Cannot load dll.");

        IntPtr addressPtr = GetProcAddress(ptr, "setX");
        setXDel = (setX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(setX));

        addressPtr = GetProcAddress(unrarPtr, "getX");
        getXDel = (getX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(getX));

    }

    public void Dispose()
    {
        if (ptr != IntPtr.Zero)
        {
            FreeLibrary(ptr);
        }
    }
于 2012-08-09T12:35:43.817 回答
0

我使用了 P/Invoke,发布了我自己的原因,其他人不包含回调。但他们是很好的答案!C# 应用程序已使用此GUI

应用程序的代码是这样的:(注意它是回答技术问题的原型)

        public partial class Form1 : Form
        {

        private delegate int Callback(int text);
        private Callback mInstance;   // Ensure it doesn't get garbage collected

        [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
        private static extern void SetCallback(Callback fn);
        [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
        private static extern void addX(int x);
        [DllImport(@"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
        private static extern void addY(int y);
        [DllImport(@"C:\\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]

        private static extern void TestCallback(); 

        private int Handler(int text) 
        {
          textBox3.Text = text.ToString();
          return 42;                       
        }


        private void button1_Click(object sender, System.EventArgs e)
        {
          mInstance = new Callback(Handler); // to set the callback in lib 
          SetCallback(mInstance);            // could also be withhin constructor!

          addX(int.Parse(textBox1.Text)); // other people in this thread posted this correct answer
          addY(int.Parse(textBox2.Text));
          TestCallback();
        }

        public Form1()
        {
          InitializeComponent();
        }

因此,如果您想使用带有函数和回调的 c++ 库(如发布的问题中),您可以使用它。

但是如何更改库?

  • lib 的路径是硬编码的(参见 [dllImport ......])。但是你可以在文件系统中交换lib。这可能发生在您构建此应用程序之后。
  • 如果 lib 不在给定路径上,则会引发异常。因此,如果您的程序想要使用此库,请首先检查该库是否存在于文件系统中。(不包括在这个简单的原型中)
  • 因此,要切换功能(swop 驱动程序库等),您将具有相同名称的不同库复制
    到给定路径中。(复制粘贴 - 可能更改名称)

如果您在构建应用程序后从不更改 dll 的接口,则此解决方案的开销最小,而且很好!

于 2012-08-10T07:32:57.293 回答