クラスの静的データ メンバーのアドレスを 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 = ¶meters;
}
そして、このクラスは基本クラスから継承します:
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 メンバー内は無効になりました。
私の考えでは、私がやっていることは次のとおりです。
- info と呼ばれる OperatorInfo 構造体へのポインターがあります。
- operatorInfo という DLL クラスの静的な OperatorInfo 構造体のアドレスを取得します。
- クラスの operatorInfo のアドレスを info というポインターに割り当てます。あれは
info = &CBlackNWhite::operatorInfo;
この時点で、DLL HINSTANCEで FreeLibrary() を発行しない限り、ポインターは有効なままになります。
どうしたの?