【问题标题】:C++/CLI DLL linker issueC++/CLI DLL 链接器问题
【发布时间】:2013-10-10 23:35:41
【问题描述】:

好的,所以我正在尝试为另一个可以使用GetProcAddress 调用的应用程序创建运行时 DLL。

所以我在 VS2012 C++ Express(下面的头文件和源代码)中构建了 DLL,即使 dll 与 exe 位于同一文件夹中,它也会返回 NULL。所以这让我相信dllmain 函数存在问题。于是我开始翻阅MSDN,发现如下链接

http://msdn.microsoft.com/en-us/library/vstudio/988ye33t.aspx

它指出,当我创建 dll 模板时,它已经照顾好我,我按照这个 MSDN 链接做了。

http://msdn.microsoft.com/en-us/library/ms235636%28v=vs.80%29.aspx

所以我决定尝试在发布模式下构建 DLL(考虑一下这可能是问题所在),但我收到一个链接器错误,提示必须定义入口点。它在调试模式下构建良好,但在发布模式下却不行。我想我在这里遗漏了一些简单的东西。

Error   1   error LNK1561: entry point must be defined  C:\Users\ProRip\Documents\Visual Studio 2012\Projects\PhantomAdapter\AdapterDLL\LINK    AdapterDLL

标题

#ifdef PHANTOMADAPTER_EXPORTS
#define PHANTOMADAPTER_API __declspec(dllexport)
#else
#define PHANTOMADAPTER_API __declspec(dllexport)
#endif
#using <mscorlib.dll>
#using <system.dll>
using namespace System; 
using namespace System::IO::Ports;
using namespace System::Threading;
namespace PhantomAdapter
{


class PhantomAdapter
{
public:
    static PHANTOMADAPTER_API int open();
    static PHANTOMADAPTER_API int close();
    //static PHANTOMADAPTER_API double init(bool );
    //static PHANTOMADAPTER_API int noDevices();
    static PHANTOMADAPTER_API int angle(double& angle);
    static PHANTOMADAPTER_API int torque(double torque);
    static PHANTOMADAPTER_API int ready();
};
public ref class SerialPort
{
private:
    static System::IO::Ports::SerialPort^ p1;
public:
    static int openPort();
    static void closePort();
    static int read();
    static void send(Byte data);
    static int check();
};

}

来源

#include "stdafx.h"


#include "stdafx.h"
#include "PhantomAdapter.h"
#include <stdexcept>

using namespace std;



namespace PhantomAdapter
{

    int PhantomAdapter::open()
    {
        int flag=0;

        flag=SerialPort::openPort();
        return flag;

    }

    int PhantomAdapter::close()
    {
        SerialPort::closePort();

        return 1;
    }

    int PhantomAdapter::angle(double& angle)
    {
        SerialPort::send(0x82);
        angle = (SerialPort::read() * 255) + (SerialPort::read());
        angle = angle*(6.2832/512);

        return 1;
    }

    int PhantomAdapter::torque(double torque)
    {
        return 1;
    }

    int PhantomAdapter::ready()
    {
        return SerialPort::check();
    }

    int SerialPort::openPort()
    {       
        bool check=0;
        p1 = gcnew System::IO::Ports::SerialPort();

        p1->BaudRate = 57600;
        p1->PortName = "COM3";
        if(p1->IsOpen)
          return 0;
        else {
            p1->Open();
            return 1;
        }

    }

    int SerialPort::check()
    {
        array<String^>^ serialPorts = nullptr;
        int flag=0;
        serialPorts = p1->GetPortNames();

        for each(String^ port in serialPorts)
        {
            if(port=="COM3")
                flag=1;             
        }

        return flag;
    }

    void SerialPort::closePort()
    {
        p1->Close();
    }

    void SerialPort::send(Byte data)
    {
         array<unsigned char>^ buffer = gcnew array<Byte>(1);

        buffer[0] = (char)data;
        p1->Write(buffer,0,1);  
    }

    int SerialPort::read()
    {
        return p1->ReadByte();
    }
}

【问题讨论】:

  • 那不是 C++,那是一种叫做 C++/CLI 的 CLR 语言。

标签: c++ visual-studio-2012 dll c++-cli


【解决方案1】:

在你的VS项目中,你能检查一下设置吗:
1.Configuration Properties &gt; General &gt; Configuration Type?在发布模式的情况下是否设置为.dll?
2.Configuration Properties &gt; Linker &gt; System &gt; SubSystem?这两种模式是一样的吗?

【讨论】:

  • 谢谢我刚刚意识到它在发布模式下设置为.exe,仍然无法解释为什么我无法使用loadlibrary 成功调用它。您有什么想法吗,尝试了 regsrv32,它说它已加载但未找到 DllRegisterServer。我知道如果它在同一个目录中我不需要 regsvr32 它但想看看它是否成功加载。
  • 您在调试模式下是否也面临同样的问题(不成功loadlibrary)?还是仅在发布模式下?
  • 我都尝试了发布模式,看看是否有影响,但没有
  • ok,接下来就是检查外部依赖了。 loadlibrary 失败是一些依赖没有解决。 Walker dependency 之类的工具将为您提供帮助。
  • 好的,所以 Dependency Walker 将 GPSVC.DLL 和 IESHIMS.DLL 延迟加载依赖模型显示为“系统找不到指定的文件”但它们位于 windows 目录中”GetLastError() 也给出了错误代码 0x0000001c我仍在尝试找出它的含义。如果可以找到 dll,为什么依赖 walker 会显示这些错误。
【解决方案2】:

您不能通过 LoadLibrary/GetProcAddress 从本机代码调用 .NET 方法(C++/CLI 方法是 .NET 方法)。 .NET 方法和类不会以这种方式导出。你总会得到一个 NULL 指针。

你可以做什么:

  • 在 .NET 中编写一个 COM 组件以在普通 C++ 中引用

  • 导出仅在内部调用 .NET 代码的普通、纯 C++ 方法

  • 使用 Assembly 类及其方法将托管 dll 导入托管(相同的 C++/CLI 或 C# 或任何其他 .NET 语言)可执行文件。

【讨论】:

  • “普通 C++ 方法”根本不是方法,它们是 函数。 C++ 没有方法,只有“虚拟非静态成员函数”可以合理地称为“方法”。
  • @BenVoigt 这些将无法导出,因为...?
  • 因为导出除了全局函数之外的任何东西都是一场灾难。非静态成员函数需要一个目标对象,它只能由对象创建表达式创建,该表达式涉及构造函数调用等——构造​​函数从来不打算被独立调用,而其他东西没有可移植的方式来重现.然后你有名字修饰问题。只是不要尝试导出成员函数。从 C++ 外部调用虚成员函数的方法是使用 vtable(在您的 COM 组件项目符号中介绍)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多