I am trying to modify an ActiveX control developed in Visual Studio 2008 to use it for a purpose for which it was not originally designed. I will be reusing at least 90% of its code. Therefore, I would like to begin by creating an identical control that uses different GUIDs. I tried to follow instructions I found here (a very old link, written in 2004), but when I tried to build my project, I got an assertion failure in ctlreg.cpp line 113. Then, I restored all my changed files back to their original states, and for each GUID is the .odl file, I searched for the GUID in my .cpp and .h files and changed it wherever I found it. I also made sure to change my major version number. I still get the assertion failure. What else should I be doing?
Here's the code from ctlreg.cpp from the start of the method containing the assertion to the assertion itself:
BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
LPCTSTR pszFileName, LPCTSTR pszHelpDir)
{
BOOL bSuccess = FALSE;
CStringW strPathNameW;
wchar_t *szPathNameW = strPathNameW.GetBuffer(_MAX_PATH);
::GetModuleFileNameW(hInstance, szPathNameW, _MAX_PATH);
strPathNameW.ReleaseBuffer();
LPTYPELIB ptlib = NULL;
// If a filename was specified, replace final component of path with it.
if (pszFileName != NULL)
{
int iBackslash = strPathNameW.ReverseFind('\\');
if (iBackslash != -1)
strPathNameW = strPathNameW.Left(iBackslash+1);
strPathNameW += pszFileName;
}
if (SUCCEEDED(LoadTypeLib(strPathNameW.GetString(), &ptlib)))
{
ASSERT_POINTER(ptlib, ITypeLib);
LPTLIBATTR pAttr;
GUID tlidActual = GUID_NULL;
if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
{
ASSERT_POINTER(pAttr, TLIBATTR);
tlidActual = pAttr->guid;
ptlib->ReleaseTLibAttr(pAttr);
}
// Check that the guid of the loaded type library matches
// the tlid parameter.
ASSERT(IsEqualGUID(tlid, tlidActual));
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);
I want to copy multiple files using IFileOperation.
Copy a single file is not a problem like this example:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775761%28v=vs.85%29.aspx
My Problem is that I don't find a way to copy multiple files like *.txt.
I have tried using SHCreateShellItemArrayFromIDLists, like this snippet:
IShellItem *psiTo = NULL;
HRESULT hr = SHCreateItemFromParsingName( csTarget, NULL, IID_PPV_ARGS(&psiTo) );
LPCITEMIDLIST pidlFiles = ILCreateFromPath(csSource);
UINT count = sizeof(pidlFiles);
IShellItemArray* psiaFiles = NULL;
hr = SHCreateShellItemArrayFromIDLists(count, &pidlFiles, &psiaFiles);
hr = pfo->CopyItems(psiaFiles, psiTo);
hr = pfo->PerformOperations();
A other way is to use SHCreateShellItemArray, like this:
LPCITEMIDLIST pidlParent = ILCreateFromPath(_T("C:\\"));
LPCITEMIDLIST pidlChild = ILCreateFromPath(_T("C:\\Temp\\*.txt"));
HRESULT hr = SHCreateShellItemArray(pidlParent, NULL, 1, &pidlChild, &psiaFiles);
hr = pfo->CopyItems(psiaFiles, psiTo);
hr = pfo->PerformOperations();
I tried different way but almost I get E_INVALIDIDARG or ERROR_PATH_NOT_FOUND.
Whats wrong?
ILCreateFromPath doesn't take wildcards. Couldn't, since it returns a single PIDLIST_ABSOLUTE.
The easiest solution is to enumerate all files manually FindFirstFile(*.txt), call CopyItem on each result, and then call PerformOperations once at the end.
As usual, the older Windows functions are better. SHFileOperation is ten times simpler and more capable to boot: it does support wildcards directly.
I want to get access to a sub object of a COM object. In my example I use the CANoe COM Server.
In my program I create a CAN interface to the CANoe Application. Here is an extract of my code so far and it does exactly what I want:
HRESULT result;
//prepare for COM handling...
result = CoInitialize(NULL);
//get CLSID of CANoe...
result = CLSIDFromProgID(L"CANoe.Application", &clsid);
if(SUCCEEDED(result))
{
//connect to COM interface of CANoe...
result = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, IID_IApplication, (void**) &pIApp);
if(SUCCEEDED(result))
{
qDebug() << "COM connection established";
}
else
{
qDebug() << "COM connection error";
}
}
else
{
qDebug() << "Error: CLSID";
}
Now I want to get access to a sub object of the COM Server. For example the Measurement object. I tried it with the method pIApp->get_UI()
IDispatch* pIDis;
IMeasurement* pIMeasurement;
result = pIApp->get_UI(&pIDis);
pIMeasurement = (IMeasurement*) pIDis;
The pointer to the COM object needs to be a pointer of the type IMeasurement, so I can use all the methods defined in the header file. But the method get_UI only supports pointer of the type IDispatch. I tried to cast the pointer from type IDispatch to IMeasurement. But the program crashs at runtime.
I also tried to create a new interface directly to the sub object:
result = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, IID_IMeasurement, (void**) &pIMeasurement);
But in this try in the variable result there is saved an error and I can't access the methods of the sub object Measurement.
Where is my mistake and how can I get access to the sub object?
Thank you for all answers and hints!
Thanks to #WhozCraig, #Hans Passant and #Eric Brown for the hints in the comments.
I was able to solve my problem with the following code:
IDispatch* pIDispatch;
//get pointer pIDispatch to Measurement object of CANoe...
result = pIApp->get_Measurement(&pIDispatch);
if(SUCCEEDED(result))
{
//pointer pIDispatch to pIMeasurement...
result = pIDispatch->QueryInterface(IID_IMeasurement, (void**) &pIMeasurement);
if(SUCCEEDED(result))
{
pIDispatch->Release();
//work with connection here...
pIMeasurement->Release();
}
}
I try to write a simple MFC - Word Automation to save for every 1 minute.
I follow this article : http://www.codeproject.com/KB/office/MSOfficeAuto.aspx
And this is what Im trying to implement , I'm new to COM so I think there's problem here:
my VBA is generated by Word 2010:
ActiveDocument.SaveAs2 FileName:="1.docx", FileFormat:=wdFormatXMLDocument _
, LockComments:=False, Password:="", AddToRecentFiles:=True, _
WritePassword:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
False, CompatibilityMode:=14
And my code to implement VBA code above :
{
COleVariant varName(L"b.docx");
COleVariant varFormat(L"wdFormatXMLDocument");
COleVariant varLockCmt((BYTE)0);
COleVariant varPass(L"");
COleVariant varReadOnly((BYTE)0);
COleVariant varEmbedFont((BYTE)0);
COleVariant varSaveNativePicFormat((BYTE)0);
COleVariant varForms((BYTE)0);
COleVariant varAOCE((BYTE)0);
VARIANT x;
x.vt = VT_I4;
x.lVal = 14;
COleVariant varCompability(&x);;
VARIANT result;
VariantInit(&result);
_hr=OLEMethod( DISPATCH_METHOD, &result, pDocApp, L"SaveAs2",10,
varName.Detach(),varFormat.Detach(),varLockCmt.Detach(),varPass.Detach(),varReadOnly.Detach(),
varEmbedFont.Detach(),varSaveNativePicFormat.Detach(),varForms.Detach(),varAOCE.Detach(),varCompability.Detach()
);
}
I get no error from this one, but it doesn't work.
The VBA syntax uses named parameters where the order and count of the parameters do not matter. However, when calling from C++ you need to pass the required number of parameters in the right order.
SaveAs2 is defined as:
void SaveAs2(
ref Object FileName,
ref Object FileFormat,
ref Object LockComments,
ref Object Password,
ref Object AddToRecentFiles,
ref Object WritePassword,
ref Object ReadOnlyRecommended,
ref Object EmbedTrueTypeFonts,
ref Object SaveNativePictureFormat,
ref Object SaveFormsData,
ref Object SaveAsAOCELetter,
ref Object Encoding,
ref Object InsertLineBreaks,
ref Object AllowSubstitutions,
ref Object LineEnding,
ref Object AddBiDiMarks,
ref Object CompatibilityMode
)
So, it has 17 parameters which means you should specify them all if you are going to pass CompatibilityMode, which was specified as 10th parameter in your example (that corressponds to SaveFormsData).
If you do not need all the parameters, or just for testing, you can try a simpler code:
_hr = OLEMethod(DISPATCH_METHOD, &result, pDocApp, L"SaveAs2", 2, varName.Detach(), varFormat.Detach());
If you need the rest of the parameters, you need to pass all the parameters up to the parameter you need set. In that case, you can pass
COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
for the parameters you do not like to set.
Edit - Test Code
This works for me:
CoInitialize(NULL);
CLSID clsid;
IDispatch *pWApp;
HRESULT hr = CLSIDFromProgID(L"Word.Application", &clsid);
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pWApp);
hr = OLEMethod(DISPATCH_PROPERTYPUT, NULL, pWApp, L"Visible", 1, COleVariant((long)1));
VARIANT result;
VariantInit(&result);
hr = OLEMethod(DISPATCH_PROPERTYGET, &result, pWApp, L"Documents", 0);
IDispatch *pDocs = result.pdispVal;
VARIANT result2;
VariantInit(&result2);
hr = OLEMethod(DISPATCH_METHOD, &result2, pDocs, L"Open", 1, COleVariant(L"D:\\Archive\\t1.docx"));
IDispatch *pDoc = result2.pdispVal;
VARIANT result3;
VariantInit(&result3);
hr = OLEMethod(DISPATCH_METHOD, &result3, pDoc, L"SaveAs2", 1, COleVariant(L"D:\\Archive\\t2.docx"));
CoUninitialize();
Change your variable varFormat from wdFormatXMLDocument to an integer of 12 (probably like you've done the varCompability variable). Also, what's the 10 for after "SaveAs2"?
Guess I'll start over since you opened the bounty.
Change your variable varFormat from wdFormatXMLDocument to an integer of 12 (probably like you've done the varCompability variable). wdFormatXMLDocument is an enum of WdSaveFormat and was introduced in Word 2003. There is no need to send in an L"name" - just send in the integer of 12.
If these are previously saved documents (i.e. not new ones), perform a conversion first to get it to the right format (like ActiveDocument.Convert)