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

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.

Related

C++ Builder - Warning W8127 Function defined with different linkage

I have imported an Activex component (*.ocx) on Embarcadero C++Builder 10.2 when I build the program I get this warning "Warning W8127 Function defined with different linkage".
Can any one tell me how I can resolve this issue.
My code is below:
#include <vcl.h>
#pragma hdrstop
#include <System.Win.ComServ.hpp>
#include <axbase.h>
#include <olectl.h>
#pragma package(smart_init)
#pragma link "System.Win.ComServ"
#pragma package(smart_init)
#pragma link "System.Win.ComServ"
// -----------------------------------------------------------------------------
// Entry point of your Server invoked by Windows for processes or threads are
// initialized or terminated.
//
// -----------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return TRUE;
}
// -----------------------------------------------------------------------------
// Entry point of your Server invoked to inquire whether the DLL is no
// longer in use and should be unloaded.
// -----------------------------------------------------------------------------
STDAPI __export DllCanUnloadNow(void)
{
Comserv::TComServer* comserver = Comserv::GetComServer();
return (!comserver ||
((comserver->ObjectCount /* + comserver->FactoryCount */) == 0)) ?
S_OK : S_FALSE;
}
// -----------------------------------------------------------------------------
// Entry point of your Server allowing OLE to retrieve a class object from
// your Server
// -----------------------------------------------------------------------------
STDAPI __export DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
Comobj::TComObjectFactory* Factory = Comobj::ComClassManager()->GetFactoryFromClassID(rclsid);
if (Factory)
{
if (Factory->GetInterface(riid, ppv))
return S_OK;
else
return E_NOINTERFACE;
}
else
{
*ppv = 0;
return CLASS_E_CLASSNOTAVAILABLE;
}
}
// -----------------------------------------------------------------------------
// Entry point of your Server invoked to instruct the server to create
// registry entries for all classes supported by the module
// -----------------------------------------------------------------------------
STDAPI __export DllRegisterServer(void)
{
Comserv::TComServer* comserver = Comserv::GetComServer();
if (comserver)
{
try
{
comserver->LoadTypeLib();
comserver->UpdateRegistry(true);
return S_OK;
}
catch(...)
{
return E_FAIL;
}
}
else
{
return E_FAIL;
}
}
// -----------------------------------------------------------------------------
// Entry point of your Server invoked to instruct the server to remove
// all registry entries created through DllRegisterServer.
// -----------------------------------------------------------------------------
STDAPI __export DllUnregisterServer(void)
{
Comserv::TComServer* comserver = Comserv::GetComServer();
if (comserver)
{
try
{
comserver->LoadTypeLib();
comserver->UpdateRegistry(false);
return S_OK;
}
catch(...)
{
return E_FAIL;
}
}
else
{
return E_FAIL;
}
}
// ------------------------------------------------------------------------------
// Entry point of your Server installation/setup. Used for 'PerUser' registration
// Invoked via call to "regsvr32 /n /i:user [/u] axlibrary.dll"
// ------------------------------------------------------------------------------
STDAPI __export DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
{
Comserv::TComServer* comserver = Comserv::GetComServer();
if (comserver)
{
bool savePerUser = comserver->PerUserRegistration;
if (pszCmdLine && !StrIComp(pszCmdLine, L"user"))
comserver->PerUserRegistration = true;
else
comserver->PerUserRegistration = false;
HRESULT result = E_FAIL;
if (bInstall)
{
result = DllRegisterServer();
if (result == E_FAIL)
DllUnregisterServer();
}
else
result = DllUnregisterServer();
comserver->PerUserRegistration = savePerUser;
return result;
}
else
{
return E_FAIL;
}
}
The functions DllCanUnloadNow() and DllGetClassObject are declared in this header file "comebaseapi.h" as follow:
_Check_return_
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv);
__control_entrypoint(DllExport)
STDAPI DllCanUnloadNow(void);
The functions DllRegisterServer() and DllUnregisterServer() are declared in this header file "olectl.h" as follow:
__control_entrypoint(DllExport)
STDAPI DllRegisterServer(void);
__control_entrypoint(DllExport)
STDAPI DllUnregisterServer(void);
The function DllInstall() is declared in this header file "shlwapi.h" as follow:
// DllInstall (to be implemented by self-installing DLLs)
STDAPI DllInstall(BOOL bInstall, _In_opt_ PCWSTR pszCmdLine);
I thank you for your support.

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

Windows Explorer: self implemented Overlay Icons do not work

I'm trying to simply display some overlay icons in the Windows Explorer.
Since I'm relatively new to programming for Windows (I just have some experience in Mac programming), I used this article to start.
So this is my code:
Icon.h
#pragma once
#include "resource.h"
#include "ExplorerSync_i.h"
using namespace ATL;
class ATL_NO_VTABLE CIcon :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CIcon, &CLSID_Icon>,
public IShellIconOverlayIdentifier,
public IDispatchImpl<IIcon, &IID_IIcon, &LIBID_ExplorerSyncLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CIcon();
STDMETHOD(GetOverlayInfo)(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD* pdwFlags);
STDMETHOD(GetPriority)(int* pPriority);
STDMETHOD(IsMemberOf)(LPCWSTR pwszPath, DWORD dwAttrib);
DECLARE_REGISTRY_RESOURCEID(IDR_ICON)
BEGIN_COM_MAP(CIcon)
COM_INTERFACE_ENTRY(IIcon)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellIconOverlayIdentifier)
END_COM_MAP()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
protected:
};
Icon.cpp
#include "stdafx.h"
#include "Icon.h"
#using <system.dll>
using namespace System;
using namespace System::Diagnostics;
STDMETHODIMP CIcon::GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int * pIndex, DWORD * pdwFlags)
{
GetModuleFileNameW(_AtlBaseModule.GetModuleInstance(), pwszIconFile, cchMax);
*pIndex = 0;
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
return S_OK;
}
STDMETHODIMP CIcon::GetPriority(int * pPriority)
{
*pPriority = 0;
return S_OK;
}
STDMETHODIMP CIcon::IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib)
{
wchar_t *s = _wcsdup(pwszPath);
HRESULT r = S_FALSE;
_wcslwr_s(s, 1);
r = S_OK;
free(s);
return r;
}
CIcon::CIcon() {
}
ExplorerSync.cpp
#include "stdafx.h"
#include "resource.h"
#include "ExplorerSync_i.h"
#include "dllmain.h"
#include "Icon.h"
#using <system.dll>
using namespace System;
using namespace System::Diagnostics;
using namespace ATL;
STDAPI DllCanUnloadNow(void)
{
return _AtlModule.DllCanUnloadNow();
}
_Check_return_
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
STDAPI DllRegisterServer(void)
{
HRESULT hr = _AtlModule.DllRegisterServer();
// not possible to instantiate, because it is abstract according to error message
//CIcon *cIcon = new (std::nothrow) CIcon();
return hr;
}
STDAPI DllUnregisterServer(void)
{
HRESULT hr = _AtlModule.DllUnregisterServer();
return hr;
}
STDAPI DllInstall(BOOL bInstall, _In_opt_ LPCWSTR pszCmdLine)
{
HRESULT hr = E_FAIL;
static const wchar_t szUserSwitch[] = L"user";
if (pszCmdLine != NULL)
{
if (_wcsnicmp(pszCmdLine, szUserSwitch, _countof(szUserSwitch)) == 0)
{
ATL::AtlSetPerUserRegistration(true);
}
}
if (bInstall)
{
hr = DllRegisterServer();
if (FAILED(hr))
{
DllUnregisterServer();
}
}
else
{
hr = DllUnregisterServer();
}
return hr;
}
So I used primarily the code from the example mentioned above and because it did not work, I changed the code a bit according to my thoughts.
The problem is not the compiling. This works and registration via regsvr32 as well without any errors. But with some event log entries I found out, that DllRegisterServer is the only method which is called. All the other functions (especially the interface implementations for the icons) are not called at all. Although it's not done in the example, I tried to instantiate the Icon class in the DllRegisterServer method in the hope it helps, but I cannot do that (error message: Icon is abstract and cannot be instantiated).
So can anybody tell me, what's going wrong, please?
Thank you so much in advance!

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

IHTMLDocument2->documentElement->outerHTML is too slow recreating HTML from DOM, is there a faster way?

I've got an IE BHO plugin that sends out via a COM call the HTML of a page that was loaded in the window.
// Note all error handling removed for readability :)
STDMETHODIMP CPlugin::get_HTML(long lMaxSize, BSTR *pbstrHTML)
{
CComPtr<IDispatch> pDispatch;
MSHTML::IHTMLDocument2Ptr pDocument2 = NULL;
MSHTML::IHTMLDocument3Ptr pDocument3 = NULL;
hr = m_spWebBrowser->get_Document(&pDispatch);
hr = pDispatch->QueryInterface(IID_IHTMLDocument3, (void**)&pDocument3);
MSHTML::IHTMLElementPtr pRoot = pDocument3->documentElement;
wstring strHTML = pRoot->outerHTML;
CComBSTR bstrHTML = strOutput.c_str();
bstrHTML.CopyTo(pbstrHTML);
}
However when it encounters a very large page (e.g. "http://sitemap.zillow.com/uncompressed/ForSale_Hood_MedPri_1.xml"), it takes 3 minutes to create the HTML from the DOM.
Is there a way to access the raw HTML/XML?
When you do a 'view page source' in IE, it pops up almost immediately, so internally IE must be using some API that can do what I want.
Thanks,
Shane.
It seems that in old versions of MSHTML, outerHTML had a O(n^2) performance. However, in newer versions (IE8) this problem is gone. If you have a choice, use IE8 or later.
Otherwise, using IPersistStream::Save is an option. But CreateStreamOnHGlobal won't help you since its implementation is also O(n^2). You'll have to use a custom IStream for that.
Included is an IStream implementation which was made for this purpose and supports quick writes:
#include <atlbase.h>
#include <atlcom.h>
#include <vector>
// an implementation of a write-only IStream.
// needed because the CreateStreamOnHGlobal implementation doesn't handle
// resizes well (N writes seem to take O(N^2) time)
class MyStream :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<MyStream>,
public IStreamImpl
{
public:
std::vector<char> buf;
BEGIN_COM_MAP(MyStream)
COM_INTERFACE_ENTRY(IStream)
END_COM_MAP()
STDMETHOD(Write) (const void * pv, ULONG cb, ULONG *pcbWritten);
};
/*
Usage:
CComPtr<IStream> stream;
hr = MyStream::CreateInstance(&stream);
// streamObj will be valid as long as IStream smart pointer lives
MyStream *streamObj = (MyStream*)stream.p;
*/
STDMETHODIMP MyStream::Write(const void * pv, ULONG cb, ULONG *pcbWritten)
{
buf.insert(buf.end(), (char*)pv, (char*)pv+cb);
return S_OK;
}
Yes, you can QI for IPersistStream and save to a memory stream created by CreateStreamOnHGlobal
Note the document must finished downloading (ready state needs to be complete).
Thanks Amnon, the following code is mostly working for me.
// an implementation of a write-only IStream.
// needed because the CreateStreamOnHGlobal implementation doesn't handle
// resizes well (N writes seem to take O(N^2) time)
class MyStream :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<MyStream>,
public IStream
{
public:
std::vector<char> buf;
BEGIN_COM_MAP(MyStream)
COM_INTERFACE_ENTRY(IStream)
END_COM_MAP()
STDMETHOD(Write) (const void * pv, ULONG cb, ULONG *pcbWritten);
// Implement IStream abstract functions
STDMETHOD(Read) (void *pv, ULONG cb, ULONG *pcbRead) { return S_OK; };
STDMETHOD(Seek) (LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition) { return S_OK; };
STDMETHOD(SetSize) (ULARGE_INTEGER libNewSize) { return S_OK; };
STDMETHOD(CopyTo) (IStream *pstm,ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead,ULARGE_INTEGER *pcbWritten) { return S_OK; };
STDMETHOD(Commit) (DWORD grfCommitFlags) { return S_OK; };
STDMETHOD(Revert) () { return S_OK; };
STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return S_OK; };
STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return S_OK; };
STDMETHOD(Stat) (__RPC__out STATSTG *pstatstg,DWORD grfStatFlag) { return S_OK; };
STDMETHOD(Clone) (__RPC__deref_out_opt IStream **ppstm) { return S_OK; };
};
STDMETHODIMP MyStream::Write(const void * pv, ULONG cb, ULONG *pcbWritten)
{
buf.insert(buf.end(), (char*)pv, (char*)pv+cb);
return S_OK;
}
// Retrieves the HTML of the current page
STDMETHODIMP CPlugin::get_HTML(long lMaxSize, BSTR *pbstrHTML)
{
HRESULT hr = S_OK;
try
{
CComPtr<IDispatch> pDispatch;
MSHTML::IHTMLDocumentPtr pDocument = NULL;
CComPtr<IStream> mystream;
hr = MyStream::CreateInstance(&mystream);
// streamObj will be valid as long as IStream smart pointer lives
MyStream *streamObj = (MyStream*)mystream.p;
hr = m_spWebBrowser->get_Document(&pDispatch);
hr = pDispatch->QueryInterface(IID_IHTMLDocument, (void**)&pDocument);
IPersistStreamInitPtr persistStream = pDocument;
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
hr = persistStream->Save(mystream, FALSE);
}
catch(...)
{
TRACE_FN("Got exception somewhere");
}
return hr;
}
Now the only problem left is how to figure why some it returns me single-byte chars most times, and double-byte chars at other times. Any ideas?
Thanks for the help.