2

我正在尝试从 DLL 中获取类静态数据成员的地址并将其保存在主机代码中。但是,当我退出打开所有(Windows typedef)HINSTANCE的 dll 管理器中的方法时,我丢失了对成员的指针/引用,即使我让它们保持打开状态。

我的设置是:

一个 Qt GUI 应用程序,它包括一个从 dll 加载插件的类。这个 dll-manager 类不使用 Qt 的东西,而是用于 Qdir 和 Qstrings 这里和那里......

dll 管理器应该发出一堆 LoadLibrary() 调用来打开 DLL,并为每个调用调用一个导出函数,该函数返回 DLL 导出的类中的静态“信息”结构的地址。

例如,DLL 类如下所示:

BlackNWhite.h

#ifdef BLACKNWHITE_EXPORTS
#define BLACKNWHITE_API __declspec(dllexport)
#else
#define BLACKNWHITE_API __declspec(dllimport)
#endif

// This class is exported from the BlackNWhite.dll
class BLACKNWHITE_API CBlackNWhite : PCOperatorBase 
{
public:

    CBlackNWhite(void);
    virtual ~CBlackNWhite(void);

    virtual int process(int* inBuffer, int* outBuffer, int bufferSize);
    void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters);

    static const OperatorInfo& info();

protected:

    static OperatorInfo operatorInfo;
};


 extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance();
 extern "C" __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo();

BlackNWhite.cpp

#include "stdafx.h"
#include "BlackNWhite.h"

PCOperatorBase::OperatorInfo CBlackNWhite::operatorInfo = {L"Black N White", L"modifier", L"color"};


const PCOperatorBase::OperatorInfo& CBlackNWhite::info()
{
    return CBlackNWhite::operatorInfo;
}

extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance()
{
    return (PCOperatorBase*)(new CBlackNWhite());
}

extern "C"  __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo()
{
    return CBlackNWhite::info();
}

CBlackNWhite::CBlackNWhite()
    : PCOperatorBase()
{
    ParameterDescriptor newParameter;
    newParameter.label = L"Parameter 1";
    parameters.push_back(newParameter);
}

CBlackNWhite::~CBlackNWhite()
{
}

int CBlackNWhite::process(int* inBuffer, int* outBuffer, int bufferSize)
{
    while(bufferSize--)
        *outBuffer++ = *inBuffer++;

    return 0;
}

void CBlackNWhite::getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters)
{
    outParameters = &parameters;
}

这个类继承自一个基类:

PCOperatorBase.h

#pragma once

#include "PCOperatorParameters.h"
#include <vector>

class PCOperatorBase
{
public:

    typedef struct OperatorInfo
    {
        wchar_t* name;
        wchar_t* type;
        wchar_t* subtype;

    } OperatorInfo;

    PCOperatorBase(void){};
    virtual ~PCOperatorBase(void){};

    virtual void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters) = 0;
    virtual int process(int* inBuffer, int* outBuffer, int bufferSize) = 0;

protected:

    std::vector<ParameterDescriptor>parameters;
};

并且 DLL-manager 有两个相关的方法。一个构建可用插件的列表,另一个只返回插件的字符串名称。

void PCOperatorManager::buildOperatorList(const QString path)
{
    QDir operatorDirectory(QDir::currentPath() + path);

    if(operatorList.size())
        operatorList.clear();

    QStringList operatorNameList = operatorDirectory.entryList(QStringList("*.dll"));

    typedef PCOperatorBase::OperatorInfo*(*PCOClassInfoFunction)();

    for(QStringList::iterator PCOClassName = operatorNameList.begin();
        PCOClassName != operatorNameList.end();
        PCOClassName++)
    {
        HINSTANCE PCOClassHandle;
        if((PCOClassHandle = LoadLibrary((operatorDirectory.absolutePath() + "/"+ *PCOClassName).toStdWString().c_str())))
        {
            OperatorDescriptor newPCOClassDescriptor;
            newPCOClassDescriptor.handle = PCOClassHandle;
            newPCOClassDescriptor.info = (*((PCOClassInfoFunction)GetProcAddress(PCOClassHandle, "getOperatorInfo")))();
            operatorList.push_back(newPCOClassDescriptor);

            printf("\n we have: %ls", operatorList[0].info->name);

        }
    }
}

QStringList PCOperatorManager::getOperatorNameList()
{
    QStringList operatorNameList;

    printf("\n the list length is: %i", operatorList.size());
    for(int i = 0; i < operatorList.size(); i++)
        printf("\n we have again: %ls", operatorList[0].info->name);

//operatorNameList << QString::fromWCharArray((*PCOClass).info.name);


    return operatorNameList;
}

发生的事情是:在 buildOperatorList() 中,我可以访问 DLL 类的静态成员并将其分配给 OperatorDescriptor 结构中的 info 成员。也就是说,读取“我们拥有”的“测试”printf 语句确实打印出该字段的正确值。

但是,在getOperatorNameList()info 成员内部不再有效。

我的思路是,我正在做的是:

  1. 我有一个指向 OperatorInfo 结构的指针,称为 info。
  2. 我得到了 DLL 类中的静态 OperatorInfo 结构的地址,称为 operatorInfo。
  3. 我将类的 operatorInfo 的地址分配给名为 info 的指针。那是info = &CBlackNWhite::operatorInfo;

此时,只要我不在 DLL HINSTANCE上发出 FreeLibrary(),指针就应该保持有效

发生什么了?

4

1 回答 1

0

我看到这里operatorList不是一个成员变量,PCOperatorManager一旦它被添加和构造,就像buildOperatorList我认为你应该访问getOperatorNameList()

于 2012-04-11T05:36:33.370 回答