Should I call Release on a ID3D10Device interface after using CreateTexture2D? why? - c++

I've this code in a directx10 project.
ID3D10Texture2D *depthStencilBuffer;
UINT a = m_device->Release();
if(FAILED(hr = m_device->CreateTexture2D( &descDepth, NULL, &depthStencilBuffer ))) {
DXGI_D3D10_ErrorExit(hr, L"CreateTexture2D");
return hr;
}
a = m_device->Release();
Now if I stop the debugger at the third line and check the value of a it says 2. And when I stop it at the line after the last one it says 3. I can't understand why. Is the CreateTexture2D function adding references to the ID3D10Device interface? And apparently it's not even adding one reference but two of them since Release() decrements one.
My problem is the documentation for ID3D10Device::CreateTexture2D doesnt specify it adds references to the ID3D10Device object. Same goes for ID3D10Device::CreateRenderTargetView for instance. How am I supposed to guess when to call Release?

I don't have the ability to have the DirectX SDK installed atm to test this, but, in general principals, when it comes to COM you should follow the COM rules and trust that other objects follow the rules too.
i.e. you shouldn't know the implementation of Texture2D but you should trust that if it needs add references to device, that it will also remove them when it is done. You shouldn't be attempting to make additional calls to Release().
Your code should read:
ID3D10Texture2D *depthStencilBuffer = NULL;
if(FAILED(hr = m_device->CreateTexture2D( &descDepth, NULL, &depthStencilBuffer ))) {
DXGI_D3D10_ErrorExit(hr, L"CreateTexture2D");
return hr;
}
depthStencilBuffer->Release();
depthStencilBuffer = NULL;
i.e. you should expect that the call returns a texture2d with a reference count of 1, this is all you need to know. When you're done, you should call release only on the depthStencilBuffer and expect it to clean up itself entirely. If during the implementation the stencil buffer needed references to the device, you should trust that it will also call release on those references correctly.

Related

Marshalling D3D11Device and D3D11DeviceContext objects

This article says:
The ID3D11DeviceContext methods (except for those that exist on
ID3D11DeviceChild) are not free-threaded, that is, they require single
threading. Only one thread may safely be calling any of its methods
(Draw, Copy, Map, etc.) at a time.
I was wondering if I can make COM do the ID3D11DeviceContext synchronization for me.
Let's say I do this (in simplified code):
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
// Create D3D11Device
CComPtr<ID3D11DeviceContext> pD3D11DeviceContext;
pD3D11Device->GetImmediateContext(&pD3D11DeviceContext);
Then I either marshall it:
IStream* pStreamD3D11DeviceContext = NULL;
CComPtr<IUnknown> pUnknownD3D11DeviceContext;
pD3D11DeviceContext->QueryInterface(IID_PPV_ARGS(&pUnknownD3D11DeviceContext));
::CoMarshalInterThreadInterfaceInStream( __uuidof(ID3D11DeviceContext), pUnknownD3D11DeviceContext, &pStreamD3D11DeviceContext );
Or us a GIT table:
CComPtr<IGlobalInterfaceTable> pIGlobalInterfaceTable;
::CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void **)&pIGlobalInterfaceTable );
CComPtr<IUnknown> pUnknownD3D11DeviceContext;
DWORD dwCookieD3D11DeviceContext = 0;
pD3D11DeviceContext->QueryInterface(IID_PPV_ARGS(&pUnknownD3D11DeviceContext));
pIGlobalInterfaceTable->RegisterInterfaceInGlobal( pUnknownD3D11DeviceContext, __uuidof(ID3D11DeviceContext), &dwCookieD3D11DeviceContext );
Unfortunately this doesn't seem to work.
CoMarshalInterThreadInterfaceInStream returns REGDB_E_IIDNOTREG (0x80040155, Interface not registered) and pStreamD3D11DeviceContext remains NULL.
GIT method goes one step further. I get the cookie, but when I try to use it on another MTA thread, the GetInterfaceFromGlobal returns E_INVALIDARG.
CComPtr<ID3D11DeviceContext> pD3D11DeviceContext;
hresult = pIGlobalInterfaceTable->GetInterfaceFromGlobal( dwCookieD3D11DeviceContext, __uuidof(ID3D11DeviceContext), (void**)&pD3D11DeviceContext );
The params for GetInterfaceFromGlobal seem okay, I tested getting the pointer back on the original thread and it worked.
The D3D11Device and D3D11DeviceContext appear to be unmarshallable. Obviously I have neither proxy DLL nor a typelib for the d3d11.
Am I missing anything?
Thank you.

Directshow render filter crashes only in release mode

I've written a custom renderer filter to push video frames to system memory and later to OpenGL. It's not in a DLL and I don't register it, but instead use it like this page describes in the first paragraph. This works fine in the Debug mode, but in Release it starts crashing. I'm doing the following to initialize the graph:
HRESULT hr;
CoInitialize(0);
CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC, IID_IGraphBuilder, (void**)&graph);
graph->QueryInterface(IID_IMediaControl, (void**)&mediaControl);
graph->QueryInterface(IID_IMediaSeeking, (void**)&mediaSeeking);
grabber = new textureGrabber(0, &hr);
grabber->AddRef(); // crash here
grabber->setTexture(&texture);
grabber->QueryInterface(IID_IBaseFilter, (void**)&base);
graph->AddFilter(base, L"OpenGL texture video filter");
graph->RenderFile(path.c_str(), 0);
This crashes on the AddRef() due to an access violation. I've already tried implementing the IUnknown of the class myself, and the best I got was to the AddFilter where it crashed because the IBaseFilter seemed to be invalid. After that I found even a Microsoft-issued example doing this the simple way and it seems to work for them. I'm curious what might be wrong since I'm doing the same exact thing - even tried the smart pointers.
EDIT: The problem is in the CBaseFilter DECLARE_IUNKNOWN macro, the GetOwner()->AddRef fails. GetOwner itself seems to work.
GetOwner returns whatever you pass as the second parameter to the CBaseFilter constructor. Normally NULL unless you are aggregating the object for some reason (if you are, you probably don't need to).
A crash can occur at that point if your release build is linking against Strmbasd.lib, which is the debug version of the DirectShow base class library.
Change your project's release configuration to link against Strmbase.lib instead, which is the release version of the library.

What is the best way to keep a ATL service running

I have created a ATL service and while testing I simply kept it running by leaving a while loop that ran forever (see code below)
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
m_running = true;
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, &MyFunctionToRunInTheService, 0, 0, 0);
while(m_running);
return CAtlServiceModuleT::Run(nShowCmd);
}
Im now ready to actually run it as a real service but am not sure how I go about doing this? I have looked all over the next and dont seem to be able to find one example of a ATL service.
If I remove the thread code and call the method direct the service is constantly in a start status. If i remove the loop the service simply starts and stops straight away. Any sugestions?
Ive fixed the problem by changing the code to
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
_beginthreadex(NULL, 0, &CheckForExpiredFiles, 0, 0, 0);
return CAtlServiceModuleT::Run(nShowCmd);
}
I didnt really need the while loop at all. On further investigation the code to keep the service alive comes as standard. The problem was that the PreMessageLoop method in atlbase.h was returning S_FALSE which casued the service to stop. The reason it returned S_FALSE in my case was becuase I had not added any COM objects. I have therefore overridden the PreMessageLoop method to return S_OK in this case.
Well, in my case, add _ATL_NO_COM_SUPPORT macro to C\C++ preprocessor solve the problem.
See more here...

Application crashes when creating an object

I have a class which inherits from IDirectInputA interface.
here: http://pastebin.com/QuHP02ai
so, when i try to create object of this, application crashes (calls CorExitProcess from somewhere). What i did wrong?
p.s. Direct input v. 7
p.p.s.
this code creates object. I deleted some code from it, except the main part
IDirectInputA** ppDI;
HRESULT hr = _DirectInputCreateA(hinst, dwVersion, ppDI, punkOuter);
xDirectInputA xDI = new xDirectInputA((IDirectInputA*)(*ppDI));
When you create your instance, you pass a pointer to IDirectInputA, right? What pointer do you pass? If you pass an uninitialized or a null pointer, you will get undefined behavior.
TBH what you are trying to do is more complicated than you think. The problem arises in what exactly you are trying to do. Are you trying to wrap IDirectInputA OR are you trying to completely re-implement it.
If you are trying to wrap it do the following:
IDirectInputA* pDI = NULL;
HRESULT hr = _DirectInputCreateA( hinst, dwVersion, &pDI, NULL );
Then create your derived class as follows:
class xDirectInputA : public IDirectInputA
{
protected:
IDirectInputA* mpInternal;
public:
xDirectInputA( IDirectInputA* pInternal ) :
mpInternal( pInternal )
HRESULT CreateDevice( REFGUID rguid, IDirectInputDevice** ppDirectInputDevice, IUknown* pOuter )
{
// Do what ever processing you need.
return mpInternal->CreateDevice( rguid, ppDirectInputDevice, pOuter );
}
// Implement other functions.
};
Now you pass your xDirectInputA pointer around instead of the normal pointer returned from DirectInputCreate. You can now intercept every message that goes through the class.
If you are trying to do your own full re-implementation it is a LOT more complicated. You are going to need to fully implement the COM object. You'll be best off putting a DInput.DLL alongside the executable that contains your implementation. All in though this is only something you should try if you REALLY know what you are doing.
If you wish to learn COM fully I suggest purchasing Essential COM by Don Box. Its a VERY helpful book.

How to obtain the PIDL of an IShellFolder

If I have an IShellFolder interface pointer. How might I obtain its PIDL?
I can see how to enumerate its children, and I can see how to use it to compare any two children. But how might I get its own pidl?
I ask because I'd like to know:
Is this IShellFolder == Another IShellFolder
I can use IShellFolder::CompareIDs(), but I have to have the IDs of both folders.
What either Chris or Mordechai writes on #1 is anyway not to the point. The question is not about objects in the shell namespace but about objects that have an IShellFolder interface. Possession of an IShellFolder interface does not itself imply a presence in the shell namespace. The original question is ill-formed, inasmuch as it assumes that an object with an IShellFolder interface must have "its own PIDL".
The best you can do, I think, is as Mordechai suggests:
see if the object also has an IPersistFolder2 interface
The purpose of this interface is to fix the object in the shell namespace, which is in turn what makes the folder persistable. Rather than infer from any absence of published documentation, look at what Microsoft actually does say of the IPersistFolder and IPersistFolder2 interfaces and the Initialize and GetCurFolder methods. Most notably:
you need to implement this interface so that the Shell folder object's ITEMIDLIST can be retrieved.
On #2, I'm afraid Chris is definitely not correct. An IShellFolder certainly can be obtained without a PIDL. The Control Panel, which Chris introduced for #1, provides a ready counter-example for #2. Just feed CLSID_ControlPanel and IID_IShellFolder to CoCreateInstance. You get a perfectly usable instantiation of the Control Panel without ever "having knowledge of a PIDL".
There are a handful of other creatable shell folders implemented in SHELL32, and any DLL can set up any number of others.
I found that you can query an IShellFolder for its IPersistFolder2, which has GetCurFolder(), which returns its absolute PIDL. I could then simply use the IShellFolder for the desktop to CompareIDs() to determine if they're equal. I found the outlines of this while looking at SHGetIDListFromObject. I couldn't just use that function, because its Vista, and I need XP compatibility.
Here's a sketch of how it works (assuming you have an ifolder_desktop, and ifolder_other, which are IShellFolder pointers. Pidl is a simple helper that ensures that the IDLISTs are deallocated properly):
CComQIPtr<IPersistFolder2> ipf2_desktop(ifolder_desktop);
CComQIPtr<IPersistFolder2> ipf2_folder(ifolder_other);
Pidl pidl_desktop, pidl_folder;
VERIFY(SUCCEEDED(ipf2_desktop->GetCurFolder(pidl_desktop)));
VERIFY(SUCCEEDED(ipf2_folder->GetCurFolder(pidl_folder)));
HRESULT hr = ifolder_desktop->CompareIDs(NULL, pidl_desktop, pidl_folder);
pCmdUI->Enable(SUCCEEDED(hr) && HRESULT_CODE(hr) != 0);
In case anyone is interested in my simple Pidl class:
class Pidl
{
public:
// create empty
Pidl() : m_pidl(NULL) { }
// create one of specified size
explicit Pidl(size_t size) : m_pidl(Pidl_Create(size)) {}
// create a copy of a given PIDL
explicit Pidl(const ITEMIDLIST * pidl) : m_pidl(Pidl_Copy(pidl)) {}
// create an absolute PIDL from a parent + child
Pidl(const ITEMIDLIST_ABSOLUTE * pParent, const ITEMIDLIST_RELATIVE * pChild) : m_pidl(Pidl_Concatenate(pParent, pChild)) { }
// return our PIDL for general use (but retain ownership of it)
operator const ITEMIDLIST * () { return m_pidl; }
// return a pointer to our pointer, for use in functions that assign to a PIDL
operator ITEMIDLIST ** ()
{
free();
return &m_pidl;
}
// release ownership of our PIDL
ITEMIDLIST * release()
{
ITEMIDLIST * pidl = m_pidl;
m_pidl = NULL;
return pidl;
}
void free()
{
if (m_pidl)
//Pidl_Free(m_pidl);
ILFree(m_pidl);
}
// automatically free our pidl (if we have one)
~Pidl()
{
free();
}
private:
ITEMIDLIST * m_pidl;
};
I forgot to mention the SHGetIDListFromObject function.
It's only available in Windows Vista and higher. It has the advantage of being documented, albeit tersely. You get more detail, of course, from my own documentation. This shows that Microsoft knows two more ways of getting a PIDL for an arbitrary interface pointer to an object in the shell namespace.
Mordachai's answer might be correct, but to me this query makes no sense on two fronts:
I don't believe there is a published document saying that an IShellFolder can have only one parent. There might be multiple ways to any particular shell folder. the control panel is accessible via My Computer, via the Start Menu, and anywhere in the file system you create a
junction point to it. It seems the shell teams oringinal intention was, given an IShellFolder instance, it should not matter to external users what its arbitrary location happened to be.
Plus, any application that instantiates an IShellFolder surely did so FROM a having knowledge of a PIDL. If your app cared about the path to an IShellFolder it already HAD that information. How did you loose it? (And why should the shell team add a method to help apps keep track of their own data?)
As said before there may be lots of issues with special folders like Control Panel (I still donĀ“t understand it fully) but here is a simple solution for "normal" folders:
HRESULT get_pidl(IShellFolder * sf, LPITEMIDLIST * pidl)
{
if (!sf || !pidl) return E_FAIL;
wchar_t FolderName[MAX_PATH] = {0};
STRRET strDispName;
sf->GetDisplayNameOf(NULL, SHGDN_FORPARSING, &strDispName);
StrRetToBuf(&strDispName, NULL, FolderName, (UINT)MAX_PATH);
IShellFolder * desktop = nullptr;
SHGetDesktopFolder(&desktop);
ULONG cbEaten, atrib = 0;
HRESULT hr = desktop->ParseDisplayName(NULL, nullptr, FolderName, &cbEaten, pidl, &atrib);
desktop->Release();
return hr;
}