从 Visual C# 2019 创建的 DLL 可以在 MFC 6.0 中使用吗?

Posted

技术标签:

【中文标题】从 Visual C# 2019 创建的 DLL 可以在 MFC 6.0 中使用吗?【英文标题】:Can a DLL created from Visual C# 2019 be used in MFC 6.0? 【发布时间】:2021-03-16 04:21:37 【问题描述】:

我使用 Visual C# 2019 (.NET Framework) 编写了一个简单的 Web 服务获取函数并将其编译为 DLL。

namespace Transporter

    public class transport
    
        private Int32 returnCode;
        private string responseBody;

        private HttpClient client = new HttpClient();

        public Int32 StartRequest(string baseAddress, string content, string token, string userName, string password)
        
            var t = Task.Run(() => postRequest(baseAddress, content, token, userName, password));
            t.Wait();
            
            responseBody = t.Result;

            return returnCode;
        

        private async Task<string> postRequest(string baseAddress, string content, string token, string userName, string password)
        
            try
            
                using (var client = new HttpClient())
                
                    client.BaseAddress = new Uri(baseAddress);
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                    client.DefaultRequestHeaders.Add("Token", token);
                    client.DefaultRequestHeaders.Add("username", userName);
                    client.DefaultRequestHeaders.Add("password", password);

                    returnCode = 0;
                    responseBody = "";
                    using (HttpResponseMessage response = await client.PostAsJsonAsync(baseAddress, content))
                    
                        response.EnsureSuccessStatusCode();
                        return await response.Content.ReadAsStringAsync();
                    
                
            
            catch (Exception ex)
            
                returnCode = 99;
                return ex.ToString();
            
        
    

我想在使用 MFC 6.0 编写的应用程序中使用 DLL。我尝试了 dllimport 和 loadlibrary,但没有成功。

typedef int32 (CALLBACK* LPSTARTREQUEST)(CString, CString, CString, CString, CString);
HINSTANCE hinstDLL;                 // Handle to DLL
LPSTARTREQUEST lpStartRequest;      // Function pointer
int32 intReturnCode;                // Return code from DLL function
CString cstrBaseAddress, cstrContent, cstrToken, cstrUserName, cstrPassword;
hinstDLL = LoadLibrary("Transporter.dll");
if (hinstDLL != NULL)

    lpStartRequest = (LPSTARTREQUEST)GetProcAddress(hinstDLL, "StartRequest");
    if (!lpStartRequest)
    
        // handle the error
        return "error";
    
    else
    
        // call the function
        intReturnCode = lpStartRequest(cstrBaseAddress, cstrContent, cstrToken, cstrUserName, cstrPassword);
    
    FreeLibrary(hinstDLL);

谁能告诉我这是否真的可行? 谢谢。

【问题讨论】:

“Visual C# 2019”告诉我们的比你想象的要少。 DLL 是 .NET Framework、.NET Standard 还是 .NET Core / .NET 5? MFC 和 VC++ 6 除外,从问题中不清楚如何使用来自 any 非托管的“dllimport and loadlibrary”的 C# 程序集C++ 应用程序,甚至是使用相同的 VS 2019 创建的应用程序。 @Llama 使用 .NET Framework 4.7.2 @Ives 打开developer command prompt 并运行dumpbin /exports Transporter.dll。你看到那里列出了StartRequest 吗?如果没有,那么无论您在哪个版本的 VC++ 中编写非托管代码,都没有可以调用的导出。如果您确实看到它,则显示相关的 C# 代码,因为导出纯.NET 本身不支持 C API。 用 C# 编写的函数完全不可能按值接受 CString 类型的参数。这就是忽略,CString 甚至不是一个类型,而是一个宏。 【参考方案1】:

您不能直接从 MFC 代码调用 C# 类库中的 .NET 函数。您需要使用 COM 而不是 win32 提供的 DLL 管理功能。例如。插入LoadLibrary(),您将使用COM 的IDispatch::QueryInterface(),而不是GetProcAddress(),您将调用IDispatch::GetIDsOfNames() 来检索函数的入口点,然后您将使用IDispatch::Invoke() 调用它。

在这样做之前有一些必要的准备工作:

在您的 .NET 类库中,在项目属性的构建选项卡上打开“注册 COM 互操作性”。 此外,建议在属性中“签署程序集”。如果您想为类库提供未来的更新,这一点很重要。

为了使 COM 工作,您需要提供一个 uuid。例如。在partial class UserControl1之前的文件'UserControl1.Designer.cs'中:

using System.Runtime.InteropServices;
using Microsoft.Win32;
[ProgId("Transporter.UserControl1")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("12fC4E0E-DC1E-A5dc-912B-A631740FG63A")]  // generate your own one!
[ComVisible(true)]

然后将这两个成员添加到您的 UserControl1 类中:

    ///<summary>
    ///Register the class as a control and set its CodeBase entry
    ///</summary>
    ///<param name="key">The registry key of the control</param>
    [ComRegisterFunction()]
    public static void RegisterClass(string key)
    
        // System.Windows.Forms.MessageBox.Show("Registered!");
    

    ///<summary>
    ///Called to unregister the control
    ///</summary>
    ///<param name="key">The registry key</param>
    [ComUnregisterFunction()]
    public static void UnregisterClass(string key)
    
        // System.Windows.Forms.MessageBox.Show("Unregistered!");
    

最后,添加你要调用的函数:

    [ComVisible(true)]
    public int StartRequest(string baseAddress, string content, string token, string userName, string password)
    
        int returnCode = 0;

        // do something here

        return returnCode;
    

请注意,.NET 类库和非托管 C++ COM DLL (.ocx) 之间存在更多差异,因为 win32 和 .NET 是完全不同的生态系统。例如,您可以使用regasm.exe 而不是regsrv32.exe 注册组件。

有关如何以编程方式调用 StartRequest() 的详细示例,请查看此答案的下半部分:https://***.com/a/47050380/1284927(这是 MFC 9.0 代码,但也应适用于 MFC 6.0。)

【讨论】:

谢谢@thomiel,我会试试的。什么情况下需要使用LoadLibrary? @Ives 如果您想从 win32 代码访问 win32 dll,请使用 LoadLibrary()。 (MFC 只是 win32 API 的一个包装器。)

以上是关于从 Visual C# 2019 创建的 DLL 可以在 MFC 6.0 中使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Visual C++ 中使用使用 C# 创建的 dll?

从 Visual Studio 2017 中的现有 VB.NET 项目创建 dll

使用 C++ Dll 的 LNK2019 构造函数/析构函数

如何解决 Visual Studio 2019 中的这个 dll 缺失问题?

Visual Studio 2019 为 .tlog 和 .dll.recipe 文件设置输出目录

无法在 Visual C# 项目中使用我的 .dll