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 を使用して 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 に答える
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 / アセンブリなど)

とにかく P/Invoke をお勧めします。合理的な代替手段はないと思います。マネージ C++ でマネージ ラッパーを作成することもあるかもしれませんが、それは本当でしょうか?

P/Invoke を使用すると、.NET ランタイムは指定した DLL を動的にロードします (これは関数を最初に呼び出したときに行われます)。P/Invoke を使用して最初に呼び出す理由はありませんLoadLibrary

于 2012-08-09T12:42:22.900 に答える
0

これを行う1つの方法は、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++ ライブラリを使用する場合は、これを使用できます。

しかし、どのようにライブラリを変更するのですか?

  • ライブラリへのパスはハードコードされています ( [dllImport ......] を参照)。ただし、ファイルシステムで lib をスワップできます。これは、このアプリケーションをビルドした後に発生する可能性があります。
  • ライブラリが指定されたパスにない場合、例外がスローされます。したがって、プログラムでこの lib を使用する場合は、最初に lib がファイルシステムに存在することを確認してください。(この単純なプロトタイプには含まれていません)
  • したがって、機能を切り替える (ドライバ ライブラリを入れ替える) には、
    同じ名前の別のライブラリを指定されたパスにコピーします。(コピーペースト - 名前を変更する可能性があります)

このソリューションはオーバーヘッドが最小であり、アプリケーションのビルド後に dll のインターフェイスをまったく変更しない場合に適しています。

于 2012-08-10T07:32:57.293 に答える