2

クラスの静的データ メンバーのアドレスを DLL から取得し、ホスト コードに保持しようとしています。ただし、すべての (Windows typedef) HINSTANCEを開いたままにしているにもかかわらず、dll-manager でメソッドを終了するとすぐに、メンバーへのポインター/参照が失われます。

私のセットアップは次のとおりです。

dll からプラグインをロードするクラスを含む Qt GUI アプリケーション。この dll-manager クラスは Qt のものを使用しませんが、あちこちで Qdir と Qstrings を使用します...

dll-manager は、一連の LoadLibrary() 呼び出しを発行して DLL を開き、それぞれに対して、DLL がエクスポートするクラス内の静的な "info" 構造体のアドレスを返すエクスポートされた関数を呼び出す必要があります。

たとえば、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 マネージャーには 2 つの関連するメソッドがあります。1 つは利用可能なプラグインのリストを作成し、もう 1 つはプラグインの文字列名を返すだけです。

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 メンバーに割り当てることができます。つまり、"we have" を読み取る "test" printf ステートメントは、そのフィールドの正しい値を出力します。

ただし、getOperatorNameList()info メンバー内は無効になりました。

私の考えでは、私がやっていることは次のとおりです。

  1. info と呼ばれる OperatorInfo 構造体へのポインターがあります。
  2. operatorInfo という DLL クラスの静的な OperatorInfo 構造体のアドレスを取得します。
  3. クラスの operatorInfo のアドレスを info というポインターに割り当てます。あれはinfo = &CBlackNWhite::operatorInfo;

この時点で、DLL HINSTANCEで FreeLibrary() を発行しない限り、ポインターは有効なままになります。

どうしたの?

4

1 に答える 1

0

私はあなたがアクセスする必要があると思うように、これが追加されて構築された後operatorListのメンバー変数ではないことがわかりますPCOperatorManagerbuildOperatorListgetOperatorNameList()

于 2012-04-11T05:36:33.370 に答える