iSampleGrabber, callback method. Code works, but might need some love? - c++

Okay. So I've got my isamplegrabber callback method to work, and I am able to get the data into opencv. But due to the fact that this is totally new to me, I just want to get some feedback if the code is "correct", cause it doesn't seem to be a good one..
At first in my code (from internet) I've got:
#pragma region Formerly located in qedit.h in Windows SDK, now obsoleted and defined within project
void createDirectShowGraph(void);
struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
ISampleGrabberCB : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SampleCB (double SampleTime, struct IMediaSample * pSample ) = 0;
virtual HRESULT __stdcall BufferCB (double SampleTime, unsigned char * pBuffer, long BufferLen ) = 0;
};
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994, { 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
ISampleGrabber : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SetOneShot (long OneShot ) = 0;
virtual HRESULT __stdcall SetMediaType (struct _AMMediaType * pType ) = 0;
virtual HRESULT __stdcall GetConnectedMediaType (struct _AMMediaType * pType ) = 0;
virtual HRESULT __stdcall SetBufferSamples (long BufferThem ) = 0;
virtual HRESULT __stdcall GetCurrentBuffer (/*[in,out]*/ long * pBufferSize,
/*[out]*/ long * pBuffer ) = 0;
virtual HRESULT __stdcall GetCurrentSample (/*[out,retval]*/ struct IMediaSample * * ppSample ) = 0;
virtual HRESULT __stdcall SetCallback (struct ISampleGrabberCB * pCallback,long WhichMethodToCallback ) = 0;
};
struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37"))
SampleGrabber;
// [ default ] interface ISampleGrabber
#pragma endregion
And later, with much help from the internet, I inserted this:
class CFakeCallback : public ISampleGrabberCB
{
public:
//some variables and stuff...
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
{
//CheckPointer(ppv, E_POINTER);
if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown)
{
*ppv = (void *) static_cast<ISampleGrabberCB *>(this);
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample )
{
//The data for grabbing the frames.
}
STDMETHODIMP BufferCB( double SampleTime, BYTE * pBuffer, long BufferLen )
{
return 0;
}
};
CFakeCallback callbackF;
And I use:
pSampleGrabber->SetCallback(&callbackF,0);
Everything works, but I wonder.
Do i need to create a new class for the callback method? I can see the all the methods in the "#pragma region..." Can't I use those methods for the callback?
question(s):
one: Do I need to have that class "fakeCallback" for the sampleCB/bufferCB method? Or can I in some way use the methods in the first code-part?
two: "virtual" - method, means that this method can be "overwritten"? is that what I am doing when creating the class fakeCallback, with methods sampleCB & bufferCB?
Thanks!

If you are just want to grab a frame from the filter graph by using callback then you need to implement ISampleGrabberCB interface.
You have already implemented CFakeCallback which is required to use ISampleGrabberCB interface. You can grab the sample either using BufferCB or SampleCB. So when you are implementing CFakeCallback you will need to override both SampleCB and BufferCB. One of them will contain you custom code to grab sample while the other will return just S_OK (0). In you code you are using SampleCB which is correct.
However if you don't want to use callback method then SampleGrabber is already present in Windows SDK. You will just need to include qedit.h in your application and you are done.

Related

Add Custom Banner to Namespace Extension

Windows explorer has the ability to show a custom banner when doing a search and indexing is disabled:
I would like to display a similar banner in a custom namespace extension with a custom message and custom link handler. Is there an namespace extension interface I can implement that will allow me to provide this functionality? I have searched for various terms in the namespace extension documentation , but I can't figure out the correct terms to use.
That feature is not documented by Microsft. And i found how to show information bar from namespace extension.
Picture
First you need declare 3 undocumented interface
IInfobarHost
MIDL_INTERFACE("e38fe0f3-3db0-47ee-a314-25cf7f4bf521")
IInfoBarHost : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Inform(IInfoBarMessage* msg) = 0;
virtual HRESULT STDMETHODCALLTYPE CancelInform(GUID guid) = 0;
};
IInfobarMessage
MIDL_INTERFACE("819d1334-9d74-4254-9ac8-dc745ebc5386")
IInfoBarMessage : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetMessageID(GUID* guid,INT* intVal) = 0;
virtual HRESULT STDMETHODCALLTYPE GetMessageW(LPWSTR* message) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateMenu(HMENU* pMwnu) = 0;
virtual HRESULT STDMETHODCALLTYPE HandleMenu(HWND hwnd,int intVal) = 0;
};
IBrowserProgressSessionProvider
MIDL_INTERFACE("18140CBD-AA23-4384-A38D-6A8D3E2BE505")
IBrowserProgressSessionProvider : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE BeginSession() = 0; //Unknown
virtual HRESULT STDMETHODCALLTYPE EndSession() = 0;//Unknown
virtual HRESULT STDMETHODCALLTYPE GetCurrentSession(PDWORD sessionId) = 0;
virtual HRESULT STDMETHODCALLTYPE ActivateSession() = 0;//Unknown
};
IID_IInfoBarHost : e38fe0f3-3db0-47ee-a314-25cf7f4bf521
IID_IBrowserProgressConnection : 20174539-B2C7-4EC7-970B-04201F9CDBAD
IID_IBrowserProgressAggregator : 5EA8EEC4-C34B-4DE0-9B56-0E15FD8C8F80
IID_IBrowserProgressSessionProvider : 18140CBD-AA23-4384-A38D-6A8D3E2BE505
2.Create one class and implement IInfoBarMessage.
GetMessageID(GUID* guid,INT* pIntVal)
Get Infobar guid. Generate own random guid for current infobar message.
HRESULT STDMETHODCALLTYPE CInfoBarMessageImpl::GetMessageID(GUID* guid, INT* intVal) {
//Our InformationBar GUID (generated in constructor)
*guid = this->guid;
return S_OK;
}
GetMessageW(LPWSTR* message)
Get InformationBar message
allocate memory and copy unicode string to parameter (using CoTaskMemAlloc)
HRESULT STDMETHODCALLTYPE CInfoBarMessageImpl::GetMessageW(LPWSTR* message) {
if (!this->message) { //message set at constructor or set at our own initialize function
return E_FAIL;
}
*message = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (this->messageLen + 1));
wcscpy_s(*message, this->messageLen + 1, this->message);
return S_OK;
}
Get IServiceProvider from ShellView(IShellView) and Get IBrowserProgressSessionProvider interface to get dwCookie value.
After that , Get IBrowserProgressConnection From GIT(GlobalInterfaceTable) using ‘dwCookie’ from ‘GetCurrentSession’ and Get IInfoBarHost interface From BrowserProgressConnection
//CInfobarManger is own class (does not implement anyone)
void CInfoBarManager::ShowInfoBar(IShellView* shview) {
HRESULT hr;
DWORD dwCookie = 0;
if (!this->sprovider) {
hr = shview->QueryInterface(IID_IServiceProvider, (PVOID*)&sprovider);
if (FAILED(hr)) {
goto escapeArea;
}
}
if (!this->sessionProvider) {
hr = this->sprovider->QueryService(IID_IBrowserProgressAggregator, IID_IBrowserProgressSessionProvider, (PVOID*)&this->sessionProvider);
if (FAILED(hr)) {
goto escapeArea;
}
}
hr = sessionProvider->GetCurrentSession(&dwCookie);
if (FAILED(hr)) {
goto escapeArea;
}
//Get GIT
if (!this->git) {
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable, (PVOID*)&this->git);
if (FAILED(hr)) {
goto escapeArea;
}
}
hr = this->git->GetInterfaceFromGlobal(dwCookie, IID_IBrowserProgressConnecion, (PVOID*)&this->browserProgress);
if (hr == S_OK) {
hr = this->browserProgress->QueryInterface(IID_IInfoBarHost, (PVOID*)&this->host);
if (hr == S_OK) {
//Call Relase in explorer inside
this->infoMsg->AddRef();
this->host->Inform(this->infoMsg);
}
}
escapeArea:
return;
}
Show Infobar at MessageSFVCB if uMsg is 17 (onrefresh) or other place if you want.
//in MessageSFVCB
else if (uMsg == 17) { //OnRefresh
if (!this->infobar) {
this->infobar = new CInfoBarManager();
infobar->InitializeSimple(L"NSE Information Bar Message");
}
infobar->ShowInfoBar(this->shview); //IShellView
}
sample codes : https://github.com/bho3538/NSEInformationBar

C++ - DirectWrite: Load font from file at runtime

I'm trying to load a font from a file at runtime and display it with DirectWrite. The following code should initialize a IDWriteTextFormat object with that font:
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
NULL, // Font collection (NULL sets it to use the system font collection)
// Somehow, a custom font collection should be used here, but I don't know how to do that
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
It works perfectly with system fonts but I don't know how to load a custom font file. I would appreciate any examples on how to achieve that.
What I tried so far:
• I read this article and this question on Stackoverflow but I don't see where one should pass the file path of the font file (therefore, I completely failed to implement any of the code provided on those two pages)
• I also read this article but if I'm right, it has nothing to do with DirectWrite (?) (I tried to implement the AddFontResourceEx-method, but to no avail)
• Finally, the answer to this question suggested using ResourceFontContext::CreateFontCollection could solve the problem but after reading this page (it's in German but the screenshot is in English) I believe that it can only be used with fonts embedded as resources (which is not an option in my case)
Sure, it's possible to do that. You'll need to:
implement IDWriteFontCollectionLoader interface in your code;
You should also implement IDWriteFontFileEnumerator obviously, but this should be trivial.
register loader with the factory using RegisterFontCollectionLoader
create a collection using CreateCustomFontCollection and same factory;
pass it to CreateTextFormat called on same factory.
When you call CreateCustomFontCollection you have to provide a collection key and its size, it's a blob only meaningful to you, could be anything. Later on your loader will be called with this key, so you can identify it. For example you can use a string 'myspecialkey' as a key, and in CreateEnumeratorFromKey check if it's called with that key, rejecting any other key.
If you only wanted to create a fontface object from a path to a file, you don't need any of above, just use CreateFontFileReference followed by CreateFontFace.
If anyone is interested in the code which finally worked:
Add Common.h, FontLoader.h and FontLoader.cpp to your project (code is given below) and add the following lines to your application:
#include "FontLoader.h"
// ...
IDWriteFactory* pDWriteFactory;
IDWriteFontCollection *fCollection;
IDWriteTextFormat* pTextFormat;
// ...
MFFontContext fContext(pDWriteFactory);
std::vector<std::wstring> filePaths; // vector containing ABSOLUTE file paths of the font files which are to be added to the collection
std::wstring fontFileFilePath = L"C:\\xyz\\abc.ttf";
filePaths.push_back(fontFileFilePath);
HRESULT hr = fContext.CreateFontCollection(filePaths, &fCollection); // create custom font collection
hr = pDWriteFactory->CreateTextFormat(
L"Font Family", // Font family name
fCollection,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
16.0f,
L"en-us",
&pTextFormat // IDWriteTextFormat object
);
FontLoader.h
#pragma once
#include <string>
#include "Common.h"
typedef std::vector<std::wstring> MFCollection;
class MFFontCollectionLoader : public IDWriteFontCollectionLoader
{
public:
MFFontCollectionLoader() : refCount_(0)
{
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontCollectionLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
);
// Gets the singleton loader instance.
static IDWriteFontCollectionLoader* GetLoader()
{
return instance_;
}
static bool IsLoaderInitialized()
{
return instance_ != NULL;
}
private:
ULONG refCount_;
static IDWriteFontCollectionLoader* instance_;
};
class MFFontFileEnumerator : public IDWriteFontFileEnumerator
{
public:
MFFontFileEnumerator(
IDWriteFactory* factory
);
HRESULT Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
);
~MFFontFileEnumerator()
{
SafeRelease(&currentFile_);
SafeRelease(&factory_);
}
// IUnknown methods
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDWriteFontFileEnumerator methods
virtual HRESULT STDMETHODCALLTYPE MoveNext(OUT BOOL* hasCurrentFile);
virtual HRESULT STDMETHODCALLTYPE GetCurrentFontFile(OUT IDWriteFontFile** fontFile);
private:
ULONG refCount_;
IDWriteFactory* factory_;
IDWriteFontFile* currentFile_;
std::vector<std::wstring> filePaths_;
size_t nextIndex_;
};
class MFFontContext
{
public:
MFFontContext(IDWriteFactory *pFactory);
~MFFontContext();
HRESULT Initialize();
HRESULT CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
);
private:
// Not copyable or assignable.
MFFontContext(MFFontContext const&);
void operator=(MFFontContext const&);
HRESULT InitializeInternal();
IDWriteFactory *g_dwriteFactory;
static std::vector<unsigned int> cKeys;
// Error code from Initialize().
HRESULT hr_;
};
class MFFontGlobals
{
public:
MFFontGlobals() {}
static unsigned int push(MFCollection &addCollection)
{
unsigned int ret = fontCollections.size();
fontCollections.push_back(addCollection);
return ret;
}
static std::vector<MFCollection>& collections()
{
return fontCollections;
}
private:
static std::vector<MFCollection> fontCollections;
};
FontLoader.cpp
#include "FontLoader.h"
IDWriteFontCollectionLoader* MFFontCollectionLoader::instance_(
new(std::nothrow) MFFontCollectionLoader()
);
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontCollectionLoader))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontCollectionLoader::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontCollectionLoader::CreateEnumeratorFromKey(
IDWriteFactory* factory,
void const* collectionKey, // [collectionKeySize] in bytes
UINT32 collectionKeySize,
OUT IDWriteFontFileEnumerator** fontFileEnumerator
)
{
*fontFileEnumerator = NULL;
HRESULT hr = S_OK;
if (collectionKeySize % sizeof(UINT) != 0)
return E_INVALIDARG;
MFFontFileEnumerator* enumerator = new(std::nothrow) MFFontFileEnumerator(
factory
);
if (enumerator == NULL)
return E_OUTOFMEMORY;
UINT const* mfCollectionKey = static_cast<UINT const*>(collectionKey);
UINT32 const mfKeySize = collectionKeySize;
hr = enumerator->Initialize(
mfCollectionKey,
mfKeySize
);
if (FAILED(hr))
{
delete enumerator;
return hr;
}
*fontFileEnumerator = SafeAcquire(enumerator);
return hr;
}
// ------------------------------ MFFontFileEnumerator ----------------------------------------------------------
MFFontFileEnumerator::MFFontFileEnumerator(
IDWriteFactory* factory
) :
refCount_(0),
factory_(SafeAcquire(factory)),
currentFile_(),
nextIndex_(0)
{
}
HRESULT MFFontFileEnumerator::Initialize(
UINT const* collectionKey, // [resourceCount]
UINT32 keySize
)
{
try
{
// dereference collectionKey in order to get index of collection in MFFontGlobals::fontCollections vector
UINT cPos = *collectionKey;
for (MFCollection::iterator it = MFFontGlobals::collections()[cPos].begin(); it != MFFontGlobals::collections()[cPos].end(); ++it)
{
filePaths_.push_back(it->c_str());
}
}
catch (...)
{
return ExceptionToHResult();
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileEnumerator))
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::AddRef()
{
return InterlockedIncrement(&refCount_);
}
ULONG STDMETHODCALLTYPE MFFontFileEnumerator::Release()
{
ULONG newCount = InterlockedDecrement(&refCount_);
if (newCount == 0)
delete this;
return newCount;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::MoveNext(OUT BOOL* hasCurrentFile)
{
HRESULT hr = S_OK;
*hasCurrentFile = FALSE;
SafeRelease(&currentFile_);
if (nextIndex_ < filePaths_.size())
{
hr = factory_->CreateFontFileReference(
filePaths_[nextIndex_].c_str(),
NULL,
&currentFile_
);
if (SUCCEEDED(hr))
{
*hasCurrentFile = TRUE;
++nextIndex_;
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE MFFontFileEnumerator::GetCurrentFontFile(OUT IDWriteFontFile** fontFile)
{
*fontFile = SafeAcquire(currentFile_);
return (currentFile_ != NULL) ? S_OK : E_FAIL;
}
// ---------------------------------------- MFFontContext ---------------------------------------------------------
MFFontContext::MFFontContext(IDWriteFactory *pFactory) : hr_(S_FALSE), g_dwriteFactory(pFactory)
{
}
MFFontContext::~MFFontContext()
{
g_dwriteFactory->UnregisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
}
HRESULT MFFontContext::Initialize()
{
if (hr_ == S_FALSE)
{
hr_ = InitializeInternal();
}
return hr_;
}
HRESULT MFFontContext::InitializeInternal()
{
HRESULT hr = S_OK;
if (!MFFontCollectionLoader::IsLoaderInitialized())
{
return E_FAIL;
}
// Register our custom loader with the factory object.
hr = g_dwriteFactory->RegisterFontCollectionLoader(MFFontCollectionLoader::GetLoader());
return hr;
}
HRESULT MFFontContext::CreateFontCollection(
MFCollection &newCollection,
OUT IDWriteFontCollection** result
)
{
*result = NULL;
HRESULT hr = S_OK;
// save new collection in MFFontGlobals::fontCollections vector
UINT collectionKey = MFFontGlobals::push(newCollection);
cKeys.push_back(collectionKey);
const void *fontCollectionKey = &cKeys.back();
UINT32 keySize = sizeof(collectionKey);
hr = Initialize();
if (FAILED(hr))
return hr;
hr = g_dwriteFactory->CreateCustomFontCollection(
MFFontCollectionLoader::GetLoader(),
fontCollectionKey,
keySize,
result
);
return hr;
}
std::vector<unsigned int> MFFontContext::cKeys = std::vector<unsigned int>(0);
// ----------------------------------- MFFontGlobals ---------------------------------------------------------
std::vector<MFCollection> MFFontGlobals::fontCollections = std::vector<MFCollection>(0);
Common.h
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
//----------------------------------------------------------------------------
#pragma once
// The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified.
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Minimum platform is Windows 7
#define WINVER 0x0601
#endif
#ifndef _WIN32_WINNT // Minimum platform is Windows 7
#define _WIN32_WINNT 0x0601
#endif
#ifndef _WIN32_WINDOWS // Minimum platform is Windows 7
#define _WIN32_WINDOWS 0x0601
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#ifndef UNICODE
#define UNICODE
#endif
// Windows header files
#include <windows.h>
#include <dwrite.h>
#include <d2d1.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <memory>
#include <vector>
// Ignore unreferenced parameters, since they are very common
// when implementing callbacks.
#pragma warning(disable : 4100)
////////////////////////////////////////
// COM inheritance helpers.
// Releases a COM object and nullifies pointer.
template <typename InterfaceType>
inline void SafeRelease(InterfaceType** currentObject)
{
if (*currentObject != NULL)
{
(*currentObject)->Release();
*currentObject = NULL;
}
}
// Acquires an additional reference, if non-null.
template <typename InterfaceType>
inline InterfaceType* SafeAcquire(InterfaceType* newObject)
{
if (newObject != NULL)
newObject->AddRef();
return newObject;
}
// Sets a new COM object, releasing the old one.
template <typename InterfaceType>
inline void SafeSet(InterfaceType** currentObject, InterfaceType* newObject)
{
SafeAcquire(newObject);
SafeRelease(&currentObject);
currentObject = newObject;
}
// Maps exceptions to equivalent HRESULTs,
inline HRESULT ExceptionToHResult() throw()
{
try
{
throw; // Rethrow previous exception.
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
catch (...)
{
return E_FAIL;
}
}
The code is certainly not perfect but it worked for me.
If you have any questions concerning this code just leave a comment (even though I probably won't be able to give a satisfying answer anymore). Note that I copied large parts of the code from here.

Why does ITypeInfo::Invoke return 0x80020003 (Member not found.)?

I am having trouble implementing an event sink for DShellWindowsEvents from SHDocVw.dll in Microsoft Visual C++.
The problem arises inside my implementation of IDispatch::Invoke. I implemented it by delegating its call to ITypeInfo::Invoke (as suggested by Microsoft on remarks section), but it always fails with error code 0x80020003 (Member not found).
It is interesting though that DShellWindowsEvents has only two methods (WindowRegistered and WindowRevoked) and ITypeInfo::GetIDsOfNames works successfully for both, returning the expected DISPID. But then how does it give "Member not found" error for Invoke?
The relevant part of the type library:
[
uuid(FE4106E0-399A-11D0-A48C-00A0C90A8F39),
helpstring("Event interface for IShellWindows")
]
dispinterface DShellWindowsEvents {
properties:
methods:
[id(0x000000c8), helpstring("A new window was registered.")]
void WindowRegistered([in] long lCookie);
[id(0x000000c9), helpstring("A new window was revoked.")]
void WindowRevoked([in] long lCookie);
};
[
uuid(9BA05972-F6A8-11CF-A442-00A0C90A8F39),
helpstring("ShellDispatch Load in Shell Context")
]
coclass ShellWindows {
[default] interface IShellWindows;
[default, source] dispinterface DShellWindowsEvents;
};
and my actual code where it all happens:
class CDShellWindowsEvents : public DShellWindowsEvents {
public:
// IUnknown implementation
virtual HRESULT __stdcall QueryInterface( REFIID riid, LPVOID *ppvObj )
{
if( ppvObj == NULL ) return E_INVALIDARG;
*ppvObj = NULL;
if( riid == IID_IUnknown || riid == IID_IDispatch || riid == DIID_DShellWindowsEvents )
{
*ppvObj = this;
AddRef( );
return NOERROR;
}
return E_NOINTERFACE;
}
virtual ULONG __stdcall AddRef( )
{
InterlockedIncrement( &m_cRef );
return m_cRef;
}
virtual ULONG __stdcall Release( )
{
ULONG ulRefCount = InterlockedDecrement( &m_cRef );
if( 0 == m_cRef )
delete this;
return ulRefCount;
}
// IDispatch implementation
virtual HRESULT __stdcall GetTypeInfoCount( unsigned int * pctinfo )
{
if( pctinfo == NULL ) return E_INVALIDARG;
*pctinfo = 1;
return NOERROR;
}
virtual HRESULT __stdcall GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo ** ppTInfo )
{
if( ppTInfo == NULL ) return E_INVALIDARG;
*ppTInfo = NULL;
if( iTInfo != 0 ) return DISP_E_BADINDEX;
*ppTInfo = m_pTypeInfo;
m_pTypeInfo->AddRef();
return NOERROR;
}
virtual HRESULT __stdcall GetIDsOfNames(REFIID riid, OLECHAR ** rgszNames, unsigned int cNames, LCID lcid, DISPID * rgDispId )
{
return m_pTypeInfo->GetIDsOfNames( rgszNames, cNames, rgDispId );
}
virtual HRESULT __stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, unsigned int * puArgErr )
{
// We could switch on dispIdMember here but we want to do this the flexible way, so we can easily implement it later for dispinterfaces with dozens of methods.
return m_pTypeInfo->Invoke( this, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr );
/*HRESULT ret;
switch( dispIdMember )
{
case 0x000000c8: ret = WindowRegistered( pDispParams->rgvarg[0].intVal ); break;
case 0x000000c9: ret = WindowRevoked( pDispParams->rgvarg[0].intVal ); break;
default: ret = DISP_E_MEMBERNOTFOUND;
}
if( pVarResult ) pVarResult->lVal = ret;
return ret;*/
}
// DShellWindowsEvents implementation
virtual HRESULT __stdcall WindowRegistered( int nCookie )
{
LOG( "CDShellWindowsEvents::WindowRegistered( nCookie=0x%X ) ." , nCookie );
return NOERROR;
}
virtual HRESULT __stdcall WindowRevoked( int nCookie )
{
LOG( "CDShellWindowsEvents::WindowRevoked( nCookie=0x%X ) ." , nCookie );
return NOERROR;
}
// Constructor
CDShellWindowsEvents( )
{
m_cRef = 1;
LoadRegTypeLib( LIBID_SHDocVw, 1, 0, LANG_NEUTRAL, &m_pTypeLib );
m_pTypeLib->GetTypeInfoOfGuid( DIID_DShellWindowsEvents, &m_pTypeInfo );
}
// Destructor
~CDShellWindowsEvents( )
{
m_pTypeInfo->Release( );
m_pTypeLib->Release( );
}
private:
ULONG m_cRef;
ITypeLib *m_pTypeLib;
ITypeInfo *m_pTypeInfo;
};
Is this a problem with the type library not specifying dual for the dispinterface? If yes, is there a way to force ITypeInfo::Invoke to threat it as dual since I know its vtable is in order.
Thanks in advance.
A dispinterface is an automation-only interface, not a dual interface. So, DShellWindowsEvents only natively has the 7 methods of IDispatch, not the extra 2 it declares. It's like declaring an IDispatch-only interface with a contract, such as predefined DISPIDs.
To use ITypeLib::Invoke in that fashion, you need to declare your own interface as [dual] with the extra methods.
[ object, dual, oleautomation, uuid(...) ]
interface IMyDualShellWindowsEvents : IDispatch
{
[id(0x000000c8), helpstring("A new window was registered.")]
HRESULT WindowRegistered([in] long lCookie);
[id(0x000000c9), helpstring("A new window was revoked.")]
HRESULT WindowRevoked([in] long lCookie);
}
You'll need provide or embed your own typelib and load it instead.
DShellWindowsEvents is a dispinterface, so your events object won't be QueryInterfaced for your internal interface, although you may handle that case anyway. As such, you don't need to register your typelib, just load it with LoadLibraryEx.
I think you may add hidden, restricted to the interface attributes, so it doesn't show up and can't be used in e.g. VBA, even by manually adding a reference to such a private typelib.

Filter Connection Issue

When I try to connect my custom written filter to an avi mux filter in graphedt it automaticaly adds a Microsoft DTV-DVD Audio Decoder in between, which isnt need because i proces video streams.
How does graphedt decide to do that and how can i prevent that?
How do two filters decide if they are compatible?
Here is the header file of my output pin:
#pragma once
#include <streams.h>
#include "MyFilter.h"
class MCMyOutputPin : public CBaseOutputPin
{
private:
// parent
CBaseFilter *mux;
IUnknown *position;
public:
MCMyOutputPin(MyFilter* filter, HRESULT *phr, LPCWSTR pName);
virtual ~MCMyOutputPin();
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
// overriden
virtual HRESULT CheckMediaType(const CMediaType *pmt);
virtual HRESULT SetMediaType(const CMediaType *pmt);
virtual HRESULT CompleteConnect(IPin *pReceivePin);
virtual HRESULT BreakConnect();
virtual HRESULT GetMediaType(int i, CMediaType *pmt);
virtual HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProps);
virtual HRESULT Deliver(IMediaSample* sample);
virtual HRESULT AgreeMediaType(IPin* recievePin, const CMediaType *pmt);
// qual prop
STDMETHODIMP Notify(IBaseFilter *pSender, Quality q);
CMediaType &CurrentMediaType() { return m_mt; }
};
And here its implementation:
#include "CMyOutPutPin.h"
#include <fstream>
MCMyOutputPin::MCMyOutputPin(MyFilter* parent, HRESULT *phr, LPCWSTR pName) : CBaseOutputPin(NAME("MyOutPutPin"), parent, &parent->m_lock_filter, phr, pName)
{
}
MCMyOutputPin::~MCMyOutputPin()
{
}
STDMETHODIMP MCMyOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT MCMyOutputPin::CheckMediaType(const CMediaType *pmt)
{
return S_OK;
}
HRESULT MCMyOutputPin::SetMediaType(const CMediaType *pmt)
{
return CBaseOutputPin::SetMediaType(pmt);
}
HRESULT MCMyOutputPin::CompleteConnect(IPin *pReceivePin)
{
return CBaseOutputPin::CompleteConnect(pReceivePin);
}
HRESULT MCMyOutputPin::BreakConnect()
{
return CBaseOutputPin::BreakConnect();
}
HRESULT MCMyOutputPin::GetMediaType(int i, CMediaType *pmt)
{
return CBaseOutputPin::GetMediaType(i, pmt);
}
HRESULT MCMyOutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProps)
{
ALLOCATOR_PROPERTIES act;
HRESULT hr;
// by default we do something like this...
pProps->cbAlign = 1;
pProps->cBuffers = 1;
pProps->cbBuffer = this->CurrentMediaType().lSampleSize;
pProps->cbPrefix = 0;
hr = pAlloc->SetProperties(pProps, &act);
if (FAILED(hr)) return hr;
// make sure the allocator is OK with it.
if ((pProps->cBuffers > act.cBuffers) ||
(pProps->cbBuffer > act.cbBuffer) ||
(pProps->cbAlign > act.cbAlign))
return E_FAIL;
return NOERROR;
}
STDMETHODIMP MCMyOutputPin::Notify(IBaseFilter *pSender, Quality q)
{
// right now we don't do anything ...
return NOERROR;
}
HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
std::ofstream outfile;
outfile.open("C:\\TEMP\\yc1.log", std::ios_base::app);
outfile << "receiving data on outputpin" << std::endl;
outfile.close();
m_pInputPin->Receive(sample);
return CBaseOutputPin::Deliver(sample);
//Forward to filter
}
HRESULT MCMyOutputPin::AgreeMediaType(IPin * pin, const CMediaType* pmt)
{
return S_OK;
}
It happens first of all because pins cannot connect directly. So basically preventing means you would not be able to connect pins, and you would have an error instead.
Additional filter insertion is called Intelligent Connect
Compatibility is ability to connect, to succeeded in IPin::Connect and IPin::ReceiveConnection method

Overriding Direct3D interfaces?

My project launches a target process, injecting a library into it which is meant to hook Direct3D functions. I have done this successfully in the past, but decided to rewrite the library to a closer specification of the Direct3D interfaces. The idea here was to create a set of my own 1:1 wrapper classes, each inheriting a DirectX interface (ie, class CD3D8 : IDirect3D8, class CD3DDevice8 : IDirect3DDevice8 and so forth). Since all members of each underlying DirectX COM interface are pure virtual methods, I thought I could easily override them...
So when my library hooks Direct3DCreate8, I return a pointer to my CDirect3D8 instead of the standard IDirect3D8. And then my library uses the virtual table of that pointer to hook method #15, which is IDirect3D8::CreateDevice. And once that is called, I return a pointer to CDirect3DDevice8 as opposed to IDirect3DDevice8. All appears to be well, except none of the overrided functions are being called by the injected application! Somehow, the app appears to be calling the original interface functions instead of my own. Am I missing some sort of concept here? Do I need to manually remap the virtual table pointers to the ones in my custom wrapper classes, for example?
Here's what I got so far (only showing d3d8):
D3D.h
#pragma once
#define STDM(method) COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE method
#define STDM_(type,method) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE method
template<class IDirect3D8>
class CD3D : public IDirect3D8
{
public:
CD3D();
~CD3D();
/*** IUnknown methods ***/
STDM(QueryInterface)(THIS_ REFIID riid, void** ppvObj);
STDM_(ULONG,AddRef)(THIS);
STDM_(ULONG,Release)(THIS);
/*** IDirect3D8 methods ***/
STDM(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction);
STDM_(UINT, GetAdapterCount)(THIS);
STDM(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER8* pIdentifier);
STDM_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter);
STDM(EnumAdapterModes)(THIS_ UINT Adapter,UINT Mode,D3DDISPLAYMODE* pMode);
STDM(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode);
STDM(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE CheckType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed);
STDM(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat);
STDM(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType);
STDM(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);
STDM(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS8* pCaps);
STDM_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter);
STDM(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface);
};
D3D.cpp
#include "stdafx.h"
#define STDIMP(iface, method, ...) COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CD3D<iface>::method(__VA_ARGS__)
#define STDIMP_(iface, type, method, ...) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE CD3D<iface>::method(__VA_ARGS__)
#define STDIMP8(method, ...) STDIMP(IDirect3D8, method, __VA_ARGS__)
#define STDIMP8_(type, method, ...) STDIMP_(IDirect3D8, type, method, __VA_ARGS__)
CD3D<IDirect3D8>::CD3D()
{
}
CD3D<IDirect3D8>::~CD3D()
{
}
STDIMP8(QueryInterface, THIS_ REFIID riid, void** ppvObj) {
return QueryInterface( riid, ppvObj );
}
STDIMP8_(ULONG, AddRef, THIS) {
return AddRef();
}
STDIMP8_(ULONG, Release, THIS) {
return Release();
}
STDIMP8(RegisterSoftwareDevice, THIS_ void* pInitializeFunction) {
return RegisterSoftwareDevice( pInitializeFunction );
}
STDIMP8_(UINT, GetAdapterCount, THIS) {
return GetAdapterCount();
}
STDIMP8(GetAdapterIdentifier, THIS_ UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER8* pIdentifier) {
return GetAdapterIdentifier( Adapter, Flags, pIdentifier );
}
STDIMP8_(UINT, GetAdapterModeCount, THIS_ UINT Adapter) {
return GetAdapterModeCount( Adapter );
}
STDIMP8(EnumAdapterModes, THIS_ UINT Adapter, UINT Mode, D3DDISPLAYMODE* pMode) {
return EnumAdapterModes( Adapter, Mode, pMode );
}
STDIMP8(GetAdapterDisplayMode, THIS_ UINT Adapter, D3DDISPLAYMODE* pMode) {
return GetAdapterDisplayMode( Adapter, pMode );
}
STDIMP8(CheckDeviceType, THIS_ UINT Adapter, D3DDEVTYPE CheckType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed) {
return CheckDeviceType( Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed );
}
STDIMP8(CheckDeviceFormat, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) {
return CheckDeviceFormat( Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat );
}
STDIMP8(CheckDeviceMultiSampleType, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType) {
return CheckDeviceMultiSampleType( Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType );
}
STDIMP8(CheckDepthStencilMatch, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) {
return CheckDepthStencilMatch( Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat );
}
STDIMP8(GetDeviceCaps, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS8* pCaps) {
return GetDeviceCaps( Adapter, DeviceType, pCaps );
}
STDIMP8_(HMONITOR, GetAdapterMonitor, THIS_ UINT Adapter) {
return GetAdapterMonitor( Adapter );
}
STDIMP8(CreateDevice, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface) {
return CreateDevice( Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface );
}
Main.cpp (Using Microsoft Detours 3.0):
#include <detours.h>
#include "D3D.h"
typedef HMODULE (WINAPI * HookLoadLibraryA)( LPCSTR lpFileName );
typedef IDirect3D8 *(WINAPI * HookDirect3DCreate8)( UINT SdkVersion );
typedef HRESULT (WINAPI * HookCreateDevice8)( IDirect3DDevice8* pInterface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface );
HookLoadLibraryA RealLoadLibraryA;
HookDirect3DCreate8 RealDirect3DCreate8;
HookCreateDevice8 RealCreateDevice8;
//...
CD3D<IDirect3D8> *m_d3d8;
CD3DDevice<IDirect3D8> *m_d3dDev8;
//...
RealLoadLibraryA = (HookLoadLibraryA)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)RealLoadLibraryA, FakeLoadLibraryA);
DetourTransactionCommit();
//...
VOID VirtualHook( PVOID pInterface, PVOID pHookProc, PVOID pOldProc, int iIndex )
{
// Hook a procedure within an interface's virtual table
PDWORD pVtable = (PDWORD)*((PDWORD)pInterface);
DWORD lpflOldProtect;
VirtualProtect( (PVOID)&pVtable[iIndex], sizeof(DWORD), PAGE_READWRITE, &lpflOldProtect );
if( pOldProc ) *(DWORD*)pOldProc = pVtable[iIndex];
pVtable[iIndex] = (DWORD)pHookProc;
VirtualProtect( pVtable, sizeof(DWORD), lpflOldProtect, &lpflOldProtect );
}
HRESULT WINAPI FakeCreateDevice8( IDirect3DDevice8* pInterface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface )
{
HRESULT ret = RealCreateDevice8( pInterface, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface );
// Save the registers
__asm pushad
if(*ppReturnedDeviceInterface != NULL)
m_d3dDev8 = reinterpret_cast<CD3DDevice<IDirect3D8> *>(*ppReturnedDeviceInterface);
// Restore the registers
__asm popad
return ret;
}
IDirect3D8 *WINAPI FakeDirect3DCreate8( UINT SdkVersion )
{
m_d3d8 = reinterpret_cast<CD3D<IDirect3D8> *>(RealDirect3DCreate8( SdkVersion ));
if( m_d3d8 ) {
// Hook CreateDevice (vftable index #15)
VirtualHook( m_d3d8, &FakeCreateDevice8, &RealCreateDevice8, 15 );
}
return m_d3d8;
}
HMODULE WINAPI FakeLoadLibraryA( LPCSTR lpFileName )
{
CStringA strFileName( lpFileName );
int i = strFileName.ReverseFind('\\');
if(i != -1) strFileName = strFileName.Right(i + 1);
if( strFileName.CompareNoCase("d3d8.dll") == 0 )
{
// Hook Direct3DCreate8
HMODULE m_hD3D = RealLoadLibraryA( lpFileName );
RealDirect3DCreate8 = (HookDirect3DCreate8)GetProcAddress(m_hD3D, "Direct3DCreate8");
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourAttach(&(PVOID&)RealDirect3DCreate8, FakeDirect3DCreate8);
DetourTransactionCommit();
return m_hD3D;
}
}
... The hooked functions get called, but none of my wrapper functions do, and the injected application runs just as it normally would. Why is this? Of course, I could manually set hooks for each and every function found in each and every DirectX interface (for each version of Direct3D), but the point of this was to try and prevent having to do that and to keep it a bit cleaner. So is there a way to get this to work as I had intended? Thanks!
You're using reinterpret_cast, which won't do much since the underlying object will still have a pointer to the 'real' IDirect3D8 or IDirect3DDevice8 COM vtable, which will be used for the calls.
Instead, instantiate your custom CD3D or CD3DDevice by passing it the original object instance. Then modify all your calls to call back the correct method on the original object -- your class effectively acting as a transparent proxy.
I mean something such as:
STDIMP8_(ULONG, AddRef, THIS) {
return realObject->AddRef();
}
with realObject being the original IDirect3D8*.