Na wstępie muszę wyjaśnić, że piszę projekt w C++/CLI, ale jestem przekonany, że problem dotyczy samego C++, dlatego wybrałem ten dział. Jeżeli coś jest niejasne to doprecyzuję.
Oto co próbuję osiągnąć. Piszę wrapper na bibliotekę C++. Żeby obsłużyć zdarzenie, muszę podać klasę implementującą interfejs ICallbackEx, ale nie mogę podać klasy zarządzanej, bo ta nie może dziedziczyć z klasy niezarządzanej. Stworzyłem więc klasę szablonową niezarządzaną, która otrzymuje obiekt zarządzany (gcroot<T>
) i na nim wywołuję pewną metodę.
Z tego co czytałem w necie to dość powszechny problem. Jednak ja chyba jestem ślepy, bo nie widzę gdzie robię błąd. Poniżej szczegóły:
Error LNK1120 2 unresolved externals
Error LNK2019 unresolved external symbol "public: __thiscall ClrWrapper::CallbackEx<class ClrWrapper::CmsVideoChannel ^>::CallbackEx<class ClrWrapper::CmsVideoChannel ^>(struct gcroot<class ClrWrapper::CmsVideoChannel ^>)" (??0?$CallbackEx@P$AAVCmsVideoChannel@ClrWrapper@@@ClrWrapper@@$$FQAE@U?$gcroot@P$AAVCmsVideoChannel@ClrWrapper@@@@@Z) referenced in function "public: __clrcall ClrWrapper::CmsVideoChannel::CmsVideoChannel(class ICmsVideoChannel *)" (??0CmsVideoChannel@ClrWrapper@@$$FQ$AAM@PAVICmsVideoChannel@@@Z)
Error LNK2028 unresolved token (0A00001D) "public: __thiscall ClrWrapper::CallbackEx<class ClrWrapper::CmsVideoChannel ^>::CallbackEx<class ClrWrapper::CmsVideoChannel ^>(struct gcroot<class ClrWrapper::CmsVideoChannel ^>)" (??0?$CallbackEx@P$AAVCmsVideoChannel@ClrWrapper@@@ClrWrapper@@$$FQAE@U?$gcroot@P$AAVCmsVideoChannel@ClrWrapper@@@@@Z) referenced in function "public: __clrcall ClrWrapper::CmsVideoChannel::CmsVideoChannel(class ICmsVideoChannel *)" (??0CmsVideoChannel@ClrWrapper@@$$FQ$AAM@PAVICmsVideoChannel@@@Z)
Kod klasy której linkowanie się nie powiodło:
CallbackEx.h
#pragma once
#include "SDKHeaders\ICallbackEx.h"
#include <vcclr.h>
namespace ClrWrapper
{
template <typename T>
class CallbackEx : public ICallbackEx
{
private:
gcroot<T> stateChangedHandler;
public:
CallbackEx(gcroot<T> videoChannel);
void OnCallbackEx(
IUnknown *pData, __int64 llData,
IUnknown *pParam,
__int64 llParam1,
__int64 llParam2);
// Inherited via ICallbackEx
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
virtual ULONG STDMETHODCALLTYPE Release(void) override;
};
}
CallbackEx.cpp
#include "stdafx.h"
#include "CallbackEx.h"
namespace ClrWrapper
{
template<typename T>
CallbackEx<T>::CallbackEx(gcroot<T> videoChannel)
{
stateChangedHandler = videoChannel;
}
template <typename T>
void CallbackEx<T>::OnCallbackEx(
IUnknown *pData, __int64 llData,
IUnknown *pParam,
__int64 llParam1,
__int64 llParam2)
{
stateChangedHandler->OnStateChanged();
}
template <typename T>
HRESULT CallbackEx<T>::QueryInterface(REFIID riid, void ** ppvObject)
{
return E_NOTIMPL;
}
template <typename T>
ULONG CallbackEx<T>::AddRef(void)
{
return 0;
}
template <typename T>
ULONG CallbackEx<T>::Release(void)
{
return 0;
}
}
Kod klasy która to wywołuje:
CmsVideoChannel.h
#pragma once
#include "CallbackEx.h"
namespace ClrWrapper
{
public ref class CmsVideoChannel
{
private:
CallbackEx<CmsVideoChannel^> * callbackEx;
internal:
CmsVideoChannel(ICmsVideoChannel * videoChannel);
//reszta nieistotna
}
}
CmsVideoChannel.cpp
namespace AlnetSDKClrWrapper
{
CmsVideoChannel::CmsVideoChannel(ICmsVideoChannel * nativeChannel)
{
videoChannel = nativeChannel;
INotifyCallbackEx * notifyCallback = videoChannel->nState();
callbackEx = new CallbackEx<CmsVideoChannel^>(this);
notifyCallback->Register(callbackEx, NULL, 0);
}
}
Wszystkie pliki są w projekcie. Log z budowania wrzuciłem tutaj: https://4programmers.net/Pastebin/6314
Wszelkie sugestie mile widziane.