Change div innerHTML through IHTMLDocument2 and C++ - c++

I'm trying to change the content of a div using IHTMLDocument2 interface this way:
IHTMLElementCollection* collection = NULL;
IDispatch* mydiv;
doc2->get_all(&collection);
long count;
collection->get_length(&count); //just to check I get something
CComVariant varstr = L"mydivname";
CComVariant varint = 0;
collection->item(varstr, varint, &mydiv); //this works I get the div
IHTMLElement* htmldiv;
mydiv->QueryInterface(IID_IHTMLElement, (void**)&htmldiv);
CComBSTR html;
htmldiv->get_innerHTML(&html); //works too, I get the current content
HRESULT hr=htmldiv->put_innerText(L"hello"); //this does not work but returns S_OK
collection->Release();
So the content of my div is just cleared and not replaced with "hello", I don't understand why, can it be a security issue ?
Thanks

According to the MSDN documentation, the string passed to put_innerText is of type BSTR.
So, I would suggest trying some code like this:
CComBSTR text(OLESTR("hello"));
hr = htmldiv->put_innerText(text);

Related

c++ MFC SDI DLL call method of OLE Server using IDispatch

I have written a c++ MFC DLL that brings up an SDI Application which is a very legacy OLE Server. (I have no choice about using this OLE Server so I have to make it work.)
I am accessing this c++ DLL from C#.
I have everything "working". I can call methods of the DLL, I have implemented C# delegates correctly, etc.
I can call methods of the OLE Server directly in C++ and export these so that my C# application call call them too. This is my "Hello World" for accessing the OLE Server functionality in its entirety from C#.
So far so good.
The next step is to make this C++ DLL as much of a "pass-through" as possible so that C# developers can write business logic around this OLE server. If changes or updates happen from the maker of the OLE Server, we do not want to have to update C++ code, we want to respond to the changes in C#.
So even though I can implement methods in C++ using the imported class from the OLEServer.tlb file and pass these through to C#, we do not want to ultimately do this. I am trying to call methods through the IDispatch interface instead and I am running into difficulties that I can't quite understand.
I am using Visual Studio 2010 for both unmanaged C++ and C#.
VARIANT LaserCat::LaserCatCommand(LPCTSTR* p_pMethodNameAndParamsInReverseOrder, UINT p_Count)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
VARIANT result;
VARIANT* pResult = NULL;
VariantInit(&result);
HRESULT hr = NULL;
DISPID dispid;
const IID IID_ITriad = {0x60EE772D,0xE076,0x4F58,{0xA8,0xB4,0x2F,0x7A,0x29,0xBB,0x02,0x50}};
COleException* pError = NULL;
BOOL HasDispatch = theApp.pTriadView->pTriadItem->Catalog.CreateDispatch(IID_ITriad, pError);
LPDISPATCH iDisp = theApp.pTriadView->pTriadItem->Catalog.m_lpDispatch;
LPOLESTR Names[1] = {(LPOLESTR)L"GetInterfaceVersion"};
hr = iDisp->GetIDsOfNames(IID_NULL, Names, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (hr != S_OK) return result;
DISPPARAMS* pParams = new DISPPARAMS();
short maj = 0;
short min = 0;
short* nMajor = &maj;
short* nMinor = &min;
VARIANTARG Args[2];
VariantInit(&Args[0]);
VariantInit(&Args[1]);
Args[0].piVal = nMinor;
Args[0].vt = VT_BYREF;
Args[1].piVal = nMajor;
Args[1].vt = VT_BYREF;
pParams->rgvarg = Args;
pParams->cNamedArgs = 0;
pParams->cArgs = 2;
pParams->rgdispidNamedArgs = NULL;
EXCEPINFO* pExcept = NULL;
UINT* pArgErrorIndex = NULL;
LPCTSTR Error = NULL;
hr = iDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, pParams, pResult, pExcept, pArgErrorIndex);
if (pExcept != NULL || pArgErrorIndex != NULL || hr != S_OK)
{
Error = _T("Error");
return result;
}
result = *pResult;
return result;
}
The following line from above gives me a "Bad variable type" error:
hr = iDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, pParams, pResult, pExcept, pArgErrorIndex);
BTW, I am sure that the code can be vastly improved, it has been years since I have written in C++ and this is just a "first kick" at getting this working so no real error handling etc.
I have toyed around with "Args[]" type and value with variations of "Type Mismatch" errors and "Null Reference Pointers"
The function that is imported by the .tlb file looks like this:
short GetInterfaceVersion(short * nMajor, short * nMinor)
{
short result;
static BYTE parms[] = VTS_PI2 VTS_PI2 ;
InvokeHelper(0x178, DISPATCH_METHOD, VT_I2, (void*)&result, parms, nMajor, nMinor);
return result;
}
Oh, although I am passing in the "pMethodNameAndParamsInReverseOrder" as a parameter, I am just hard-coding it to get this one simple method working. Once I have it working with this and a few other methods, I am planning on making this generic to handle any methods implemented by the COM interface via IDispatch.
Any help would be appreciated mostly in getting this working but I would also appreciate any pointers on improving the code, I have mouch to learn in C++
Thank-You!
BTW, If this helps clarify things, theApp.pTriadView->pTriadItem->Catalog is the COM class I am implementing
EDIT:
Thanks to #HansPassant (see first comment) I see what I was missing. Unfortunately I have hit a downstream result of fixing that. The VARIANT "pResult" is coming back empty. I will continue to hunt that down now but any thoughts would be welcome :)

How to convert UnicodeString to BSTR?

I'm having a problem when calling OpenDatabase function (DAO). It's prototipe is:
virtual HRESULT STDMETHODCALLTYPE OpenDatabase(BSTR Name/*[in]*/, VARIANT Options/*[in,opt]*/,
VARIANT ReadOnly/*[in,opt]*/,
VARIANT Connect/*[in,opt]*/,
Dao_tlb::Database** ppDb/*[out,retval]*/) = 0; // [-1]
So, when I do this:
if(OpenDialog1->Execute() != true) return;
The selected filename is saved in OpenDialog1->FileName. Then I call the function above:
pDatabasePtr = pDBEngine->OpenDatabase(WideString(OpenDialog1->FileName).c_bstr(), myOpts, myRead, myCon);
and this works! But, the problem is when I try to set the filename to something else:
OpenDialog1->FileName = ParamStr(1); // OpenDatabase don't work in runtime - file not recognised!
or even set the filename inside a function:
pDatabasePtr = pDBEngine->OpenDatabase(WideString(L"SomeDB.mdb").c_bstr(), myOpts, myRead, myCon);
In both cases I get strange errors and never able to open a database. So, I probably convert UnicodeString/WideString to BSTR incorrectly.
So, why this function (OpenDatabase) works with
if(OpenDialog1->Execute() != true) return;
and does not work with
OpenDialog1->FileName = ParamStr(1);
How do I set the conversion correctly?
I found answer in here if anyone else needs it:
https://forums.embarcadero.com/thread.jspa?messageID=498776

WICPixelFormatGUID = {????????-????-????-????-????????????} gives on debugging

I am trying to display on a button click. i have written a code and i am sure it is correct.
On debuging i get the value of WICPixelFormatGUID = {????????-????-????-????-????????????} and guidPixelFormatSource = {CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC}. I don't know why i get these strange values??
My code is as follows-
HRESULT AMEPreviewHandler::ConvertBitmapSourceTo32bppHBITMAP(
IWICBitmapSource * pBitmapSource,
IWICImagingFactory * pImagingFactory,
HBITMAP * pStream)
//Pay Attention that this function is called from a static function by creating instance of the class (there is no problem in the function call . I have checked the value of the parameters while debugging and i am sure that its correct)
{
IWICBitmapSource *pBitmapSourceConverted = NULL;
WICPixelFormatGUID guidPixelFormatSource; /the problem here is here on debugging it gives strange value.
HRESULT hr = pBitmapSource->GetPixelFormat(&guidPixelFormatSource);
if (SUCCEEDED(hr) && (guidPixelFormatSource != GUID_WICPixelFormat32bppBGRA))
{
IWICFormatConverter *pFormatConverter;
hr = pImagingFactory->CreateFormatConverter(&pFormatConverter);
if (SUCCEEDED(hr))
{
.......And so on....
}
}
}
One more thing is when i run the same code from non-static function it works fine(but my situation is i have to call it on button click event and it is done by DialogProc()function (and it is static function) and i have no more option left so i created the instance of the class and using those instance and pointer i am calling this ConvertBitmapSourceTo32bppHBITMAP(by passing the parameter using instances which are intialized in contructor).
Any reasons for the strange value on debugging of the two ???

Get record set from stored procedure using C++ ADODB CommandPtr::Execute()

I'm trying to get a recordset from a stored procedure using ADODB.
Stored procedures get executeed successfully (Doing everything written in the SP), but the recordset count is "-1".
Here is what I'm doing (stored procedure has no parameters):
hr = ptrCom.CreateInstance(__uuidof(Command));
ptrCom->ActiveConnection = _connection;
ptrCom->CommandType = adCmdStoredProc;
ptrCom->CommandText = _bstr_t(_T("get_all_users"));
_variant_t vtEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
ADODB::_RecordsetPtr record_set;
HRESULT normal_hr = ptrCom->raw_Execute(&vtEmpty, &vtEmpty, adCmdStoredProc, &record_set);
int cnt = record_set->RecordCount; // PROBLEM: cnt == -1 :-(
Can anyone point out what am I doing wrong?
thanks!
Have you tried just calling Execute?
ptrCom->Execute(NULL, NULL, ADODB::adCmdStoredProc);
returns _RecordSetPtr.
You might also want to try:
after you set the connection.
ptrCom->ActiveConnection->PutCursorLocation(ADODB::adUseClient);

return array from com object

I want to pass a list of alarm names from COM to VBScript used in ASP pages. If the method name is GetAlarms, What would be the signature of the method?. The number of alarms returned by GetAlarms will vary.
Does VBScrip support Safe Array?
The declaration in the *.idl file would look like this:
[id(1)] HRESULT GetAlarms([out,retval] SAFEARRAY(VARIANT)* pAlarms);
The corresponding C++ method would look like this:
STDMETHODIMP CMyClass::GetAlarms(SAFEARRAY** pAlarms)
{
CComSafeArray<VARIANT> alarms(3);
CComVariant value;
value = L"First Alarm";
alarms.SetAt(0, value);
value = L"Second Alarm";
alarms.SetAt(1, value);
value = L"Third Alarm";
alarms.SetAt(2, value);
*pAlarms = alarms.Detach();
return S_OK;
}
And finally, here is a sample VBScript that uses the above method:
Set obj = CreateObject("MyLib.MyClass")
a = obj.GetAlarms
For i = 0 To UBound(a)
MsgBox a(i)
Next
In ASP, of course, you would use something else instead of MsgBox.