0

I'm testing some code examples for a CLR project. What would be this code equivalent without using smart pointers?

Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
...
m_d3dDevice.As(&dxgiDevice);

I tried something like this, but I'm not sure if it's ok.

ID3D11Device1* m_d3dDevice;
IDXGIDevice1* dxgiDevice;
...
dxgiDevice = reinterpret_cast<IDXGIDevice1*>(m_d3dDevice);
Milos
  • 1,353
  • 2
  • 18
  • 37
  • Are these std smart pointers? If yes, take a look here: https://en.cppreference.com/w/cpp/memory/unique_ptr – rbf Nov 20 '20 at 09:39
  • 2
    You should probably give some kind of context to what the code is or what your are using. Are we talking `std::shared_ptr`s or what... ? [mcve] is always a good idea. – super Nov 20 '20 at 09:40
  • 1
    I'm pretty sure `ComPtr::As` uses QueryInterface to get a proper interface. – Botje Nov 20 '20 at 09:40
  • I suspect you need `dynamic_cast` if there is an inheritance relationship. Is there a special reason you want to avoid smart pointers? – Galik Nov 20 '20 at 09:41
  • 1
    @Galik - these are COM objects. You don't do a cast between interfaces. – selbie Nov 20 '20 at 09:56
  • 1
    I read this question as: "I want to break my code make it fragile, how to do it?". – Marek R Nov 20 '20 at 09:57

1 Answers1

2

These are COM object pointers.

I am not sure why you would not want to use a COM smart pointer template class. They eliminate most reference counting issues that can drive you crazy. And they have almost zero overhead.

As such, you can use the ComPtr class or the legacy CComPtr from ATL as your smart ptr template type to automatically handle Addref, Release, and QueryInterface calls for yourself. You can also roll your own smart pointer classes, but ComPtr/CComPtr are very efficiently written.

The rules of COM basically often break when you try to cast between interfaces without using QueryInterface. The actual concrete implementation is probably a C++ class with multiple inheritance from many interfaces. As such, casting between interfaces is probably a shift in the pointer value. But the compiler can't infer that from base class interfaces only. Also, many COM classes cheat this by having QueryInterface return an entirely different object.

So, instead of this:

dxgiDevice = reinterpret_cast<IDXGIDevice1*>(m_d3dDevice);

This is probably all you need:

HRESULT hr = m_d3dDevice->QueryInterface(&dxgiDevice);

Some legacy SDKs don't have the template overload for IUnknown::QueryInterface that eliminates the need to deal with IID guids. So the full expanded function is really this:

HRESULT hr = m_d3dDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgiDevice);

Or the most "old school" way (assuming you know how to link in the definition for the IID variable). dxguids.lib might still be a thing, otherwise, the header file hacks for DEFINE_GUID.

HRESULT hr = m_d3dDevice->QueryInterface(IID_IDXGIDevice1, (void**)&dxgiDevice);
selbie
  • 100,020
  • 15
  • 103
  • 173
  • ``Microsoft::WRL::ComPtr`` is an improved version of ATL's ``CComPtr``, and it's available in all versions of Visual C++/ Windows SDK back to VS 2012. if you were using C++/WinRT, the ``winrt::com_ptr`` class is a good choice. See [this wiki page](https://github.com/Microsoft/DirectXTK/wiki/ComPtr). It has nothing to do with "Managed" or "CLR". – Chuck Walbourn Nov 22 '20 at 22:34