I want to enable proxy from BHO for only Internet Explorer or if that is not possible at least set proxy for LAN.
After the below code is executed nothing happen, proxy is not changed and not enabled.
I want to change proxy settings when a user visit a website, and Idealy will be if it is possible to enable proxy only for internet explorer, so other programs can work normaly with direct connection which not need proxy, so if it is possible to set proxy only for internet explorer please tell me how, I would like also to use PAC automation script if it is possible.
This code have no errors, but proxy is not enabled, and nothing happen:
INTERNET_PER_CONN_OPTION_LIST conn_options;
BOOL bReturn;
DWORD dwBufferSize = sizeof(conn_options);
conn_options.dwSize = dwBufferSize;
conn_options.pszConnection = NULL;//connNameStr;//NULL == LAN
conn_options.dwOptionCount = 3;
conn_options.pOptions = new INTERNET_PER_CONN_OPTION[3];
if(!conn_options.pOptions) ::MessageBox(NULL,_T("option error"),_T("option error"),MB_ICONSTOP);
conn_options.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
conn_options.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT|PROXY_TYPE_PROXY;
conn_options.pOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
conn_options.pOptions[1].Value.pszValue = TEXT("100.200.100.200:1020");
conn_options.pOptions[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
conn_options.pOptions[2].Value.pszValue = _T("local");
bReturn = InternetSetOption(NULL,INTERNET_OPTION_PER_CONNECTION_OPTION, &conn_options, dwBufferSize);
delete [] conn_options.pOptions;
bReturn = InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
bReturn = InternetSetOption(NULL, INTERNET_OPTION_REFRESH , NULL, 0);
The above code is supposed to change the proxy, but if I use it in the below code in the document complete event, it compile successful but will not change the proxy.
#include <windows.h>
#include <tchar.h>
#include <exdisp.h>
#include <exdispid.h>
#include <mshtml.h>
#include <mshtmdid.h>
#include <shlwapi.h>
HINSTANCE hInstance;
LONG gref=0;
const CLSID BhoCLSID = {0xC9C42510,0x9B41,0x42c1,0x9D,0xCD,0x72,0x82,0xA2,0xD0,0x7C,0x61};
#define BhoCLSIDs _T("{C9C42510-9B41-42c1-9DCD-7282A2D07C61}")
class BHO : public IObjectWithSite, public IDispatch
{ long ref;
IWebBrowser2* webBrowser;
IHTMLDocument* doc; IHTMLDocument2 *doc2;
IHTMLWindow2 *win2;
public:
// IUnknown...
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) {if (riid==IID_IUnknown) *ppv=static_cast<BHO*>(this); else if (riid==IID_IObjectWithSite) *ppv=static_cast<IObjectWithSite*>(this); else if (riid==IID_IDispatch) *ppv=static_cast<IDispatch*>(this); else return E_NOINTERFACE; AddRef(); return S_OK;}
ULONG STDMETHODCALLTYPE AddRef() {InterlockedIncrement(&gref); return InterlockedIncrement(&ref);}
ULONG STDMETHODCALLTYPE Release() {int tmp=InterlockedDecrement(&ref); if (tmp==0) delete this; InterlockedDecrement(&gref); return tmp;}
// IDispatch...
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR* pctinfo) {*pctinfo=1; return NOERROR;}
HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo) {return NOERROR;}
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId) {return NOERROR;}
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr)
{
// DISPID_DOCUMENTCOMPLETE: This is the earliest point we can obtain the "document" interface
if (dispIdMember==DISPID_DOCUMENTCOMPLETE)
{ if (!webBrowser) return E_FAIL;
IDispatch *idisp; webBrowser->get_Document(&idisp);
if (idisp && !doc) idisp->QueryInterface(IID_IHTMLDocument, (void**)&doc);
if (idisp && !doc2) idisp->QueryInterface(IID_IHTMLDocument2, (void**)&doc2);
if (doc2 && !win2) doc2->get_parentWindow(&win2);
IConnectionPointContainer *cpc=0; if (doc) doc->QueryInterface(IID_IConnectionPointContainer, (void**) &cpc);
IConnectionPoint* cp=0; if (cpc) cpc->FindConnectionPoint(DIID_HTMLDocumentEvents2, &cp);
DWORD cookie; HRESULT hr; if (cp) hr=cp->Advise(static_cast<IDispatch*>(this), &cookie);
if (cp) cp->Release(); if (cpc) cpc->Release(); if (idisp) idisp->Release();
if (!doc || !doc2 || !win2 || hr!=S_OK) {release(); return E_FAIL;}
return NOERROR;
}
if (dispIdMember==DISPID_HTMLDOCUMENTEVENTS_ONCLICK)
{ // This shows how to respond to simple events.
MessageBox(0,_T("Try pressing some keys on the keyboard!"),_T("BHO"),MB_OK);
return NOERROR;
}
if (dispIdMember==DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN)
{ // This shows how to examine the "event object" of an event
IDispatch *param1=0; if (pDispParams->cArgs==1 && (pDispParams->rgvarg)[0].vt==VT_DISPATCH) param1=(pDispParams->rgvarg)[0].pdispVal;
IHTMLEventObj *pEvtObj=0; if (param1) param1->QueryInterface(IID_IHTMLEventObj, (void**)&pEvtObj);
long keycode; HRESULT hr; if (pEvtObj) hr=pEvtObj->get_keyCode(&keycode);
if (pEvtObj) pEvtObj->Release();
if (!pEvtObj || hr!=S_OK) return E_FAIL;
// This shows how to manipulate the CSS style of an element
int i=keycode-32; if (i<0) i=0; if (i>63) i=63; i*=4;
wchar_t buf[100]; wsprintfW(buf,L"rgb(%i,%i,%i)",i,255-i,i/2);
IHTMLElement *body=0; doc2->get_body(&body);
IHTMLStyle *style=0; if (body) body->get_style(&style);
VARIANT v; v.vt=VT_BSTR; v.bstrVal=buf;
if (style) style->put_backgroundColor(v);
if (style) style->Release(); if (body) body->Release();
if (!body || !style) return E_FAIL;
return NOERROR;
}
return NOERROR;
}
// IObjectWithSite...
HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void** ppvSite) {return E_NOINTERFACE;}
HRESULT STDMETHODCALLTYPE SetSite(IUnknown* iunk)
{ // This is called by IE to plug us into the current web window
release();
iunk->QueryInterface(IID_IWebBrowser2, (void**)&webBrowser);
IConnectionPointContainer *cpc=0; iunk->QueryInterface(IID_IConnectionPointContainer, (void**)&cpc);
IConnectionPoint* cp=0; if (cpc) cpc->FindConnectionPoint(DIID_DWebBrowserEvents2, &cp);
DWORD cookie; HRESULT hr; if (cp) hr=cp->Advise(static_cast<IDispatch*>(this), &cookie);
if (!webBrowser || !cpc || !cp || hr!=S_OK) {if (cp) cp->Release(); if (cpc) cpc->Release(); release(); return E_FAIL;}
return S_OK;
}
// BHO...
BHO() : ref(0), webBrowser(0), doc(0), doc2(0), win2(0) {};
~BHO() {release();}
void release() {if (webBrowser) webBrowser->Release(); webBrowser=0; if (doc) doc->Release(); doc=0; if (doc2) doc2->Release(); doc2=0; if (win2) win2->Release(); win2=0;}
};
class MyClassFactory : public IClassFactory
{ long ref;
public:
// IUnknown... (nb. this class is instantiated statically, which is why Release() doesn't delete it.)
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) {if (riid==IID_IUnknown || riid==IID_IClassFactory) {*ppv=this; AddRef(); return S_OK;} else return E_NOINTERFACE;}
ULONG STDMETHODCALLTYPE AddRef() {InterlockedIncrement(&gref); return InterlockedIncrement(&ref);}
ULONG STDMETHODCALLTYPE Release() {int tmp = InterlockedDecrement(&ref); InterlockedDecrement(&gref); return tmp;}
// IClassFactory...
HRESULT STDMETHODCALLTYPE LockServer(BOOL b) {if (b) InterlockedIncrement(&gref); else InterlockedDecrement(&gref); return S_OK;}
HRESULT STDMETHODCALLTYPE CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) {*ppvObj = NULL; if (pUnkOuter) return CLASS_E_NOAGGREGATION; BHO *bho=new BHO(); bho->AddRef(); HRESULT hr=bho->QueryInterface(riid, ppvObj); bho->Release(); return hr;}
// MyClassFactory...
MyClassFactory() : ref(0) {}
};
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
{ static MyClassFactory factory; *ppvOut = NULL;
if (rclsid==BhoCLSID) {return factory.QueryInterface(riid,ppvOut);}
else return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow(void)
{ return (gref>0)?S_FALSE:S_OK;
}
STDAPI DllRegisterServer(void)
{ TCHAR fn[MAX_PATH]; GetModuleFileName(hInstance,fn,MAX_PATH);
SHSetValue(HKEY_CLASSES_ROOT,_T("CLSID\\")BhoCLSIDs,_T(""),REG_SZ,_T("BHO"),4*sizeof(TCHAR));
SHSetValue(HKEY_CLASSES_ROOT,_T("CLSID\\")BhoCLSIDs _T("\\InProcServer32"),_T(""),REG_SZ,fn,((int)_tcslen(fn)+1)*sizeof(TCHAR));
SHSetValue(HKEY_CLASSES_ROOT,_T("CLSID\\")BhoCLSIDs _T("\\InProcServer32"),_T("ThreadingModel"),REG_SZ,_T("Apartment"),10*sizeof(TCHAR));
SHSetValue(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\\")BhoCLSIDs,_T(""),REG_SZ,_T(""),sizeof(TCHAR));
return S_OK;
}
STDAPI DllUnregisterServer()
{ SHDeleteKey(HKEY_CLASSES_ROOT,_T("CLSID\\") BhoCLSIDs);
SHDeleteKey(HKEY_LOCAL_MACHINE,_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\\")BhoCLSIDs);
return S_OK;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{ if (fdwReason==DLL_PROCESS_ATTACH) hInstance=hinstDLL;
return TRUE;
}
Full source code is available for download here:
http://www.wischik.com/lu/programmer/bho.html
Related
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
I have problem with IWMPEvents, which I advised successfully but never raised. Here is how I create embeded Windows Media Player:
HRESULT MyWMP::setURL(wchar_t* url)
{
return pMediaPlayer->put_URL(url); // Load and play songs successfully;
}
bool MyWMP::CreatePlayer()
{
HRESULT hr;
const CLSID CLSID_WindowsMediaPlayer = { 0x6BF52A52, 0x394A, 0x11d3,{ 0xB1, 0x53, 0x00, 0xC0, 0x4F, 0x79, 0xFA, 0xA6 } };
hr = ::OleCreate(CLSID_WindowsMediaPlayer, IID_IOleObject, OLERENDER_DRAW, 0, this, this, (void**)&oleObject);
if (SUCCEEDED(hr) && oleObject)
{
if (SUCCEEDED(hr)) hr = oleObject->SetClientSite(this);
if (SUCCEEDED(hr)) hr = OleSetContainedObject(oleObject, TRUE);
if (SUCCEEDED(hr))
{
RECT posRect;
::SetRect(&posRect, -300, -300, 300, 300);
hr = oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, -1, this->hwnd, &posRect);
}
hr = oleObject->QueryInterface(&pMediaPlayer);
}
if (FAILED(hr) || !pMediaPlayer)
{
MessageBox(NULL, L"Create Browser failed!", L"Error", MB_ICONERROR);
return false;
}
return true;
}
MyWMP::MyWMP(HWND parentHWND, HINSTANCE hInstance) :
isFullyCreated(false)
{
OleInitialize(NULL);
HRESULT hr = E_FAIL;
IConnectionPointContainer* container = nullptr;
IUnknown* punk = nullptr;
this->parentHWND = parentHWND;
this->hwnd = CreateWindow(L"Static", NULL, WS_CHILD | WS_VISIBLE, 221, 0, 300, 300, parentHWND, NULL, hInstance, 0);
iComRefCount = 0;
::SetRect(&rObject, 0, 0, 300, 300);
if (CreatePlayer())
{
hr = pMediaPlayer->get_settings(&pMediaPlayerSettings);
if (SUCCEEDED(hr) && pMediaPlayerSettings)
{
pMediaPlayerSettings->put_autoStart(VARIANT_TRUE);
pMediaPlayerSettings->put_volume(100);
}
hr = pMediaPlayer->QueryInterface(IID_IConnectionPointContainer, (void**)&container);
if (SUCCEEDED(hr) && container) hr = container->FindConnectionPoint(__uuidof(IWMPEvents), &callback);
if (FAILED(hr) && container)
{
hr = container->FindConnectionPoint(__uuidof(_WMPOCXEvents), &callback);
}
if (SUCCEEDED(hr) && callback)
{
CWMPEventDispatch *cw = new CWMPEventDispatch();
IUnknown *cwUnk = NULL;
if (SUCCEEDED(cw->QueryInterface(IID_IUnknown, (void**)&cwUnk)))
{
if (SUCCEEDED(hr) && container)
{
hr = callback->Advise(cwUnk, &eventCookie);
if (SUCCEEDED(hr) && eventCookie)
{
isFullyCreated = true; // Set breakpoint here and is triggered
// by debugger
// hr = S_OK
}
}
}
if (cwUnk) cwUnk->Release();
}
if (punk) punk->Release();
if (container) container->Release();
}
}
Bellow is the CWMPEventDispatch class. I set breakpoint at all IDispatch functions and none of them get triggered by debugger. When I load new songs, play/pause (on the embeded UI control buttons), these functions is never called.
// CWMPEventDispatch.h : Declaration of the event dispatcher
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#include "stdafx.h"
#include "wmpids.h"
#include "wmp.h"
class CWMPEventDispatch :
public IWMPEvents,
public _WMPOCXEvents
{
public:
// ----- IUnknown -----
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void**ppvObject) override;
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
// IDispatch methods
STDMETHOD(GetIDsOfNames)(REFIID /*riid*/,
__in_ecount(cNames) LPOLESTR FAR * /*rgszNames*/,
unsigned int /*cNames*/,
LCID /*lcid*/,
DISPID FAR * /*rgDispId*/)
{
return(E_NOTIMPL);
}
STDMETHOD(GetTypeInfo)(unsigned int /*iTInfo*/,
LCID /*lcid*/,
ITypeInfo FAR *FAR * /*ppTInfo*/)
{
return(E_NOTIMPL);
}
STDMETHOD(GetTypeInfoCount)(unsigned int FAR * /*pctinfo*/)
{
return(E_NOTIMPL);
}
STDMETHOD(Invoke)(DISPID dispIdMember,
REFIID /*riid*/,
LCID /*lcid*/,
WORD /*wFlags*/,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* /*pVarResult*/,
EXCEPINFO FAR* /*pExcepInfo*/,
unsigned int FAR* /*puArgErr*/);
private:
int iComRefCount;
};
#include "stdafx.h"
#include "myWMPEventDispatch.h"
#pragma region ----- IUnknown -----
ULONG STDMETHODCALLTYPE CWMPEventDispatch::AddRef(void) { return ++iComRefCount; }
ULONG STDMETHODCALLTYPE CWMPEventDispatch::Release(void) { return --iComRefCount; }
HRESULT STDMETHODCALLTYPE CWMPEventDispatch::QueryInterface(REFIID riid, void**ppvObject)
{
if (riid == __uuidof(IUnknown)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IDispatch)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IWMPEvents)) *ppvObject = static_cast<IWMPEvents*>(this);
else if (riid == __uuidof(_WMPOCXEvents)) *ppvObject = static_cast<_WMPOCXEvents*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
#pragma endregion
HRESULT CWMPEventDispatch::Invoke(
DISPID dispIdMember,
REFIID /*riid*/,
LCID /*lcid*/,
WORD /*wFlags*/,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* /*pVarResult*/,
EXCEPINFO FAR* /*pExcepInfo*/,
unsigned int FAR* /*puArgErr*/)
{
if (!pDispParams)
return E_POINTER;
if (pDispParams->cNamedArgs != 0)
return DISP_E_NONAMEDARGS;
HRESULT hr = DISP_E_MEMBERNOTFOUND;
return(hr);
}
Question:
Why my IWMPEvents functions are never called, and how to fix it?
I attack full source code as a 7z archive. You can download it here.
Environment: Win 10 x64, VS 2017 Community
This piece of code:
if (SUCCEEDED(hr) && container) hr = container->FindConnectionPoint(__uuidof(IWMPEvents), &callback);
if (FAILED(hr) && container)
{
hr = container->FindConnectionPoint(__uuidof(_WMPOCXEvents), &callback);
}
Will succeed on the first line, so you will hook events on the IWMPEvents only, you will not continue and hook _WMPOCXEvents.
IWMPEvents are early-bound (IUnknown derived) events, so the Media Player will indeed call IWMPEvents::PlayStateChange(...) IWMPEvents::StatusChange(...) etc. but it won't call IDispatch::Invoke with corresponding DISPIDs.
If you want IDispatch events, just remove the first FindConnectionPoint, or call both.
I'm trying hook custom Credentential Provider UI, based on ICredentialProvider interface.
Using this guide(Vtable Patching) , i'm succesufly hook COM interface.
But trouble with hooking GetCredentenialAt method, i'm set vtable index equal to 10, and try relogin.
LogonUI screen blinking on :Ctrl+Alt+Del Screen:.
my source code:
#include "stdafx.h"
#include "VtableHooks.h"
#include "credentialprovider.h"
namespace Hook
{
STDMETHODIMP GetCredentialAt(IUnknown* This, DWORD dwIndex, ICredentialProviderCredential** ppcpc);
STDMETHODIMP QueryInterface(IUnknown* This, REFIID riid, void **ppvObject);
}
struct Context
{
Context(): m_Name("Hooked object"){}
PVOID m_OriginalQueryInterface;
PVOID m_OriginalGetCredentialAt;
ATL::CComBSTR m_Name;
};
std::auto_ptr<Context> g_Context;
HRESULT HookMethod(IUnknown* original, PVOID proxyMethod, PVOID* originalMethod, DWORD vtableOffset)
{ PVOID* originalVtable = *(PVOID**)original;
if (originalVtable[vtableOffset] == proxyMethod)
return S_OK;
*originalMethod = originalVtable[vtableOffset];
originalVtable[vtableOffset] = proxyMethod;
return S_OK;
}
HRESULT InstallComInterfaceHooks(IUnknown* originalInterface, REFIID riid)
{
HRESULT hr = S_OK;
if (riid == IID_ICredentialProvider)
{
// Only single instance of a target object is supported in the sample
if (g_Context.get())return E_FAIL;
ATL::CComPtr<ICredentialProvider> so;
HRESULT hr = originalInterface->QueryInterface(IID_ICredentialProvider, (void**)&so);
if (FAILED(hr)) return hr; // we need this interface to be present
// remove protection from the vtable
DWORD dwOld = 0;
if (!::VirtualProtect(*(PVOID**)(originalInterface), sizeof(LONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld))
return E_FAIL;
// hook interface methods
g_Context.reset(new Context);
HookMethod(so, (PVOID)Hook::QueryInterface, &g_Context->m_OriginalQueryInterface, 0);
HookMethod(so, (PVOID)Hook::GetCredentialAt, &g_Context->m_OriginalGetCredentialAt, 10);
}
return hr;
}
typedef HRESULT (WINAPI *QueryInterface_T)(IUnknown* This, REFIID riid, void **ppvObject);
STDMETHODIMP Hook::QueryInterface(IUnknown* This, REFIID riid, void **ppvObject)
{
QueryInterface_T qi = (QueryInterface_T)g_Context->m_OriginalQueryInterface;
HRESULT hr = qi(This, riid, ppvObject);
return hr;
}
typedef HRESULT(WINAPI *GetCredentialAt_T)(IUnknown* This, DWORD dwIndex, ICredentialProviderCredential** ppcpc);
STDMETHODIMP Hook::GetCredentialAt(IUnknown* This, DWORD dwIndex, ICredentialProviderCredential** ppcpc)
{
GetCredentialAt_T qi = (GetCredentialAt_T)g_Context->m_OriginalGetCredentialAt;
HRESULT hr = qi(This, dwIndex, ppcpc);
return hr;
}
Using IDA, i'm showing load 3rd custom dll. This Dll break interface.
I am tying to implement Microsoft's COM objects DDiscMaster2Events on mingw to get disk drive change events. I have not been able to find any examples of this. I already got DDiskFormat2DataEvents to work so I expect it to be similar to that. In DDiskFormat2DataEvents I had to connect my DDiskFormat2DataEvents with a IDiskFormat2Data to get the events. This is normally done with the AfxConnectionAdvise method. What com object do I need to connect my DDiscMaster2Events events sink to, to receive disk change events? A Visual Studio c++ example should answer my question. Thanks
There is some information about how to receive COM events in this article COM Connection Points by Thottam R. Sriram.
Based on its contents, somethink like this might work for you:
#include <imapi2.h>
#include <iostream>
#include <cassert>
class DiscMaster2EventsSink : public DDiscMaster2Events {
public:
STDMETHOD(NotifyDeviceAdded)(IDispatch *object, BSTR uniqueId)
{
std::cout << "NotifyDeviceAdded(...)\n";
return S_OK;
}
STDMETHOD(NotifyDeviceRemoved)(IDispatch *object, BSTR uniqueId)
{
std::cout << "NotifyDeviceRemoved(...)\n";
return S_OK;
}
public:
// The uninteresting stuff follows...
DiscMaster2EventsSink()
: m_refCount(1)
{
}
STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
{
*ppv = NULL;
if (riid == IID_IUnknown)
*ppv = static_cast<void*>(static_cast<IUnknown*>(this));
else if (riid == IID_IDispatch)
*ppv = static_cast<void*>(static_cast<IDispatch*>(this));
else if (riid == __uuidof(DDiscMaster2Events))
*ppv = static_cast<void*>(static_cast<DDiscMaster2Events*>(this));
if (*ppv) {
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)()
{
return InterlockedIncrement(&m_refCount);
}
STDMETHOD_(ULONG, Release)()
{
ULONG result = InterlockedDecrement(&m_refCount);
if (result == 0)
delete this;
return result;
}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
return E_NOTIMPL;
}
STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetTypeInfoCount)(UINT *pctinfo)
{
*pctinfo = 0;
return S_OK;
}
STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
return E_NOTIMPL;
}
private:
ULONG m_refCount;
};
int main()
{
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
assert(SUCCEEDED(hr));
IDiscMaster2* pDiscMaster2;
hr = CoCreateInstance(__uuidof(MsftDiscMaster2), NULL, CLSCTX_ALL, __uuidof(IDiscMaster2), (void**)&pDiscMaster2);
assert(SUCCEEDED(hr));
IConnectionPointContainer* pCPC;
hr = pDiscMaster2->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);
assert(SUCCEEDED(hr));
IConnectionPoint* pCP;
hr = pCPC->FindConnectionPoint(IID_DDiscMaster2Events, &pCP);
assert(SUCCEEDED(hr));
DiscMaster2EventsSink* pSink = new DiscMaster2EventsSink();
IUnknown* pSinkUnk;
hr = pSink->QueryInterface(IID_IUnknown, (void**)&pSinkUnk);
assert(SUCCEEDED(hr));
DWORD dwAdvise;
hr = pCP->Advise(pSinkUnk, &dwAdvise);
assert(SUCCEEDED(hr));
std::cout << "OK...\n";
std::cin.get();
pSinkUnk->Release();
pSink->Release();
pCP->Release();
pCPC->Release();
pDiscMaster2->Release();
CoUninitialize();
return 0;
}
It compiles and runs fine for me as far as I can see (S_OK all the way), but I cannot see any events - possibly because I doesn't have an external optical drive to mess with to create any device add/remove events.
(Also obviously with some C++ COM helper class it would be much nicer.)
Hopefully it might still help you, perhaps with a few changes even under MinGW.
What I want to do:
Write an application that listens to Office events. I want to listen to events from any instance opened on the machine. E.g. if I'm listening to BeforeDocumentSave in Word, then I want my sink for this method to be activated whenever any instance of Word on the host saves a document.
Another requirement is that I'm writing in C++ without MFC or ATL.
What I've done:
I've written a program that's supposed to listen to Word events. See the code below.
The problem:
It doesn't work - the event handlers are never entered, although I open a word application and do the actions that should trigger the events.
I have some specific questions, and of course any other input would be very welcome!
Questions:
Is it possible to listen to events from an application that wasn't started by me? In all the examples I found, the listening application starts the office application it wants to listen to.
In a microsoft howto (http://support.microsoft.com/kb/183599/EN-US/) I found the following comment:
However, most events, such as
Microsoft Excel's Workbook events, do
not start with DISPID 1. In such
cases, you must explicitly modify the
dispatch map in MyEventSink.cpp to
match the DISPIDs with the correct
methods.
How do I modify the dispatch map?
For now I've defined only Startup, Quit and DocumentChange, which take no arguments. The methods I really need do take arguments, specifically one of type Document. How do I define parameters of this type if I'm not using MFC?
Code:
Here's the header file for my project, followed by the C file:
#ifndef _OFFICEEVENTHANDLER_H_
#define _OFFICEEVENTHANDLER_H_
// 000209FE-0000-0000-C000-000000000046
static const GUID IID_IApplicationEvents2 =
{0x000209FE,0x0000,0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
struct IApplicationEvents2 : public IDispatch // Pretty much copied from typelib
{
/*
* IDispatch methods
*/
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj) = 0;
STDMETHODIMP_(ULONG) AddRef() = 0;
STDMETHODIMP_(ULONG) Release() = 0;
STDMETHODIMP GetTypeInfoCount(UINT *iTInfo) = 0;
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) = 0;
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId) = 0;
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams,
VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
UINT* puArgErr) = 0;
/*
* IApplicationEvents2 methods
*/
STDMETHODIMP Startup();
STDMETHODIMP Quit();
STDMETHODIMP DocumentChange();
};
class COfficeEventHandler : IApplicationEvents2
{
public:
DWORD m_dwEventCookie;
COfficeEventHandler
(
) :
m_cRef(1),
m_dwEventCookie(0)
{
}
STDMETHOD_(ULONG, AddRef)()
{
InterlockedIncrement(&m_cRef);
return m_cRef;
}
STDMETHOD_(ULONG, Release)()
{
InterlockedDecrement(&m_cRef);
if (m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj)
{
if (riid == IID_IUnknown){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else if (riid == IID_IApplicationEvents2){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else if (riid == IID_IDispatch){
*ppvObj = static_cast<IApplicationEvents2*>(this);
}
else
{
char clsidStr[256];
WCHAR wClsidStr[256];
char txt[512];
StringFromGUID2(riid, (LPOLESTR)&wClsidStr, 256);
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, wClsidStr, -1, clsidStr, 256, NULL, NULL);
sprintf_s(txt, 512, "riid is : %s: Unsupported Interface", clsidStr);
*ppvObj = NULL;
return E_NOINTERFACE;
}
static_cast<IUnknown*>(*ppvObj)->AddRef();
return S_OK;
}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
return E_NOTIMPL;
}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
return E_NOTIMPL;
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return E_NOTIMPL;
}
// IApplicationEvents2 methods
void Startup();
void Quit();
void DocumentChange();
protected:
LONG m_cRef;
};
#endif // _OFFICEEVENTHANDLER_H_
The C file:
#include <windows.h>
#include <stdio.h>
#include "OfficeEventHandler.h"
#include "OCIdl.h"
int main()
{
CLSID clsid; // CLSID of automation object
HRESULT hr;
LPUNKNOWN punk = NULL; // IUnknown of automation object
LPDISPATCH pdisp = NULL; // IDispatch of automation object
IConnectionPointContainer *pConnPntCont;
IConnectionPoint *pConnPoint;
IUnknown *iu;
IID id;
COfficeEventHandler *officeEventHandler = new COfficeEventHandler;
CoInitialize(NULL);
hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid);
hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,
IID_IUnknown, (void FAR* FAR*)&punk);
hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont);
// IID for ApplicationEvents2
hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}",&id);
hr = pConnPntCont->FindConnectionPoint( id, &pConnPoint );
hr = officeEventHandler->QueryInterface( IID_IUnknown, (void FAR* FAR*)&iu);
hr = pConnPoint->Advise( iu, &officeEventHandler->m_dwEventCookie );
Sleep( 360000 );
hr = pConnPoint->Unadvise( officeEventHandler->m_dwEventCookie );
if (punk) punk->Release();
if (pdisp) pdisp->Release();
CoUninitialize();
return hr;
}
// IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
printf( "In Startup\n" );
}
void COfficeEventHandler::Quit()
{
printf( "In Quit\n" );
}
void COfficeEventHandler::DocumentChange()
{
printf( "In DocumentChnage\n" );
}
Your number one problem is you don't run the message loop in the main thread and that causes the events to never reach your sink object. Calls form the COM server to your sink object are dispatched using Windows messages, so you have to run the message loop instead of simply calling Sleep() so that the incoming events are eventually dispatched to the sink object.
I found two problems in the code I gave here:
As sharptooth pointed out, Sleep is wrong here. It even causes the application I listen to to hang, or sleep. I put in a message loop as sharptooth suggested.
I hadn't implemented 'Invoke'. I thought that if I implemented the event methods themselves, they would be called by the application, but this is not the case. I had to implement invoke and make it switch on the dispid and call the different event methods. I found the dispid in the typelib. Looking at a method in the OLE viewer, I used the 'id' which apparently is the dispid.
Following is a corrected .cpp file. In the .h file the only correction is to change Invoke into a declaration instead of an implementation.
Two notes on the code:
I constructed it out of various examples I found, so you may find names or comments that seem irrelevant because they were taken from elsewhere.
To get the COM object I used either GetActiveObject or CoCreateInstance. The former works only if the event firing application is already running. The latter creates an invisible instance of it. For Word this worked well, possibly because if I open another Word instance its part of the same process. I haven't checked yet what happens if I open a new process, if the events would still be triggered.
Hope this helps!
#include <windows.h>
#include <stdio.h>
#include "OfficeEventHandler.h"
#include "OCIdl.h"
int main()
{
CLSID clsid; // CLSID of automation object
HRESULT hr;
LPUNKNOWN punk = NULL; // IUnknown of automation object
LPDISPATCH pdisp = NULL; // IDispatch of automation object
IConnectionPointContainer *pConnPntCont;
IConnectionPoint *pConnPoint;
IUnknown *iu;
IID id;
COfficeEventHandler *officeEventHandler = new COfficeEventHandler;
CoInitialize(NULL);
hr = CLSIDFromProgID(OLESTR("Word.Application"), &clsid);
/* hr = GetActiveObject( clsid, NULL, &punk );
*/ hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,
IID_IUnknown, (void FAR* FAR*)&punk);
hr = punk->QueryInterface(IID_IConnectionPointContainer, (void FAR* FAR*)&pConnPntCont);
// IID for ApplicationEvents2
hr = IIDFromString(L"{000209FE-0000-0000-C000-000000000046}",&id);
hr = pConnPntCont->FindConnectionPoint( id, &pConnPoint );
hr = officeEventHandler->QueryInterface( IID_IUnknown, (void FAR* FAR*)&iu);
hr = pConnPoint->Advise( iu, &officeEventHandler->m_dwEventCookie );
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 )
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if( msg.message == WM_QUERYENDSESSION || msg.message == WM_QUIT || msg.message == WM_DESTROY )
{
break;
}
}
hr = pConnPoint->Unadvise( officeEventHandler->m_dwEventCookie );
if (punk) punk->Release();
if (pdisp) pdisp->Release();
CoUninitialize();
return hr;
}
// IApplicationEvents2 methods
void COfficeEventHandler::Startup()
{
printf( "In Startup\n" );
}
void COfficeEventHandler::Quit()
{
printf( "In Quit\n" );
}
void COfficeEventHandler::DocumentChange()
{
printf( "In DocumentChnage\n" );
}
STDMETHODIMP COfficeEventHandler::Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
//Validate arguments
if ((riid != IID_NULL))
return E_INVALIDARG;
HRESULT hr = S_OK; // Initialize
/* To see what Word sends as dispid values */
static char myBuf[80];
memset( &myBuf, '\0', 80 );
sprintf_s( (char*)&myBuf, 80, " Dispid: %d :", dispIdMember );
switch(dispIdMember){
case 0x01: // Startup
Startup();
break;
case 0x02: // Quit
Quit();
break;
case 0x03: // DocumentChange
DocumentChange();
break;
}
return S_OK;
}