set value to Excel cell in C++ throw exception 0x800A03EC - c++

I'm writing an Excel Addin. One of a UDF in the addin is to set value to a selected cell by using Excel Automation in C++. In my code, I have no problem to get range, read value from selected cell, but when I try to set value to cell, if the value is a string, the code throw exception (0x80020005 Type mismatch), otherwise, it always throw exception with HResult 0x800A03EC. Below is a code snippet:
Any ideas?
void SetValue()
{
Excel::SheetsPtr pSheets = GetExcelApplicationObj()->GetWorksheets();
Excel::_WorksheetPtr pSheet = GetExcelApplicationObj()->GetActiveSheet();
_variant_t text = pSheet->Range["A2"]->Text; //Read value from selected cell works fine
pSheet->Range["C2"]->Value = "Hello"; // throw 0x80020005 Type mismatch
pSheet->Range["B2"]->Value = 5.0; //Set value throw Exception with HRESULT 0x800A03EC
}
Excel::_Application* GetExcelApplicationObj()
{
if (m_pApp == NULL)
{
std::vector<HWND>::iterator it;
std::vector<HWND> handles = getToplevelWindows();
for (it = handles.begin(); it != handles.end(); it++)
{
HWND hwndChild = NULL;
::EnumChildWindows( (*it), EnumChildProc, (LPARAM)&hwndChild);
if (hwndChild != NULL)
{
Excel::Window* pWindow = NULL;
HRESULT hr = ::AccessibleObjectFromWindow(hwndChild, OBJID_NATIVEOM, __uuidof(Excel::Window), (void**)&pWindow);
if (SUCCEEDED(hr))
{
if (pWindow != NULL)
{
m_pApp = pWindow->GetApplication();
pWindow->Release();
}
break;
}
}
}
}
return m_pApp;
}
std::vector<HWND> getToplevelWindows()
{
EnumWindowsCallbackArgs args( ::GetCurrentProcessId() );
if ( ::EnumWindows( &EnumWindowsCallback, (LPARAM) &args ) == FALSE ) {
return std::vector<HWND>();
}
return args.handles;
}
BOOL CALLBACK EnumWindowsCallback( HWND hnd, LPARAM lParam )
{
EnumWindowsCallbackArgs *args = (EnumWindowsCallbackArgs *)lParam;
DWORD windowPID;
(void)::GetWindowThreadProcessId( hnd, &windowPID );
if ( windowPID == args->pid ) {
args->handles.push_back( hnd );
}
return TRUE;
}
BOOL CALLBACK EnumChildProc(HWND hwndChild,LPARAM lParam)
{
CHAR className[128];
::GetClassName(hwndChild, className, 128);
if (strcmp(className, "EXCEL7") == 0)
{
HWND * phandle = (HWND*)lParam;
(*phandle) = hwndChild;
return FALSE;
}
return TRUE;
}

You have to wrap the string value into a variant.
Try this:
pSheet->Range["C2"]->Value = _variant_t(_bstr_t("Hello")).Detach();

Related

C++ get windows title using process name

edit: how can i get windows title using processname? for example get current title of chrome.exe
You can get title of specific windows using it's process ID.
If you know the name of executed file(ex: Chrome.exe), you can get Handle with FindWindowEX() or get PID "Chrome.exe" with CreateToolHelp32Snapshot.
Then use EnumWindows to get HWND using HANDLE.
struct param_enum
{
unsigned long ulPID;
HWND hWnd_out;
};
HWND find_specific_window(unsigned long process_id)
{
param_enum param_data;
param_data.ulPID = process_id;
param_data.hWnd_out = 0;
EnumWindows(enum_windows_callback, (LPARAM)&param_data);
get_window_title(process_id, param_data.hWnd_out);
return param_data.hWnd_out;
}
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
param_enum& param_data = *(param_enum*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (param_data.ulPID != process_id)
{
return TRUE;
}
param_data.hWnd_out = handle;
return FALSE;
}
---------------------------Get Handle---------------------------
HANDLE GetHandleFromProcessPath(TCHAR* szExeName, DWORD& dwPID)
{
HANDLE hExeName = INVALID_HANDLE_VALUE;
HANDLE hSnap = INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE != hSnap)
{
if (Process32First(hSnap, &pe32))
{
do
{
//!!! Attention pe32.szExeFile always return exe file name. not window title.
if (NULL != _tcsstr(pe32.szExeFile, szExeName))
{
hExeName = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pe32.th32ProcessID);
dwPID = pe32.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &pe32));
}
}
return hExeName;
}
Completing the answer of "G.Alexander" and and the comment of Skewjo
the get_window_title code is incomplete. So, worked for me, by removing it and calling find_specific_window like below:
wchar_t* caption = new wchar_t[MAX_PATH*2];
HWND h = find_specific_window(processID);
GetWindowTextW(h, caption, MAX_PATH*2);

ListView accessibility issue -- how to make Windows Narrator read the entire selected row, including subitems?

I'm trying to add accessibility support to the WC_LISTVIEW control in my Win32/MFC application. I'm using Windows Narrator tool in Windows 10 to test the results. And by default it only reads the main item name of a selected row. For instance, in this case:
it will read only the country, when I need it to read the whole line.
So I found that I can set up a Server annotation for the list-view control using this example.
I would first set it up as such:
CAccPropServer_ListView* pMyPropSrv = NULL;
HRESULT hr;
CComPtr<IAccPropServices> pAccPropSvc = NULL;
hr = ::CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, IID_IAccPropServices, (void **)&pAccPropSvc);
if(SUCCEEDED(hr) &&
pAccPropSvc )
{
pMyPropSrv = new (std::nothrow) CAccPropServer_ListView( pAccPropSvc );
if( pMyPropSrv )
{
MSAAPROPID propids[] = {
PROPID_ACC_NAME,
};
hr = pAccPropSvc->SetHwndPropServer( hWndListCtrl, OBJID_CLIENT,
CHILDID_SELF, propids, 1, pMyPropSrv, ANNO_CONTAINER);
pMyPropSrv->Release();
}
}
where the CAccPropServer_ListView class does all the work:
class CAccPropServer_ListView: public IAccPropServer
{
ULONG m_Ref;
IAccPropServices * m_pAccPropSvc;
public:
CAccPropServer_ListView( IAccPropServices * pAccPropSvc )
: m_Ref( 1 ),
m_pAccPropSvc( pAccPropSvc )
{
m_pAccPropSvc->AddRef();
}
~CAccPropServer_ListView()
{
m_pAccPropSvc->Release();
}
/* TODO: Addref/Release/QI go here...
Skipped them for brevity...
*/
HRESULT STDMETHODCALLTYPE GetPropValue (const BYTE * pIDString,
DWORD dwIDStringLen, MSAAPROPID idProp, VARIANT * pvarValue,
BOOL * pfGotProp )
{
if(!pfGotProp)
return E_POINTER;
pvarValue->vt = VT_EMPTY;
*pfGotProp = FALSE;
HWND hwnd;
DWORD idObject;
DWORD idChild;
if( S_OK != m_pAccPropSvc->DecomposeHwndIdentityString( pIDString,
dwIDStringLen, &hwnd, &idObject, &idChild ) )
{
return S_OK;
}
if( idChild != CHILDID_SELF )
{
if( idProp == PROPID_ACC_NAME )
{
CString str;
str.Format(L"Line index %d", idChild);
BSTR bstr = ::SysAllocString((LPCTSTR)str.GetString());
pvarValue->vt = VT_BSTR;
pvarValue->bstrVal = bstr;
*pfGotProp = TRUE;
}
}
return S_OK;
}
};
So my question is concerning GetPropValue method above that actually generates the text prompt for Narrator to read out loud.
How do I get an index of a row read by the Narrator from the idChild that is returned by DecomposeHwndIdentityString?
In my example above, purely experimentally, I was getting the following values:
"Line index 17"
"Line index 33"
"Line index 49"
"Line index 65"
and so on
which would translate to 0x11, 0x21, 0x31, 0x41 that are not row indexes. Are those IDs documented anywhere for a SysListView32?

How to set window text by its handle in another process?

For my purposes I need to set text for a window that belongs to another process using its HWND handle. I came up with the following code, but it doesn't seem to work:
BOOL SetWindowTextInAnotherProcess(HWND hWnd, LPCTSTR pStrText)
{
//Set text of the 'hWnd' (assuming that 'hWnd' is in another process)
//'pStrText' = ASCIIZ string to set
//RETURN:
// = TRUE if done
BOOL bRes = FALSE;
if(hWnd &&
pStrText)
{
DWORD dwProcID = 0;
::GetWindowThreadProcessId(hWnd, &dwProcID);
if(dwProcID)
{
HANDLE hProc = ::OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcID);
if(hProc)
{
int nLn = lstrlen(pStrText);
int ncbSzStr = (nLn + 1) * sizeof(TCHAR);
VOID* pVMem = ::VirtualAllocEx(hProc, NULL, ncbSzStr, MEM_COMMIT, PAGE_READWRITE);
if(pVMem)
{
SIZE_T sztWrtn = 0;
if(::WriteProcessMemory(hProc, pVMem, pStrText, ncbSzStr, &sztWrtn))
{
if(sztWrtn == ncbSzStr)
{
DWORD_PTR dwMsgRes = 0xCCCCABAB;
if(::SendMessageTimeout(hWnd, WM_SETTEXT, NULL, (LPARAM)pVMem,
SMTO_NORMAL | SMTO_ABORTIFHUNG | SMTO_ERRORONEXIT,
1000 * 2,
&dwMsgRes))
{
//Check result
if(dwMsgRes != 0xCCCCABAB &&
dwMsgRes == TRUE)
{
//Done
bRes = TRUE;
}
}
}
}
//Free mem
::VirtualFreeEx(hProc, pVMem, ncbSzStr, MEM_DECOMMIT);
}
::CloseHandle(hProc);
}
}
}
return bRes;
}
SendMessageTimeout returns FALSE and GetLastError returns 0.
Any idea what am I doing wrong?
PS. Both processes are running non-elevated on the same desktop.

Working with transparent PNG in Windows mobile 6.x using C++

I have been trying to add to resource and use some semi transparent PNG files in my windows mobile 6.x application. After days of looking around and experimenting with different methods, I decided to dynamically load and use gdiplus.dll and use the flat APIs. everything works except function GdipCreateHBITMAPFromBitmap returns NotImplemented (6). any idea how to fix this problem? I have 3 files that I am attaching here.
GdiPlusDynamic.cpp:
#include "GdiPlusDynamic.h"
#include "GdiPlusDynamicTools.h"
#include <string>
TAutoStream::TAutoStream(HGLOBAL m_hBuffer)
{
pStream = NULL;
switch(::CreateStreamOnHGlobal(m_hBuffer, TRUE, &pStream))
{
case E_NOINTERFACE:
throw std::wstring(L"The specified interface is not supported");
break;
case E_OUTOFMEMORY:
throw std::wstring(L"Not enough memory");
break;
default:
break;
}
}
TAutoStream::~TAutoStream(void)
{
if(NULL != pStream)
pStream->Release();
}
IStream* TAutoStream::get(void)
{
return pStream;
}
AutoGlobal::AutoGlobal(UINT uFlags, SIZE_T dwBytes) : len(0)
{
m_hBuffer = ::GlobalAlloc(uFlags, dwBytes);
if(IsOk())
{
memset(m_hBuffer, 0, dwBytes);
len = dwBytes;
}
}
AutoGlobal::~AutoGlobal(void)
{
if(IsOk())
::GlobalFree(m_hBuffer);
}
bool AutoGlobal::IsOk(void)
{
return (NULL != m_hBuffer);
}
HGLOBAL AutoGlobal::get(void)
{
return m_hBuffer;
}
TAutoLockedBuff::TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes) : AutoGlobal(uFlags, dwBytes)
{
pBuffer = NULL;
if(AutoGlobal::IsOk())
pBuffer = GlobalLock(m_hBuffer);
}
TAutoLockedBuff::~TAutoLockedBuff(void)
{
if(IsOk())
GlobalUnlock(m_hBuffer);
}
bool TAutoLockedBuff::IsOk(void)
{
return (AutoGlobal::IsOk() && (NULL != pBuffer));
}
void TAutoLockedBuff::CopyFrom(const void* pSrcData, SIZE_T srcLen)
{
if(IsOk())
CopyMemory(pBuffer, pSrcData, min(srcLen, len));
}
TDynamicGdiPlus::TDynamicGdiPlus(void) : everythigOK(false)
{
GdiplusStartupInput dpStartupInfo;
token = 0;
pGdiplusStartup = NULL;
pGdiplusShutdown = NULL;
pGdipCreateBitmapFromStream = NULL;
pGdipCreateHBITMAPFromBitmap = NULL;
pGdipFree = NULL;
hGdiPlus = ::LoadLibrary(L"gdiplus.dll");
if(NULL == hGdiPlus)
throw std::wstring(L"Unable to load 'gdiplus.dll'");
pGdiplusStartup = (TGdiplusStartup)GetProcAddress(hGdiPlus, L"GdiplusStartup");
if(NULL == pGdiplusStartup)
throw std::wstring(L"Unable to get the address of 'GdiplusStartup'");
pGdiplusShutdown = (TGdiplusShutdown)GetProcAddress(hGdiPlus, L"GdiplusShutdown");
if(NULL == pGdiplusShutdown)
throw std::wstring(L"Unable to get the address of 'GdiplusShutdown'");
pGdipCreateBitmapFromStream = (TGdipCreateBitmapFromStream)GetProcAddress(hGdiPlus, L"GdipCreateBitmapFromStreamICM");
if(NULL == pGdipCreateBitmapFromStream)
throw std::wstring(L"Unable to get the address of 'GdipCreateBitmapFromStreamICM'");
pGdipCreateHBITMAPFromBitmap = (TGdipCreateHBITMAPFromBitmap)GetProcAddress(hGdiPlus, L"GdipCreateHBITMAPFromBitmap");
if(NULL == pGdipCreateHBITMAPFromBitmap)
throw std::wstring(L"Unable to get the address of 'GdipCreateHBITMAPFromBitmap'");
pGdipFree = (TGdipFree)GetProcAddress(hGdiPlus, L"GdipFree");
if(NULL == pGdipFree)
throw std::wstring(L"Unable to get the address of 'GdipFree'");
if(Status::Ok != pGdiplusStartup(&token, &dpStartupInfo, NULL))
throw std::wstring(L"Unable to start 'GDI Plus'");
else
everythigOK = true;
}
TDynamicGdiPlus::~TDynamicGdiPlus(void)
{
if((0 != token) && (NULL != pGdiplusShutdown))
pGdiplusShutdown(token);
if(NULL != hGdiPlus)
FreeLibrary(hGdiPlus);
}
HBITMAP TDynamicGdiPlus::LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType)
{
HBITMAP retVal = NULL;
if(everythigOK)
{
HRSRC hResource = ::FindResource(hInst, lpName, lpType);
if (NULL != hResource)
{
DWORD imageSize = ::SizeofResource(hInst, hResource);
if (0 < imageSize)
{
const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));
if (NULL != pResourceData)
{
TAutoLockedBuff m_Buffer(GMEM_MOVEABLE, imageSize + 1);
void* pBmp;
m_Buffer.CopyFrom(pResourceData, imageSize);
TAutoStream m_Stream(m_Buffer.get());
pGdipCreateBitmapFromStream(m_Stream.get(), &pBmp);
if (NULL != pBmp)
{
pGdipCreateHBITMAPFromBitmap(pBmp, &retVal, 0x00FFFFFF); // this returns NotImplemented
pGdipFree(pBmp);
if(NULL == retVal)
throw std::wstring(L"Unable to extract HBITMAP from Gdiplus::Bitmap");
}
else
throw std::wstring(L"Unable to extract Gdiplus::Bitmap from stream");
}
else
throw std::wstring(L"Unable to lock resource");
}
else
throw std::wstring(L"Size of resource is 0");
}
else
throw std::wstring(L"Unable to find resource");
}
return retVal;
}
GdiPlusDynamic.h
#pragma once
typedef enum {
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
ProfileNotFound = 21
} Status;
enum DebugEventLevel
{
DebugEventLevelFatal,
DebugEventLevelWarning
};
// Callback function that GDI+ can call, on debug builds, for assertions
// and warnings.
typedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);
// Notification functions which the user must call appropriately if
// "SuppressBackgroundThread" (below) is set.
typedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);
typedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);
struct GdiplusStartupInput
{
UINT32 GdiplusVersion; // Must be 1 (or 2 for the Ex version)
DebugEventProc DebugEventCallback; // Ignored on free builds
BOOL SuppressBackgroundThread; // FALSE unless you're prepared to call
// the hook/unhook functions properly
BOOL SuppressExternalCodecs; // FALSE unless you want GDI+ only to use
// its internal image codecs.
GdiplusStartupInput(
DebugEventProc debugEventCallback = NULL,
BOOL suppressBackgroundThread = FALSE,
BOOL suppressExternalCodecs = FALSE)
{
GdiplusVersion = 1;
DebugEventCallback = debugEventCallback;
SuppressBackgroundThread = suppressBackgroundThread;
SuppressExternalCodecs = suppressExternalCodecs;
}
};
struct GdiplusStartupOutput
{
// The following 2 fields are NULL if SuppressBackgroundThread is FALSE.
// Otherwise, they are functions which must be called appropriately to
// replace the background thread.
//
// These should be called on the application's main message loop - i.e.
// a message loop which is active for the lifetime of GDI+.
// "NotificationHook" should be called before starting the loop,
// and "NotificationUnhook" should be called after the loop ends.
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
};
typedef Status (WINAPI *TGdiplusStartup)(ULONG_PTR* token, const GdiplusStartupInput *input, GdiplusStartupOutput *output);
typedef void (WINAPI *TGdiplusShutdown)(ULONG_PTR token);
typedef Status (WINAPI *TGdipCreateBitmapFromStream)(IStream* stream, void **bitmap);
typedef Status (WINAPI *TGdipCreateHBITMAPFromBitmap)(void* bitmap, HBITMAP* hbmReturn, DWORD background);
typedef void (WINAPI *TGdipFree)(void* ptr);
class TDynamicGdiPlus
{
private:
bool everythigOK;
protected:
HMODULE hGdiPlus;
TGdiplusStartup pGdiplusStartup;
TGdiplusShutdown pGdiplusShutdown;
TGdipCreateBitmapFromStream pGdipCreateBitmapFromStream;
TGdipCreateHBITMAPFromBitmap pGdipCreateHBITMAPFromBitmap;
TGdipFree pGdipFree;
ULONG_PTR token;
public:
TDynamicGdiPlus(void);
virtual ~TDynamicGdiPlus(void);
HBITMAP LoadImageFromResource(HINSTANCE hInst, LPCTSTR lpName, LPCTSTR lpType);
};
and GdiPlusDynamicTools.h
#pragma once
class TAutoStream
{
protected:
IStream* pStream;
public:
TAutoStream(HGLOBAL m_hBuffer);
virtual ~TAutoStream(void);
IStream* get(void);
};
class AutoGlobal
{
protected:
HGLOBAL m_hBuffer;
SIZE_T len;
public:
AutoGlobal(UINT uFlags, SIZE_T dwBytes);
virtual ~AutoGlobal(void);
bool IsOk(void);
HGLOBAL get(void);
};
class TAutoLockedBuff : public AutoGlobal
{
protected:
void* pBuffer;
public:
TAutoLockedBuff(UINT uFlags, SIZE_T dwBytes);
virtual ~TAutoLockedBuff(void);
bool IsOk(void);
void CopyFrom(const void* pSrcData, SIZE_T srcLen);
};
You can use IImagingFactory service instead GDI+
This service can render png, bmp with alpha channel.
We use this service for real project under Windows Mobile 6.x
This code mockup:
CComPtr<IImagingFactory> spImageFactory;
spImageFactory.CoCreateInstance(__uuidof(ImagingFactory);
HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(resID), _T("PNG"));
DWORD imageSize = SizeOfResource(hInstance, hRes);
HGLOBAL hGlobal = LoadResource(hInstance, hRes);
CComPtr<IImage> spImage;
spImageFactory->CreateImageFromBuffer(LockResource(hGlobal, imageSize), BufferDisposalFlagNone, &spImage);
ImageInfo info = {0};
spImage->GetImageInfo(&info);
CRect rect(x, y, x+info.Width, y+info.Height);
spImage->Draw(hDc, &rect, NULL);

Not able to Print the folder path in EditBox- MFC

I am using the following function ..instead of CFolderDialog.. to get the folder path...check my code below....am getting a run time error when i try toprint the folder path name in a edit box..
void
CSelfExtractorUIDlg::OnBnClickedButton1()
{
CDialog dlg;
HWND hwnd = NULL; LPCTSTR szCurrent =
(LPCTSTR)malloc(25*sizeof(TCHAR));
szCurrent = NULL; LPTSTR szPath =
(LPTSTR)malloc(25*sizeof(TCHAR)); BOOL
check =
BrowseForFolder(hwnd,szCurrent,szPath);
if( check == TRUE) {
dlg.SetDlgItemTextW(IDC_EDIT1,szPath);
}
}
BOOL BrowseForFolder(HWND hwnd,
LPCTSTR szCurrent, LPTSTR szPath) {
BROWSEINFO bi = { 0 }; LPITEMIDLIST
pidl; TCHAR szDisplay[256]; BOOL
retval;
//CoInitialize();
bi.hwndOwner = hwnd;
bi.pszDisplayName = szDisplay;
bi.lpszTitle = TEXT("Please
choose a folder."); bi.ulFlags
= BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; bi.lpfn
= BrowseCallbackProc; bi.lParam = (LPARAM) szCurrent;
pidl = SHBrowseForFolder(&bi);
if (NULL != pidl) {
retval = SHGetPathFromIDList(pidl, szPath);
CoTaskMemFree(pidl); } else {
retval = FALSE; }
if (!retval) {
szPath[0] = TEXT('\0'); }
CoUninitialize(); return retval;
} static int CALLBACK
BrowseCallbackProc(HWND hwnd,UINT
uMsg, LPARAM lParam, LPARAM lpData)
{
// If the BFFM_INITIALIZED message is
received // set the path to the start
path.
switch (uMsg) { case
BFFM_INITIALIZED: { if (NULL !=
lpData) { SendMessage(hwnd,
BFFM_SETSELECTION, TRUE, lpData); }
} }
return 0; // The function
25 characters seems a little short for a full path length, I'd use MAX_PATH.