How to find the function name, which is going to be invoked? - visual-c++

I got:
InvokeHelper(0x18, DISPATCH_METHOD, VT_I4, (void*)&result, NULL);
How to get function name, if we have the object method or property
specified by dwDispID = 0x18?
void AFX_CDECL InvokeHelper(
DISPID dwDispID,
WORD wFlags,
VARTYPE vtRet,
void* pvRet,
const BYTE* pbParamInfo,
...
);

Here's a simple sample of how to fetch the name
void CTestDlg::OnTypeinfo()
{
HRESULT hr = S_OK;
COleDispatchDriver sc;
sc.CreateDispatch("Omtool.ServConnect.1"); // change for your type
CComPtr<ITypeInfo> pti;
hr = sc.m_lpDispatch->GetTypeInfo(0, GetUserDefaultLCID(), &pti);
ASSERT(SUCCEEDED(hr));
CComBSTR bstrName;
UINT nCount = 0;
hr = pti->GetNames(0x2, &bstrName, 1, &nCount); // change 0x2 for your ID
ASSERT(SUCCEEDED(hr));
}

I would try to get a ITypeInfo interface on the object (CWnd::GetControlUnknown, IUnknown::QueryInterface). Then you can use the ITypeInfo::GetNames function with your member ID (0x18) to get the name of the method.

Related

Component Object Model via C++

I want to use object of my software using COM interface my code is :
::CLSIDFromProgID(OLESTR("SGNSAutomation.SGNSApplication"), &clsid);
IID iid;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL,
IID_IDispatch, (LPVOID*)&pWMPDispatch);
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
DISPPARAMS params = {NULL};
OLECHAR * Name = OLESTR("addSimulationCase");
HRESULT hresult =pWMPDispatch->GetIDsOfNames(IID_NULL,
&Name,1,LOCALE_SYSTEM_DEFAULT,&dispid);
hresult =pWMPDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &params, NULL, NULL,
NULL);
//pdisp IDispatch
_ASSERT(hr==S_OK);
I don't know what is exactly param that is one of input argument of invoke.
please Help me I am a dummy in C++.

How to get installed application path for executable in COM

I am trying to get the installed location of all application using COM. I am able to get the display name of each application. But I am not able to get installed path of each application.
MY Code:
CComPtr<IShellItem> spPrinters;
CoInitialize(nullptr);
HRESULT hresult = ::SHCreateItemFromParsingName(L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\"
L"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr, IID_PPV_ARGS(&spPrinters));
CComPtr<IEnumShellItems> spEnum;
spPrinters->BindToHandler(nullptr, BHID_EnumItems, IID_PPV_ARGS(&spEnum));
for (CComPtr<IShellItem> spProgram; spEnum->Next(1, &spProgram, nullptr) == S_OK; spProgram.Release())
{
CComHeapPtr<wchar_t> spszName;
spProgram->GetDisplayName(SIGDN_NORMALDISPLAY, &spszName);
CString cDisplayName = spszName;
}
Any idea how to get installed path from IEnumShellItems?
Here is a piece of code that will dump this out. The child's IPropertyStore does not return these, I don't know why, so we have to use the old
IShellFolder2::GetDetailsEx method with a special column id (which is the same as a PROPERTYKEY).
CComPtr<IShellItem> cpl;
CComPtr<IShellFolder2> folder;
CComPtr<IEnumShellItems> enumerator;
PROPERTYKEY pkLocation;
SHCreateItemFromParsingName(L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr, IID_PPV_ARGS(&cpl));
// bind to IShellFolder
cpl->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARGS(&folder));
// bind to IEnumShellItems
cpl->BindToHandler(NULL, BHID_EnumItems, IID_PPV_ARGS(&enumerator));
// get this property key's value
PSGetPropertyKeyFromName(L"System.Software.InstallLocation", &pkLocation);
for (CComPtr<IShellItem> child; enumerator->Next(1, &child, nullptr) == S_OK; child.Release())
{
// get child's display name
CComHeapPtr<wchar_t> name;
child->GetDisplayName(SIGDN_NORMALDISPLAY, &name);
wprintf(L"%s\n", name);
// get child's PIDL
CComHeapPtr<ITEMIDLIST> pidl;
SHGetIDListFromObject(child, &pidl);
// the PIDL is absolute, we need the relative one (the last itemId in the list)
// get it's install location
CComVariant v;
if (SUCCEEDED(folder->GetDetailsEx(ILFindLastID(pidl), &pkLocation, &v)))
{
// it's a VT_BSTR
wprintf(L" %s\n", v.bstrVal);
}
}
Note it's using an undocumented System.Software.InstallLocation PROPERTYKEY. To find it I just dumped all columns with a code like this for each child:
int iCol = 0;
do
{
SHCOLUMNID colId;
if (FAILED(folder->MapColumnToSCID(iCol, &colId)))
break; // last column
CComHeapPtr<wchar_t> name;
PSGetNameFromPropertyKey(colId, &name);
CComVariant v;
if (SUCCEEDED(folder->GetDetailsEx(ILFindLastID(pidl), &colId, &v)))
{
if (v.vt == VT_BSTR)
{
wprintf(L" %s: %s\n", name, v.bstrVal);
}
else
{
wprintf(L" %s vt: %i\n", name, v.vt);
}
}
iCol++;
} while (true);
}
PS: I've not added much error checking, but you should.

Waitformultipleobjects returns invalid handle

The code is below and it is part of a thread. pFileChange->m_hDirectory is of type HANDLE and pFileChange->m_eventFileChange if of type CEvent. CreateFile and ReadDirectoryChangesW return with a success. I am not able to figure out why i am getting an invalid handle status, please help!
UINT CFileChange::FileMontiorThread(LPVOID pArgs)
{
CFileChange* pFileChange = NULL;
pFileChange = (CFileChange*)pArgs;
pFileChange = (CFileChange*)pArgs;
CString str = pFileChange->m_strDirectory;
LPSTR strDirectory;
strDirectory = str.GetBuffer(str.GetLength());
PathRemoveFileSpec(strDirectory);
DWORD dwBytes = 0;
vector<BYTE> m_Buffer;
BOOL m_bChildren;
OVERLAPPED m_Overlapped;
HANDLE arrHandles[2] = { pFileChange->m_hDirectory, pFileChange->m_eventFileChange };
::ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
DWORD dwBufferSize = 16384;
m_Buffer.resize(dwBufferSize);
m_bChildren = false;
pFileChange->m_hDirectory = ::CreateFile(
(LPCSTR)(LPCTSTR)strDirectory,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED,
NULL);
if (pFileChange->m_hDirectory == INVALID_HANDLE_VALUE)
{
return false;
}
BOOL success = ::ReadDirectoryChangesW(
pFileChange->m_hDirectory, // handle to directory
&m_Buffer[0], // read results buffer
m_Buffer.size(), // length of buffer
m_bChildren, // monitoring option
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME, // filter conditions
&dwBytes, // bytes returned
&m_Overlapped, // overlapped buffer
NULL); // no completion routine
DWORD dwWaitStatus;
while (!pFileChange->m_bKillThread)
{
dwWaitStatus = WaitForMultipleObjects(2, arrHandles, FALSE, INFINITE);
Switch(dwWaitStatus)
{
case WAIT_FAILED:
{
ULONG rc = 0;
rc = ::GetLastError();
LPVOID lpMsgBuf = NULL;
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL);
CString strErrMsg;
strErrMsg.Format(_T("%s, %s, Reason:%s"), "", "", (LPTSTR)lpMsgBuf);
break;
}
}
}
return 0;
}
Note that, as it specifies in the documentation, you can't wait on any type of handle.
Waiting on a directory handle isn't going to do what you think it should. Read this related question and its answers for more information and background reading.
As it seems you're trying to create a folder monitor, perhaps read this blog post for the correct way to use ReadDirectoryChangesW.
The answer was provided by Hans Passant in a comment:
You copy the handles into arrHandles too soon, before they are created. That cannot work of course.

How to define Task with parameters and return value in c++\cli?

i have a class in a cs file:
public class ThreadData
{
private int index;
public ThreadData(int index)
{
this.index = index;
}
public static ThreadDataOutput DoWork(ThreadDataInput input)
{
return new ThreadDataOutput();
}
}
now, i have c++ code that tries to init a new task and to us the above function:
int numOfThread = 2;
array<Task^>^ taskArr = gcnew array<Task^>(numOfThread);
for (int i = 0; i < numOfThread; i++)
{
ThreadData^ td = gcnew ThreadData(i);
ThreadDataInput^ input = gcnew ThreadDataInput(i);
Task<ThreadDataOutput^>^ task = gcnew Task<ThreadDataOutput^>(td->DoWork, input);
taskArr[i] = task;
taskArr[i]->Start();
}
Task::WaitAll(taskArr, 300 * 1000);
the following code return 2 errors at compile time:
can't take address of 'ThreadData::DoWork' unless creating delegate instance
cannot convert argument 1 from 'AmadeusWS::ThreadDataOutput ^(__clrcall *)(AmadeusWS::ThreadDataInput ^)' to 'System::Func ^
i also tried to declare a delegate like this in the cs file:
public static Func<ThreadDataInput, ThreadDataOutput> DoWork2 = delegate(ThreadDataInput taskDataInput)
{
return new ThreadDataOutput();
};
but i don't know how to call it from the c++\cli code
can anyone assist me to understand how to define cli delegate that can take parametr ?
thanks
In order to create a delegate instance in C++/CLI, you need to construct it explicitly, and specify the object that it will be called on separately from the class & method to be called.
gcnew Func<TInput, TOutput>(theObject, &TheClass::MethodToInvoke)
Note that the method to be called is specified in the C++ style.
Substituting that in to your task creation, I believe this statement will work for you:
Task<ThreadDataOutput^>^ task = gcnew Task<ThreadDataOutput^>(
gcnew Func<ThreadDataInput^, ThreadDataOutput^>(td, &ThreadData::DoWork),
input);
Edit
In the code you posted in your comment, you missed the object to invoke the delegate on.
gcnew Func<Object^, Object^>(td, &ThreadData::DoWork)
^^

My BHO does not work properly. DocumentComplete does not trigger

I am doing a BHO for Internet Explorer. The problem is only the SetSite is working. BUt the DocumentComplete does not been triggered. I need some help in pointing me what is I am doing wrong.
Here is what I declared inside my header file:
class ATL_NO_VTABLE CStockBar :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CStockBar, &CLSID_StockBar>,
public IDeskBand,
public IObjectWithSite,
public IObjectWithSiteImpl<CStockBar>,
public IInputObject,
public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>,
public IDispEventImpl<1, CStockBar, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
{
public:
CStockBar();
DECLARE_REGISTRY_RESOURCEID(IDR_STOCKBAR)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_CATEGORY_MAP(CStockBar)
// IMPLEMENTED_CATEGORY(CATID_InfoBand)
// IMPLEMENTED_CATEGORY(CATID_CommBand)
// IMPLEMENTED_CATEGORY(CATID_DeskBand)
END_CATEGORY_MAP()
BEGIN_COM_MAP(CStockBar)
COM_INTERFACE_ENTRY(IStockBar)
// COM_INTERFACE_ENTRY(IInputObject)
COM_INTERFACE_ENTRY(IOleWindow)
COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)
COM_INTERFACE_ENTRY(IObjectWithSite)
COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
BEGIN_SINK_MAP(CStockBar)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()
Here is my SetSite and DocumentComplete functions:
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite)
{
//If a site is being held, release it.
if(m_pSite)
{
m_ReflectWnd.GetToolBar().SetBrowser(NULL);
m_pSite->Release();
m_pSite = NULL;
}
if (pUnkSite != NULL)
{
// Cache the pointer to IWebBrowser2.
HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void**)&m_spWebBrowser);
if (SUCCEEDED(hr))
{
// Register to sink events from DWebBrowserEvents2.
hr = DispEventAdvise(m_spWebBrowser);
if (SUCCEEDED(hr))
{
m_fAdvised = TRUE;
}
}
}
else
{
if (m_fAdvised)
{
DispEventUnadvise(m_spWebBrowser);
m_fAdvised = FALSE;
}
m_spWebBrowser.Release();
}
//If punkSite is not NULL, a new site is being set.
if(pUnkSite)
{
//Get the parent window.
IOleWindow *pOleWindow = NULL;
m_hWndParent = NULL;
if(SUCCEEDED(pUnkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow)))
{
pOleWindow->GetWindow(&m_hWndParent);
pOleWindow->Release();
}
if(!::IsWindow(m_hWndParent))
return E_FAIL;
if(!RegisterAndCreateWindow())
return E_FAIL;
//Get and keep the IInputObjectSite pointer.
if(FAILED(pUnkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pSite)))
{
return E_FAIL;
}
IWebBrowser2* s_pFrameWB = NULL;
IOleCommandTarget* pCmdTarget = NULL;
HRESULT hr = pUnkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarget);
if (SUCCEEDED(hr))
{
IServiceProvider* pSP;
hr = pCmdTarget->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);
pCmdTarget->Release();
if (SUCCEEDED(hr))
{
hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&s_pFrameWB);
pSP->Release();
_ASSERT(s_pFrameWB);
m_ReflectWnd.GetToolBar().SetBrowser(s_pFrameWB);
s_pFrameWB->Release();
}
}
}
return S_OK;
}
void STDMETHODCALLTYPE CStockBar::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
// Retrieve the top-level window from the site.
HWND hwnd;
HRESULT hr = m_spWebBrowser->get_HWND((LONG_PTR*)&hwnd);
if (SUCCEEDED(hr))
{
// Output a message box when page is loaded.
MessageBox(hwnd,"Hello World!","BHO", MB_OK);
}
}
You should use SINK_ENTRY_INFO with IDispEventImpl as pointed in
http://msdn.microsoft.com/en-us/library/2wt7d0s4(v=vs.80).aspx
You are probably running your code in release as otherwise you would have get a assertion because idispeventimpl wouldn't be able to retrieve the typelib for DIID_DWebBrowserEvents2. DIID_DWebBrowserEvents2 doesn't have a typelib because it's a disp interface.
Declare in your header:
extern ATL::_ATL_FUNC_INFO DocumentComplete2Struct;
BEGIN_SINK_MAP(CStockBar)
SINK_ENTRY_INFO(1, __uuidof(DWebBrowserEvents2), DISPID_DOCUMENTCOMPLETE, OnDocumentComplete, &DocumentComplete2Struct);
END_SINK_MAP()
In your CPP :
ATL::_ATL_FUNC_INFO DocumentComplete2Struct = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BYREF|VT_VARIANT}};
I can't see anything that stands out as definably incorrect, so here is another example hacked out of some working code, includes only the bits needed for site to keep it simple.
One thing that may be an issue is - m_spWebBrowser if this is the ATL class then it doesn't like you overwriting existing using the address of once it is set. It may be returning false at which point you won't be running advise.
HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void**)&m_spWebBrowser);
declaration h
class ATL_NO_VTABLE CStockBar:
public CComObjectRootEx<CComGlobalsThreadModel>,
public CComCoClass<CStockBar, &CLSID_StockBar>,
public IObjectWithSiteImpl<CStockBar>,
public IDispEventImpl<1, CStockBar, &__uuidof(DWebBrowserEvents2), &LIBID_SHDocVw, 1, 0>{
protected:
typedef IDispEventImpl<1, CStockBar, &__uuidof(DWebBrowserEvents2), &LIBID_SHDocVw, 1, 0> base_BrowserDispEvents;
typedef IObjectWithSiteImpl<CStockBar> base_objectWithSite;
BEGIN_SINK_MAP(CStockBar)
// we use this variation - think it resolves the same
SINK_ENTRY_EX(1, (__uuidof(DWebBrowserEvents2)), DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()
CComQIPtr<IWebBrowser2> m_spBrowser;
Implementation cpp
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite) {
// Detach the web browser and site
if (m_spBrowser) {
base_BrowserDispEvents::DispEventUnadvise(m_spBrowser);
m_spBrowser.Release();
}
if (pUnkSite) {
m_spBrowser = pUnkSite;
if (m_spBrowser)
{
base_BrowserDispEvents::DispEventAdvise(m_spBrowser);
}
}
return base_objectWithSite::SetSite(pUnkSite);

Resources