Why my IWMPEvents functions are never called? - c++

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.

Related

using GetEditBoxText in IFileSaveDialog

The folowing code is a part of my application.
I want to get a value from file save dialog using a editbox.
So i use AddEditBox function and GetEditBoxText to return value.
I enter "2000.0" in the editbox but the rturn value is Empty.
what is the problem?
wstring GetSaveFileForMakeDif(double & MinDistance) {
const DWORD CONTROL_GROUP = 5001;
const DWORD CONTROL_LABEL = 5002;
const DWORD CONTROL_EDITBOX_MINDIST = 5003;
wstring ret(L"");
HRESULT hr = S_FALSE;
IFileDialogCustomize *pfdc = NULL;
// Create a new common open file dialog.
IFileSaveDialog *pfd = NULL;
hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
// Set the title of the dialog.
if (SUCCEEDED(hr)) {
hr = pfd->SetTitle(L"Select Files");
hr = pfd->SetFileName(L"outputfile");
hr = pfd->SetDefaultExtension(L"txt");
}
// Set up the customization.
hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
if (SUCCEEDED(hr))
{
hr = pfdc->StartVisualGroup(CONTROL_GROUP, L"");
if (SUCCEEDED(hr))
hr = pfdc->AddText(CONTROL_LABEL, L"Min Distance:");
if (SUCCEEDED(hr))
hr = pfdc->AddEditBox(CONTROL_EDITBOX_MINDIST, L"2000.0");
pfdc->EndVisualGroup();
}
// Show the open file dialog.
if (SUCCEEDED(hr))
{
hr = pfd->Show(hMainWindow);
if (SUCCEEDED(hr))
{
IShellItem *psi = NULL;
hr = pfd->GetResult(&psi);
wchar_t *pszPath = new wchar_t[MAX_PATH];
psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr))
{
ret = pszPath;
wchar_t * txt = NULL;
hr = pfdc->GetEditBoxText(CONTROL_EDITBOX_MINDIST, &txt);
//txt return L""
MinDistance = _wtof(txt);
}
}
}
pfd->Release();
}
pfdc->Release();
return ret;
};
Event handling is needed to catch the values before the dialog closes.
There is a complete MSDN example available here:
Common File Dialog Sample
At the moment the download link does not seem to be available. The example below shows how to catch the event in OnFileOk
Note that you need CoTaskMemFree to release memory which had been allocated by GetEditBoxText
#include <windows.h>
#include <shobjidl.h>
#include <shlwapi.h>
#include <new>
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "Shlwapi.lib")
// Controls
#define CONTROL_GROUP 2000
#define CONTROL_LABEL 5002
#define CONTROL_EDITBOX_MINDIST 5003
class CDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents
{
public:
// IUnknown methods
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) {
static const QITAB qit[] = {
QITABENT(CDialogEventHandler, IFileDialogEvents),
QITABENT(CDialogEventHandler, IFileDialogControlEvents),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
IFACEMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&_cRef);
}
IFACEMETHODIMP_(ULONG) Release() {
long cRef = InterlockedDecrement(&_cRef);
if (!cRef)
delete this;
return cRef;
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog *pfd);
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) { return S_OK; };
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnSelectionChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
IFACEMETHODIMP OnTypeChange(IFileDialog *) { return S_OK; };
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
// IFileDialogControlEvents methods
IFACEMETHODIMP OnItemSelected(IFileDialogCustomize *, DWORD, DWORD) { return S_OK; };
IFACEMETHODIMP OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
IFACEMETHODIMP OnCheckButtonToggled(IFileDialogCustomize *, DWORD, BOOL) { return S_OK; };
IFACEMETHODIMP OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
CDialogEventHandler() : _cRef(1) { };
private:
~CDialogEventHandler() { };
long _cRef;
};
// Instance creation helper
HRESULT CDialogEventHandler_CreateInstance(REFIID riid, void **ppv)
{
*ppv = NULL;
CDialogEventHandler *pDialogEventHandler = new (std::nothrow) CDialogEventHandler();
HRESULT hr = pDialogEventHandler ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
hr = pDialogEventHandler->QueryInterface(riid, ppv);
pDialogEventHandler->Release();
}
return hr;
}
//EDIT BEGIN ***************************
// IFileDialogEvents methods
IFACEMETHODIMP CDialogEventHandler::OnFileOk(IFileDialog *fileDialog)
{
IFileDialogCustomize *fileCustomize = NULL;
fileDialog->QueryInterface(IID_PPV_ARGS(&fileCustomize));
wchar_t *buf;
fileCustomize->GetEditBoxText(IDC_EDTI1, &buf);
MessageBox(0, buf, 0, 0);
CoTaskMemFree(buf);
fileCustomize->Release();
return S_OK;
}
//EDIT END *****************************
// This code snippet demonstrates how to add custom controls in the Common File Dialog.
HRESULT AddCustomControls()
{
// CoCreate the File Open Dialog object.
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents *pfde = NULL;
DWORD dwCookie = 0;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set up a Customization.
IFileDialogCustomize *pfdc = NULL;
if (SUCCEEDED(pfd->QueryInterface(IID_PPV_ARGS(&pfdc))))
{
pfdc->StartVisualGroup(CONTROL_GROUP, L"");
pfdc->AddText(CONTROL_LABEL, L"Min Distance:");
pfdc->AddEditBox(CONTROL_EDITBOX_MINDIST, L"2000.0");
pfdc->EndVisualGroup();
pfdc->Release();
}
else
{
// Unadvise here in case we encounter failures before we get a chance to show the dialog.
pfd->Unadvise(dwCookie);
}
}
pfde->Release();
}
if (SUCCEEDED(hr))
{
// Now show the dialog.
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// You can add your own code here to handle the results.
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfd->Release();
}
return hr;
}
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
AddCustomControls();
CoUninitialize();
return 0;
}

change LAN proxy

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

What to connect/link my DDiscMaster2Events to for drive change events. Microsoft COM objects

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.

C++ MFC create IShellItem from CLSID (GUID)

I have to create a ShellItem to Windows Help and Windows Run...
I have this
Help and Support {2559a1f1-21d7-11d4-bdaf-00c04f60b9f0}
Run {2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}
from http://www.sevenforums.com/tutorials/110919-clsid-key-list-windows-7-a.html
I've tried
IShellFolder* desk = NULL;
HRESULT hr =SHGetDesktopFolder(&desk);
LPITEMIDLIST pidl2=NULL;
ULONG cbEaten;
DWORD dwAttribs = 0 ;
hr = desk->ParseDisplayName(NULL,
NULL,
L"::{2559A1F1-21D7-11D4-BDAF-00C04F60B9F0}",
&cbEaten, // This can be NULL
&pidl2,
&dwAttribs);
It returns OK but Null as pidl2
could you guys give me some help?
ParseDisplayName should be able to parse it if you pass "shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}" but I guess that is not really what you want.
ParseDisplayName is able to parse some ::{clsid} paths but I think it is restricted to a very limited set of CSIDL_* special folders. SHSimpleIDListFromPath was able to parse it.
If you really want to parse it with ParseDisplayName you can try to emulate SHSimpleIDListFromPath:
class EmptyFileSystemBindData : public IFileSystemBindData {
public:
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_IUnknown || riid == IID_IFileSystemBindData) {
*ppv = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
*ppv = NULL; return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP SetFindData(const WIN32_FIND_DATAW *pfd)
{
return S_OK;
}
STDMETHODIMP GetFindData(WIN32_FIND_DATAW *pfd)
{
ZeroMemory(pfd,sizeof(WIN32_FIND_DATAW));
return S_OK;
}
};
LPITEMIDLIST pidl2=NULL;
HRESULT hr;
IShellFolder*psf;
IBindCtx*pbc;
hr = CreateBindCtx(0,&pbc);
EmptyFileSystemBindData efsbd;
if (SUCCEEDED(hr))
{
BIND_OPTS bo = {sizeof(bo)};
bo.grfMode = STGM_CREATE;
hr = pbc->RegisterObjectParam(STR_FILE_SYS_BIND_DATA,&efsbd);
if (SUCCEEDED(hr) && 0==pbc->SetBindOptions(&bo))
{
hr = SHGetDesktopFolder(&psf);
if (SUCCEEDED(hr))
{
hr = psf->ParseDisplayName(0,pbc,L"::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}",0,&pidl2,0);
if (SUCCEEDED(hr))
{
OutputDebugStringA("parsed ok\n");
ILFree(pidl2);
}
psf->Release();
}
}
pbc->Release();
}

How to listen to COM events from Office applications that were started independently?

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;
}