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;
}
Related
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.
In advance sorry for the TOO Long post, but given that there are many parts involved, and I am not sure where I can be making a mistake, hence, I need to post all the parts involved. Please do not assume anything, I can be making any type of error here.
Problem:
1) Real problem: Just learning COM.
2) I need to pass a IDispatch pointer from my console client (ConsoleClient) in C++ as parameter to a COM function in a Windows Service (WinService). This IDispatch pointer acts as callback. The WinService knows the name of the function to be called. All my attempts have been unsuccessulf. I am getting different errors like: No implemented, RPC is unavailable, etc..
NOTE: The following error is correct! I edited after #Igor pointed out my error: to have a do-while (which I removed from the main()) in a STA thread. I added a message pump (GetMessage, TranslateMessage and DispatchMessage) in the main() thread (instead of the do-while) and my problem was fixed!
I have a WinService exposing the following COM interface (WinService's idl file):
[
object,
uuid(DBE8BC31-9D2B-4F4B-903A-B40473408DE9),
dual,
nonextensible,
pointer_default(unique)
]
interface IWinService : IDispatch
{
///Here there are more functions..
[id(4), helpstring("Interface HELP")]
HRESULT WinServiceCOMfunction( [in] VARIANT vCallback, [out, retval] LONG* pReturn );
//Here there even more functions...
};
[
uuid(DEF3BFAE-ADF4-493B-8D01-E47A279225C5),
version(1.0),
helpstring("LIB HELP")
]
library WinServiceLib
{
importlib("stdole2.tlb");
[
uuid(AC290DC9-8CB4-4502-A73C-2BDAEC4B215A)
]
coclass CoWinService
{
[default] interface IWinService;
};
}
The WinService internally expects that vCallBack.vt = VT_DISPATCH, i.e., that is the callback pointer I need to pass in when I invoke the WinServiceCOMfunction from my ConsoleClient.EXE app. WinService knows the name of the function that acts as callback. I.e., WinService calls from the IDispatch-pointer-callback GetIDsOfName with "FunctionCallback" as parameter. However, here I am getting different errors in the WinService like: No implemented, RPC is unavailable, etc.. Then no callback is executed (the ConsoleClient does not receive anything back).
What I have done so far (all the following source code is found in the ConsoleClient.EXE)
ConsoleClient.EXE main.cpp:
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
//To be brief: Let's think that I already have an IDispatch pointer to the WinService interface IWinService:
CComPtr<IDispatch> pIWinService; //pIWinService
//Here I queried the IWinService interface...It was successful!!!
OLECHAR * winServiceNameFunction = L"WinServiceCOMfunction";
DISPID dispid;
hr = pIWinService->GetIDsOfNames( IID_NULL, &winServiceNameFunction, 1, LOCALE_USER_DEFAULT, &dispid );
if ( FAILED( hr ) )
{
wprintf( L"GetIDsOfNames failed" );
return 1;
}
else
{
wprintf( L"GetIDsOfNames succeeded!" );
}
CComPtr<IDispatch> consoleClientCallback( new CConsoleClientInterface() );
CConsoleClientInterface *sanity = dynamic_cast<CConsoleClientInterface *>( consoleClientCallback.p );
if ( nullptr == pAutoCallback )
{
wprintf( L"CConsoleClientInterface pointer failed\n" );
return 1;
}
else
{
wprintf( L"CConsoleClientInterface pointer succeeded\n" );
}
DWORD dwRegister;
hr = CoRegisterClassObject(CLSID_CoConsoleClient, consoleClientCallback.p,
CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister);
if(FAILED(hr))
{
wprintf(L"CoRegisterClassObject Failed\n");
return 1;
}
else
{
wprintf(L"CoRegisterClassObject Succeeded\n");
}
CComVariant paramCallback( consoleClientCallback.Detach() );
VARIANTARG varParams[] = { paramCallback };
DISPPARAMS dispparams = { vArgs, NULL, 1, 0 };
hr = pPtr->Invoke(
dispid,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&dispparams,
NULL,
NULL,
NULL);
if ( FAILED( hr ) )
{
wprintf( L"Invoke failed" );
return 1;
}
else
{
wprintf( L"Invoke Succeeded" );
}
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoRevokeClassObject(dwRegister);
CoUninitialize();
return 0;
}
All the main is succesfully executed. However, I never get anything from the callback. When the WinService tries to QueryInterface from teh IDispatch pointer callback, it throws erros like: No implemented, RPC is unavailable, among others...
Template class to create the ConsoleClient IDispatch interface
From: http://blogs.msdn.com/b/oldnewthing/archive/2013/06/12/10425215.aspx
disInterfaceBase.h:
template<typename DispInterface>
class CDispInterfaceBase : public DispInterface
{
public:
CDispInterfaceBase() : m_cRef(1), m_dwCookie(0) { }
/* IUnknown */
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
*ppv = nullptr;
HRESULT hr = E_NOINTERFACE;
if (riid == IID_IUnknown || riid == IID_IDispatch ||
riid == __uuidof(DispInterface))
{
*ppv = static_cast<DispInterface *>
(static_cast<IDispatch*>(this));
AddRef();
hr = S_OK;
}
return hr;
}
IFACEMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
IFACEMETHODIMP_(ULONG) Release()
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0) delete this;
return cRef;
}
// *** IDispatch ***
IFACEMETHODIMP GetTypeInfoCount(UINT *pctinfo)
{
*pctinfo = 0;
return E_NOTIMPL;
}
IFACEMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo)
{
*ppTInfo = nullptr;
return E_NOTIMPL;
}
IFACEMETHODIMP GetIDsOfNames(REFIID, LPOLESTR *rgszNames,
UINT cNames, LCID lcid,
DISPID *rgDispId)
{
return E_NOTIMPL;
}
IFACEMETHODIMP Invoke(
DISPID dispid, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS *pdispparams, VARIANT *pvarResult,
EXCEPINFO *pexcepinfo, UINT *puArgErr)
{
if (pvarResult) VariantInit(pvarResult);
return SimpleInvoke(dispid, pdispparams, pvarResult);
}
// Derived class must implement SimpleInvoke
virtual HRESULT SimpleInvoke(DISPID dispid,
DISPPARAMS *pdispparams, VARIANT *pvarResult) = 0;
public:
HRESULT Connect(IUnknown *punk)
{
HRESULT hr = S_OK;
CComPtr<IConnectionPointContainer> spcpc;
if (SUCCEEDED(hr)) {
hr = punk->QueryInterface(IID_PPV_ARGS(&spcpc));
}
if (SUCCEEDED(hr)) {
hr = spcpc->FindConnectionPoint(__uuidof(DispInterface), &m_spcp);
}
if (SUCCEEDED(hr)) {
hr = m_spcp->Advise(this, &m_dwCookie);
}
return hr;
}
void Disconnect()
{
if (m_dwCookie) {
m_spcp->Unadvise(m_dwCookie);
m_spcp.Release();
m_dwCookie = 0;
}
}
private:
LONG m_cRef;
CComPtr<IConnectionPoint> m_spcp;
DWORD m_dwCookie;
};
The actual IDispatch implementation in the ConsoleClient
ConsoleClient.h
class CConsoleClientInterface : public CDispInterfaceBase<ICONSOLEINTERFACE>
{
public:
CConsoleClientInterface() { }
~CConsoleClientInterface() { }
STDMETHODIMP GetIDsOfNames(REFIID, LPOLESTR *rgszNames,
UINT cNames, LCID lcid,
DISPID *rgDispId)
{
HRESULT hr = E_FAIL;
if(_wcsicmp(*rgszNames, L"FunctionCallback") == 0)
{
*rgDispId = 1;
hr= S_OK;
}
else
{
hr= DISP_E_UNKNOWNINTERFACE;
}
if(FAILED(hr))
{
std::cout << L"FAILED\n";
}
return hr;
}
HRESULT SimpleInvoke(
DISPID dispid, DISPPARAMS *pdispparams, VARIANT *pvarResult)
{
// switch (dispid)
// {
// case 4:
std::cout << L"SimpleInvoke" << std::endl; //This is never printed (for the error that I am trying to figure out)
HRESULT hr = FunctionCallback( pdispparams->rgvarg[1].intVal, pdispparams->rgvarg[0].parray );
// break;
// }
return hr;
}
HRESULT FunctionCallback( LONG longValue, LPSAFEARRAY safearray )
{
//So simple, I just want that this value is printed in the ConsoleClient's console! Unfortunately this is not happening!
std::cout << longValue << std::endl;
return S_OK;
}
};
And the ConsoleClient.idl
[
object,
uuid(CD08B160-558A-4251-885C-173A08A461F1),
dual,
nonextensible,
helpstring("ICONSOLEINTERFACE Interface"),
pointer_default(unique)
]
interface ICONSOLEINTERFACE : IDispatch{
[id(1), helpstring("method FunctionCallback")]
HRESULT FunctionCallback([in] LONG longValue, [in] LPSAFEARRAY safeArray );
};
[
uuid(F3445A9E-555B-4729-952B-8B72B8DB2E37),
version(1.0),
helpstring("ConsoleClientLib Help Lib")
]
library ConsoleClientLib
{
importlib("stdole2.tlb");
[
uuid(EFF9EC78-3031-4558-9BA3-5B2641CCB304),
helpstring("CoConsoleClient Class")
]
coclass ConsoleClientInterface
{
[default] interface ICONSOLEINTERFACE;
};
};
I have created:
HKEY_CLASSES_ROOT\CLSID\{EFF9EC78-3031-4558-9BA3-5B2641CCB304} //CLSID
(Default) REG_SZ = C:\Program Files\Common Files\ConsoleClient.EXE
HKEY_CLASSES_ROOT\CLSID\{EFF9EC78-3031-4558-9BA3-5B2641CCB304}\LocalServer32
ThreadingModel REG_SZ = Both
Also I have registered the tlb using regtlibv12.exe
Sorry for the TOO LONG post, but COM forces me to do this, in particular that I am new with COM and I do not know where I can be making a mistake.
NOTE: I am sure that the Invoke (from the ConsoleClient.EXE) to the WinService COM function (WinServiceCOMfunction) is successful (I debugged it and hits inside this function after the Invoke).
NOTE2: I am sure that the WinService using the callback works. There are other implementations (in different programming languages) making use of this mechanism via the same Function (WinServiceCOMfunction) in WinService.
Any help? Thanks in advance!
I have successfully compiled and registered a direct show filter. Now I want to use it in my code. But the call to COCreateInstance returns errorcode E_NOINTERFACE.
Here is the registration code of my filter
#include "MyFilter.h"
#include <aviriff.h>
static WCHAR g_wszName[] = L"MyFilter";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_MyFilter,
MyFilter::CreateInstance,
NULL,
NULL
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
// Declare media type information.
FOURCCMap fccMap = FCC('MRLE');
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };
// Declare pin information.
REGFILTERPINS sudPinReg[] = {
// Input pin.
{ TEXT("PinInput0"), FALSE, // Rendered?
FALSE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudInputTypes // Media types.
},
{ TEXT("PinInput1"), FALSE,
FALSE,
FALSE,
FALSE,
0, 0, 1, &sudInputTypes
},
{
TEXT("PinInput2"), FALSE,
FALSE,
FALSE,
FALSE,
0, 0, 1, &sudInputTypes
},
// Output pin.
{ 0, FALSE, // Rendered?
TRUE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudOutputTypes // Media types.
}
};
// Declare filter information.
REGFILTER2 rf2FilterReg = {
1, // Version number.
MERIT_DO_NOT_USE, // Merit.
4, // Number of pins.
sudPinReg // Pointer to pin information.
};
STDAPI DllRegisterServer(void)
{
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_MyFilter, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_VideoCompressorCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2FilterReg // Filter information.
);
pFM2->Release();
}
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_MyFilter);
pFM2->Release();
}
return hr;
}
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
And here the code that uses the filter
#include <DShow.h>
#include "MyFilter.h"
#include <streams.h>
IPin *GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir)
{
BOOL bFound = FALSE;
IEnumPins *pEnum;
IPin *pPin;
pFilter->EnumPins(&pEnum);
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
pPin->QueryDirection(&PinDirThis);
if (bFound = (PinDir == PinDirThis))
break;
pPin->Release();
}
pEnum->Release();
return (bFound ? pPin : 0);
}
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
CoInitialize(NULL);
IGraphBuilder* pGraph = NULL;
IMediaControl* pMediaControl = NULL;
IMediaEvent* pMediaEvent = NULL;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_ALL, IID_IFilterGraph, (void **) &pGraph);
if(hr < 0)
{
return -1;
}
IBaseFilter* pSource = NULL;
pGraph->QueryInterface(IID_IMediaControl, (void **) pMediaControl);
pGraph->QueryInterface(IID_IMediaEvent, (void **) pMediaEvent);
pGraph->AddSourceFilter(TEXT("C:\\TEMP\\video1.avi"), 0, &pSource);
IPin* pSourceOut = GetPin(pSource, PINDIR_OUTPUT);
IBaseFilter* pAVISplitter = NULL;
CoCreateInstance(CLSID_AviSplitter, NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pAVISplitter);
IPin* pAvIIn = GetPin(pAVISplitter, PINDIR_INPUT);
pGraph->AddFilter(pAVISplitter, L"Splitter");
pGraph->Connect(pSourceOut, pAvIIn);
IPin* pAVIOut = GetPin(pAVISplitter, PINDIR_OUTPUT);
MyFilter* myfilter;
hr = CoCreateInstance(CLSID_MyFilter, NULL, CLSCTX_INPROC_SERVER, IID_MyFilter, (void **)& myfilter);
if(hr < 0)
{
return -1;
}
IPin* myfilterIn = myfilter->GetPin(0);
IPin* myFilterOut = myfilter->GetPin(3);
pGraph->Connect(pAVIOut, myfilterIn);
pGraph->Render(myFilterOut);
CoUninitialize();
return 0;
}
Simply calls the base class:
STDMETHODIMP MyFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
Also note that I can import my filter in graphedit
MyFilter::NonDelegatingQueryInterface is where you should look at
Simply calls the base class:
Compare to EzRGB24 sample, which - similarly to yours - adds custom interface. You need to update your project respectively.
//
// NonDelegatingQueryInterface
//
// Reveals IIPEffect and ISpecifyPropertyPages
//
STDMETHODIMP CEZrgb24::NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
CheckPointer(ppv,E_POINTER);
if (riid == IID_IIPEffect) {
return GetInterface((IIPEffect *) this, ppv);
} else if (riid == IID_ISpecifyPropertyPages) {
return GetInterface((ISpecifyPropertyPages *) this, ppv);
} else {
return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
}
}
See this example Add Support for COM, when NonDelegatingQueryInterface requests IID_MyFilter, you have to return a pointer to that interface.
If your filter can be added in graphedit but not your application, maybe you have a 32/64 bit problem. The filter dll/ax needs to be compiled with the same bit width as your app, this applies to any dll not just Directshow.
Here's some other tips for Directshow programming in C++:
Use GraphStudioNext as you can compile it with debug symbols and 32/64 bit versions
Use ATL COM Smart Pointers to avoid memory leaks and messy code eg CComPtr pSmartFilter
CComPtr<IPin> myfilterIn;
myfilterIn.Attach(myfilter->GetPin(0));
// No need to Release myfilterIn as CComPtr will do it for you when it goes out of scope
I am stacking with this code for more that a week :)
I've changed the sample code included with Windows SDK (CWavSink) which is a custom wave sink to record a PCM data to wav file.
I've made some changes to use that sample as a video sink to record the video stream from a web cam on Windows 8.
I was managed to get the video frames from the IMFSample but the problems I have is:
When record the captured frames to test file then try to convert it to avi or any other format using ffmpeg the output has wrong colors and the video is not played OK.
What ever I set for the width and height I always get the frames as 320X240.
Sample buffer is always 600kb which contains 2 frames (I am setting it to get one frame as the sample size)
I've tried to change the format from RGB32 to H263 but it seems that the setting was ignored and I get RGB32 always.
I am appreciating any help on that
Here is my code
#include "pch.h"
#include "VideoSink.h"
#pragma warning( push )
#pragma warning( disable : 4355 ) // 'this' used in base member initializer list
using namespace VideoRecorder;
const DWORD VIDEO_SINK_STREAM_ID = 1;
HRESULT ValidateVideoFormat(const WAVEFORMATEX *pWav, DWORD cbSize);
HRESULT CreateRawVideoType(
UINT32 frameRate, // Samples per second
UINT32 width, // Bits per sample
UINT32 hieght, // Number of channels
IMFMediaType **ppType // Receives a pointer to the media type.
);
IFACEMETHODIMP CVideoSink::Initialize()
{
IMFByteStream *pStream = nullptr;
HRESULT hr = S_OK;
if (SUCCEEDED(hr))
{
hr = this->Initialize(pStream);
}
return hr;
}
CVideoSink::CVideoSink() :
m_nRefCount(1), m_IsShutdown(FALSE), m_pStream(NULL), m_pClock(NULL)
{
}
CVideoSink::~CVideoSink()
{
TRACE((L"~CVideoSink\n"));
assert(m_IsShutdown);
}
IFACEMETHODIMP CVideoSink::GetCharacteristics(DWORD *pdwCharacteristics)
{
AutoLock lock(m_critSec);
if (pdwCharacteristics == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pdwCharacteristics = MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS;
}
return hr;
}
IFACEMETHODIMP CVideoSink::AddStreamSink(
DWORD dwStreamSinkIdentifier,
IMFMediaType *pMediaType,
IMFStreamSink **ppStreamSink)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::RemoveStreamSink(DWORD dwStreamSinkIdentifier)
{
return MF_E_STREAMSINKS_FIXED;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkCount(DWORD *pcStreamSinkCount)
{
AutoLock lock(m_critSec);
if (pcStreamSinkCount == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*pcStreamSinkCount = 1; // Fixed number of streams.
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkByIndex(
DWORD dwIndex,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream: Index 0.
if (dwIndex > 0)
{
return MF_E_INVALIDINDEX;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetStreamSinkById(
DWORD dwStreamSinkIdentifier,
IMFStreamSink **ppStreamSink)
{
AutoLock lock(m_critSec);
if (ppStreamSink == NULL)
{
return E_INVALIDARG;
}
// Fixed stream ID.
if (dwStreamSinkIdentifier != VIDEO_SINK_STREAM_ID)
{
return MF_E_INVALIDSTREAMNUMBER;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
*ppStreamSink = m_pStream;
(*ppStreamSink)->AddRef();
}
return hr;
}
IFACEMETHODIMP CVideoSink::SetPresentationClock(IMFPresentationClock *pPresentationClock)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// If we already have a clock, remove ourselves from that clock's
// state notifications.
if (SUCCEEDED(hr))
{
if (m_pClock)
{
hr = m_pClock->RemoveClockStateSink(this);
}
}
// Register ourselves to get state notifications from the new clock.
if (SUCCEEDED(hr))
{
if (pPresentationClock)
{
hr = pPresentationClock->AddClockStateSink(this);
}
}
if (SUCCEEDED(hr))
{
// Release the pointer to the old clock.
// Store the pointer to the new clock.
SAFE_RELEASE(m_pClock);
m_pClock = pPresentationClock;
if (m_pClock)
{
m_pClock->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::GetPresentationClock(IMFPresentationClock **ppPresentationClock)
{
AutoLock lock(m_critSec);
if (ppPresentationClock == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
if (m_pClock == NULL)
{
hr = MF_E_NO_CLOCK; // There is no presentation clock.
}
else
{
// Return the pointer to the caller.
*ppPresentationClock = m_pClock;
(*ppPresentationClock)->AddRef();
}
}
return hr;
}
IFACEMETHODIMP CVideoSink::Shutdown()
{
TRACE((L"CVideoSink::Shutdown\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Shutdown();
SAFE_RELEASE(m_pClock);
SAFE_RELEASE(m_pStream);
m_IsShutdown = true;
}
return hr;
}
IFACEMETHODIMP CVideoSink::BeginFinalize(
IMFAsyncCallback *pCallback,
IUnknown *punkState)
{
TRACE((L"CVideoSink::BeginFinalize\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
// Tell the stream to finalize.
if (SUCCEEDED(hr))
{
hr = m_pStream->Finalize(pCallback, punkState);
}
return hr;
}
IFACEMETHODIMP CVideoSink::EndFinalize(IMFAsyncResult *pResult)
{
TRACE((L"CVideoSink::EndFinalize\n"));
HRESULT hr = S_OK;
// Return the status code from the async result.
if (pResult == NULL)
{
hr = E_INVALIDARG;
}
else
{
hr = pResult->GetStatus();
}
return hr;
}
HRESULT CVideoSink::OnClockStart(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ LONGLONG llClockStartOffset)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Start(llClockStartOffset);
}
return hr;
}
HRESULT CVideoSink::OnClockStop(
/* [in] */ MFTIME hnsSystemTime)
{
TRACE((L"CVideoSink::OnClockStop\n"));
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Stop();
}
return hr;
}
HRESULT CVideoSink::OnClockPause(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Pause();
}
return hr;
}
HRESULT CVideoSink::OnClockRestart(
/* [in] */ MFTIME hnsSystemTime)
{
AutoLock lock(m_critSec);
HRESULT hr = CheckShutdown();
if (SUCCEEDED(hr))
{
hr = m_pStream->Restart();
}
return hr;
}
HRESULT CVideoSink::OnClockSetRate(
/* [in] */ MFTIME hnsSystemTime,
/* [in] */ float flRate)
{
return S_OK;
}
HRESULT CVideoSink::Initialize(IMFByteStream *pByteStream)
{
HRESULT hr = S_OK;
m_pStream = new CVideoStream();
if (m_pStream == NULL)
{
hr = E_OUTOFMEMORY;
}
IMFMediaTypeHandler* typeHandler;
IMFMediaType* type;
// Initialize the stream.
if (SUCCEEDED(hr))
{
hr = m_pStream->Initialize(this, pByteStream);
}
return hr;
}
I will add the second part as another post ( sorry it is long code :) )
# not allowed :) get it from here https://github.com/Felixsoft/VideoSink
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();
}