Błąd linkowania - unresolved externals

0

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.

1

Dobra sprawa wyjaśniona. Szablon robi tu problemy. Wyjaśnienie tutaj:
http://stackoverflow.com/questions/456713/why-do-i-get-unresolved-external-symbol-errors-when-using-templates

Templated classes and functions are not instantiated until they are used, typically in a separate .cpp file (e.g. the program source). When the template is used, the compiler needs the full code for that function to be able to build the correct function with the appropriate type. However, in this case the code for that function is detailed in the template's source file and hence unavailable.

As a result of all this the compiler just assumes that it's defined elsewhere and only inserts the call to the templated function. When it comes to compile the template's source file, the specific template type that is being used in the program source isn't used there so it still won't generate the code required for the function. This results in the unresolved external symbol.

Zrobiłem implementacje inline w .h i jak ręką odjął :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1