Search code examples
c++windows-shellshell-namespace-extension

Add Custom Banner to Namespace Extension


Windows explorer has the ability to show a custom banner when doing a search and indexing is disabled:

Explorer indexing not running image

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.


Solution

  • 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;
    }
    
    1. 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;
    }
    
    1. 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