2012-08-09 43 views
3

我在C++文件中编译了该代码,并将其编译为dll。如何在运行时在C#应用程序中加载Dll(C++)

#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的/组装)

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

  • 这个DLL是由客户编写的,所以它应该尽可能的简单!

+0

http://www.pinvoke.net/ – deltree 2012-08-09 12:18:18

+0

要求是相当荒谬的。没有人要求最艰难的方式来做到这一点。你真的*想要利用pinvoke。要求客户编写这段代码的COM版本,这样你就不必再努力工作了,可能会变得很糟糕。 – 2012-08-09 12:43:24

回答

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与功能和回调(如你问题发布)你可以使用这个。

但如何更改lib?

  • lib的路径是硬编码的(参见[dllImport ......])。但你 可以swop文件系统中的库。这可能会发生后,你建立这个 应用程序。
  • 如果lib不在给定路径上,则抛出异常。因此,如果你的程序想要使用这个库,首先检查该文件系统是否存在lib。因此,要切换功能(swop驱动程序库),请将不同的库与
    同名复制到给定路径中。 (复制粘贴 - 也许更改名称)

此解决方案的开销最小,并且如果在应用程序构建后永远不会更改dll的界面,那么这个解决方案很好!

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); 
     } 
    } 
+2

您正在使用P/Invoke来提供您自己的与P/Invoke类似的实现。只需使用P/Invoke即可。 – 2012-08-09 12:44:42

1

你也可以做过来的P/Invoke,作为例子:

[DllImport("unmanaged.dll", CharSet = CharSet.Ansi)] 
private extern static int yourFunction(int var1, int var2); 
1

我不喜欢的框架(如PInvoke的/组装)

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

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

+0

这个问题是因为一个激烈的讨论,你可以调用没有任何框架的.net lib函数发布。 – Thomas 2012-08-10 07:38:16

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); 
    } 
} 
相关问题