Export templated buffer class in a DLL

Started by
7 comments, last by Sepiantum 12 years, 2 months ago
I was just wondering if there would be a way to export a templated class into a DLL. Mainly because I want to wrap ID3D11Buffer. The other way would be to store things to be copied to the buffer in a std::vector<void*> and do some smart copying when you call Map(). If it were possible to export a templated class that would allow me to keep my vertex/index data inside std::vector<T> and just do a single memcpy, let me know.

Thanks in advance,
Sepiantum.
Follow and support my game engine (still in very basic development)? Link
Advertisement
Export to whom? Under what restrictions?

If you're willing to include the template header in the DLL client code, and willing to use explicit instantiation, then yes, it can be done - provided you ensure that you use the same compiler (down to the version/service pack number) for both the DLL and the client code. Outside of that, it's really not practical.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Actually, it's worse than that. You also need to make sure both client and DLL use the same compiler settings. In particular standard library containers can look significantly different between debug and release.
So my best bet would be to use a vector of void* pointers to hold data of any sort instead of a type-specific buffer class.
Follow and support my game engine (still in very basic development)? Link
You've provided insufficient information to say what your best bet would be. In addition to what ApochPiQ has already ask you might want to show exactly how you intend to use your vector.
Here is my buffer class code.

#include "CBuffer11.h"
#include <iterator>
//Constructor - sets stuff to null
QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::CBuffer(QuantumGameEngine::QuantumGraphics::CGraphicsController* pController)
: ExtendedWindowsAPI::CDebugLogger("CBuffer"), ExtendedWindowsAPI::IInitializable(), pGC(pController), stride(0), pBuffer(nullptr){
this->data.clear(); //Clear the data buffer
ZeroMemory(&this->BufferDesc, sizeof(this->BufferDesc)); //Clear the buffer description
}
//Destructor - checks for non nulled pointers
QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::~CBuffer(){
//pBuffer
if(this->pBuffer){
this->log(LEVEL_WARNING, "pBuffer = %p", this->pBuffer);
this->pBuffer = nullptr;
}
//pGC
if(this->pGC){
this->log(LEVEL_WARNING, "pGC = %p" , this->pGC);
this->pGC = nullptr;
}
}
//initialization code - creates the buffer of specified type
bool QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::initialize(){
//HRESULT to store return codes
HRESULT hr;
//Calculate the total size of the buffer
this->BufferDesc.ByteWidth = this->data.size() * stride;
//Create the buffer
if(FAILED(hr = this->pGC->pDevice->CreateBuffer(&this->BufferDesc, nullptr, &this->pBuffer))){
this->log(LEVEL_ERROR, "Failed to create the vertex buffer - %ld", hr);
return false;
}
//Map the region
D3D11_MAPPED_SUBRESOURCE ms;
if(FAILED(hr = this->pGC->pDeviceContext->Map(this->pBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms))){
this->log(LEVEL_ERROR, "Failed to map the vertex buffer data region - %ld", hr);
return false;
}
//Copy to the mapped region - does this even work...
for(UINT i = 0; i < this->data.size(); i++){
memcpy((LPVOID)((UINT)ms.pData + this->stride * i), this->data, stride);
}
//Unmap the region
this->pGC->pDeviceContext->Unmap(this->pBuffer, NULL);
return true;
}
//cleanup code - nothing yet
bool QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::cleanup(){
//pBuffer
if(this->pBuffer){
this->pBuffer->Release();
this->pBuffer = nullptr;
}
//Cleanup buffer data
for(UINT i = 0; i < this->data.size(); i++){
delete reinterpret_cast<BYTE*>(this->data);
}
//Null the graphics controller reference
this->pGC = nullptr;
return true;
}
//Sets stride - that is all
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::SetStride(size_t size_of_data){
this->stride = size_of_data;
}
//Appends a data pointer to the end of the vector
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::AddData(void* pData){
this->data.push_back(pData);
}
//Sets buffer usage
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::SetUsage(D3D11_USAGE Usage){
this->BufferDesc.Usage = Usage;
}
//Sets CPU access flags
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::SetCPUFlags(UINT Flags){
this->BufferDesc.CPUAccessFlags = Flags;
}
//Sets misc flags
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::SetMiscFlags(UINT Flags){
this->BufferDesc.MiscFlags = Flags;
}
//Sets structure byte stride. no idea what this is... LOL
void QuantumGameEngine::QuantumGraphics::Quantum3D::CBuffer::SetStructureByteStride(UINT SBS){
this->BufferDesc.StructureByteStride = SBS;
}
Follow and support my game engine (still in very basic development)? Link

I was just wondering if there would be a way to export a templated class into a DLL.


Can't be done, although you can export template class specialisations. i.e.


template< typename T>
class DLL_EXPORT Foo
{
};
template DLL_EXPORT class Foo<float>;


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

Actually, it's worse than that. You also need to make sure both client and DLL use the same compiler settings. In particular standard library containers can look significantly different between debug and release.

[/font][/quote]

This isn't anything template specific. Basically you must never do:


class Foo
{
public:

#ifdef _DEBUG
int m_someDebuggingData;
#endif
float m_foo;
};


The change in class size is the important factor, and not specifically templates (It just so happens that STL containers/iterators contain additional data in debug, which isn't present in release). This can and does cause problems when mixing debug/release DLLs, but only occurs when you are doing that. If you only ever run a full debug build, or a full release build, you can safely ignore this problem (on VC++ it generates warning C4251). For what the OP wants, unless he intends to ship the DLL as part of some API or modding toolkit, he can probably just get away with ignoring the problems (it's perfectly safe to do so in this case).

To be perfectly honest though, if your DLL interface depends on some code not shipped with your DLL (std::vector / boost headers etc), then you're doing it wrong anyway. It's just too much of a nightmare dealing with numerous people wanting to use their own preferred STL implementation, or a specific boost version, etc. It's just better to not allow that to happen by writing DLL interfaces that DONT depend on 3rd Party code.

If it's your own template, and it's size is the same in Debug & Release, then there are no problems exporting specialisations from your DLL.
If the class changes size between debug and release, then you will never be able to safely mix debug/release DLLs.
If the template is mainly small inline funcs, then you'd be better off not exporting it at all.

If it's your own template, and it's size is the same in Debug & Release, then there are no problems exporting specialisations from your DLL.

You're still making assumptions about answers to questions that the OP hasn't bothered to give. For example, the whole whether or not the compiler for the client of the DLL is going to be the same as the compiler for the DLL. If he wants to use MSVC 2010 for one and BCB 3 for the other then there are going to be issues. And settings with impact on the size of classes in Release vs. Debug aren't the only relevant compiler settings. For example, good luck getting a 64-bit DLL to work with a 32-bit compiler. If you don't bother to specify the calling conventions on your functions, a DLL and a client that uses different default calling convention flags is going to give a lot of fun runtime errors. And so on.

[quote name='RobTheBloke' timestamp='1328532231' post='4910120']If it's your own template, and it's size is the same in Debug & Release, then there are no problems exporting specialisations from your DLL.

You're still making assumptions about answers to questions that the OP hasn't bothered to give. For example, the whole whether or not the compiler for the client of the DLL is going to be the same as the compiler for the DLL. If he wants to use MSVC 2010 for one and BCB 3 for the other then there are going to be issues. And settings with impact on the size of classes in Release vs. Debug aren't the only relevant compiler settings. For example, good luck getting a 64-bit DLL to work with a 32-bit compiler. If you don't bother to specify the calling conventions on your functions, a DLL and a client that uses different default calling convention flags is going to give a lot of fun runtime errors. And so on.
[/quote]

I'm pretty much assuming that people are going to use the latest version of MSVC. I normally don't add debug only data and haven't done that yet, so that won't be a problem. And finally, it's not that hard to build 32-bit or 64-bit versions of the same dll, as I don't use 32-bit or 64-bit only functions.
Follow and support my game engine (still in very basic development)? Link

This topic is closed to new replies.

Advertisement