与 C# 控制台应用程序互操作 C++ (DLL) 的问题

Posted

技术标签:

【中文标题】与 C# 控制台应用程序互操作 C++ (DLL) 的问题【英文标题】:Problems Interoping C++ (DLL) with C# console app 【发布时间】:2013-12-07 19:39:22 【问题描述】:

我正在尝试将 C++ DLL(反汇编优势)与 C# 应用程序互操作,因此我创建了一个带有如下导出符号的 C++ Win32 项目 (DLL):

LicensePolicy32.h:

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the LICENSEPOLICY32_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// LICENSEPOLICY32_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef LICENSEPOLICY32_EXPORTS
#define LICENSEPOLICY32_API __declspec(dllexport)
#else
#define LICENSEPOLICY32_API __declspec(dllimport)
#endif

LICENSEPOLICY32_API char* GetXmlTokenNode(void);

LicensePolicy32.cpp:

#include "stdafx.h"
#include "LicensePolicy32.h"

bool GetLicense()

    DWORD dwType = REG_SZ;
    HKEY hKey = 0;
    char value[1024];
    DWORD value_length = 1024;
    LPCWSTR subkey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WSESecurityPolicy";
    LONG openReg = RegOpenKeyEx(HKEY_LOCAL_MACHINE,subkey,0, KEY_WOW64_64KEY | KEY_QUERY_VALUE, &hKey);
    if (openReg==ERROR_SUCCESS)
    
        return true;
    
    else
    
        return false;
    

    LONG getReg = RegQueryValueEx(hKey, L"WSEHostProcessID", NULL, &dwType, (LPBYTE)&value, &value_length);
    if (getReg==ERROR_SUCCESS)
    
        return true;
    
    else
    
        return false;
    


LICENSEPOLICY32_API char* GetXmlTokenNode()

    char *orig;
    bool resultLicense = GetLicense();
    if (!resultLicense)
    
        return "";
    
    else
    
        return "/0:Envelope/0:Header";
    

我的C#测试代码如下:

using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace TestDllConsoleApplication

    class Program
    
        [STAThread]
        static void Main(string[] args)
        
            Test testObj = new Test();
        
    

    public class Test
    
        [MarshalAs(UnmanagedType.LPStr)]
        public string result;

        [DllImport(@"D:\Proyectos\NET\Dll\LicensePolicy32\Release\LicensePolicy32.dll", CharSet=CharSet.Ansi, EntryPoint = "GetXmlTokenNode")]
        public static extern string GetXmlTokenNode();

        public Test()
        
            try
            
                result = GetXmlTokenNode();
                result += " result";
            
            catch (DllNotFoundException exDll)
            
                string error = "Dll no encontrado";
            
            catch (BadImageFormatException exBad)
            
                string error = "Plataforma Ensamblado incompatible";
            
            catch (Win32Exception exWin32)
            
                string error = "Error general de Win32";
            
            catch (EntryPointNotFoundException exPoint)
            
                string error = "No encontró punto de entrada al método";
            
            catch (Exception ex)
            
                string error = "Error otros";
            
        
    

DLL 的路径很好,但是当我运行 C# 测试项目时会抛出 EntryPointNotFoundException。

感谢您的帮助,谢谢

【问题讨论】:

您没有猜对 EntryPoint = "GetXmlTokenNode"。让链接器创建一个 .map 文件。或者在您的 DLL 上运行 Dumpbin.exe /exports。无论哪种方式,您都会看到修饰的名称。您也不能像那样返回 C 字符串,pinvoke 编组器将尝试释放该字符串,就像它应该的那样。那会炸弹。将其声明为 IntPtr 并使用 Marshal.PtrToStringAnsi()。 【参考方案1】:

这些不是您要寻找的机器人。您的 c++ 名称将被修饰,实际名称不会是 GetXmlTokenNode。为避免这种情况,请使用 extern "C" 作为您要导出的方法的签名的一部分。这将避免名称修饰。

您可能会发现this whitepaper 很有用。

【讨论】:

【参考方案2】:

C++ 编译器为任何函数名添加后缀。后缀定义了参数类型和顺序——这样编译器就可以处理重载。

为避免这种情况,您可以使用 C 进行编译(将 cpp 后缀更改为 C,如果您在代码中没有特殊的 C++ 功能,VS 会理解您想要做什么)。

或者找到原生DLL函数的真实名称,并将其作为入口点。

【讨论】:

其实 Aaron 建议添加 'extern C' 更好。对于重载的解释,我留下我的答案。

以上是关于与 C# 控制台应用程序互操作 C++ (DLL) 的问题的主要内容,如果未能解决你的问题,请参考以下文章

本机 C++ 程序在使用 C++/CLI 和 C# 互操作 DLL 启动时崩溃

C# 和 C++ 互操作

与 php 和 java 互操作的 C# dll

如何读取 C++ SAFEARRAY**,它是 C# 返回值为 byte[] 的 COM 互操作的结果?

无法在 Vista x64 的 C# 应用程序中加载 C++ DLL

将 C# 函数指针传递到 C++/CLI 互操作 dll