2010-01-30 29 views
18

trong dự án tiếp theo của tôi, tôi muốn triển khai GUI cho mã đã tồn tại trong C++. Kế hoạch của tôi là bọc phần C++ trong một tệp DLL và triển khai GUI trong C#. Vấn đề của tôi là tôi không biết làm thế nào để thực hiện một cuộc gọi lại từ DLL không được quản lý vào mã C#. Tôi đã thực hiện một số phát triển trong C# nhưng giao tiếp giữa mã được quản lý và không được quản lý là mới đối với tôi. Ai có thể cho tôi một số gợi ý hoặc lời khuyên đọc hoặc một ví dụ đơn giản để bắt đầu từ đâu? Thật không may tôi không thể tìm thấy bất cứ điều gì hữu ích.Làm cách nào để triển khai giao diện gọi lại từ DLL không được quản lý đến ứng dụng .net?

Trả lời

42

Bạn không cần sử dụng Marshal.GetFunctionPointerForDelegate(), P/Invoke marshaller thực hiện tự động. Bạn sẽ cần phải khai báo một đại biểu ở phía C# có chữ ký tương thích với khai báo con trỏ hàm trên phía C++. Ví dụ:

using System; 
using System.Runtime.CompilerServices; 
using System.Runtime.InteropServices; 

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

    public UnManagedInterop() { 
    mInstance = new Callback(Handler); 
    SetCallback(mInstance); 
    } 
    public void Test() { 
    TestCallback(); 
    } 

    private int Handler(string text) { 
    // Do something... 
    Console.WriteLine(text); 
    return 42; 
    } 
    [DllImport("cpptemp1.dll")] 
    private static extern void SetCallback(Callback fn); 
    [DllImport("cpptemp1.dll")] 
    private static extern void TestCallback(); 
} 

Và C++ mã tương ứng sử dụng để tạo ra các DLL không được quản lý:

#include "stdafx.h" 

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

Callback Handler = 0; 

extern "C" __declspec(dllexport) 
void __stdcall SetCallback(Callback handler) { 
    Handler = handler; 
} 

extern "C" __declspec(dllexport) 
void __stdcall TestCallback() { 
    int retval = Handler("hello world"); 
} 

Đó là đủ để giúp bạn bắt đầu với nó. Có hàng triệu chi tiết có thể khiến bạn gặp rắc rối, bạn nhất định sẽ gặp phải một số vấn đề. Cách hiệu quả hơn nhiều để có được loại mã này là viết một trình bao bọc trong ngôn ngữ C++/CLI. Điều đó cũng cho phép bạn bọc một lớp C++, một cái gì đó bạn không thể làm với P/Invoke. Một hướng dẫn khá là available here.

+0

Cảm ơn nobugz, tôi sẽ cố gắng sớm thôi. Và tôi hy vọng tôi sẽ không nhận được vào quá nhiều rắc rối ;-) – chrmue

+0

hoạt động hoàn hảo cho tôi, cảm ơn một lần nữa! – chrmue

5

P/Invoke có thể xử lý marshaling một đại biểu được quản lý với một con trỏ hàm. Vì vậy, nếu bạn tiếp xúc với API của đăng ký một cuộc gọi trở lại chức năng từ DLL của bạn và trong C# vượt qua một đại biểu cho chức năng đó.

Có ví dụ về MSDN khi thực hiện việc này với chức năng EnumWindows. Trong bài viết này phải cẩn thận chú ý đến dòng tại điểm 4 cho biết: Thao

Tuy nhiên, nếu chức năng gọi lại có thể được gọi sau khi trở về cuộc gọi, gọi quản lý phải thực hiện các bước để đảm bảo rằng đại biểu vẫn còn không được thu thập cho đến khi hàm gọi lại kết thúc. Để biết chi tiết thông tin về ngăn ngừa rác thải bộ sưu tập, hãy xem Interop Marshaling với Platform Invoke.

Điều gì đang nói là bạn cần đảm bảo rằng đại biểu của bạn không được thu thập rác cho đến sau khi mã được quản lý được gọi bằng cách giữ tham chiếu đến mã đó trong mã của bạn hoặc ghim nó.

+0

+1 cho P/Invoke quan trọng - chỉ đảm bảo tính hợp lệ của con trỏ trong khi gọi - nếu bạn đang lưu vào bộ nhớ, bạn cần ghim nó (không thể nói để stashing tham chiếu , đáng ngờ, nhưng điều đó không có nghĩa là :-) –

Các vấn đề liên quan