Using COM methods in console application - c++

i made a win32 console application that imports an ".ocx" file from geovision SDK. I found proper CLSID and interface ID of COM components in generated ".tli" and ".tlh" headers and everything works until i invoke any method(Login2 for example in my code below). Then _com_exception occurs and it gives no detailed info about what exactly happens.
Can anybody give me a hint what should i do next or where should i look for solution? It took me over a week to reach this point of using COM components in console application... I hope its possible to do it.
#include "stdafx.h"
#include "stdio.h"
#import "C:\Windows\GeoOCX\SinglePlayer\20121003\GVSinglePlayer.ocx" \
named_guids no_namespace no_smart_pointers
int _tmain(int argc, _TCHAR* argv[])
{
try
{
CoInitialize(NULL);
_DGVSinglePlayer* pSP = 0;
HRESULT hr = CoCreateInstance(CLSID_GVSinglePlayer ,NULL, CLSCTX_INPROC_SERVER,DIID__DGVSinglePlayer,reinterpret_cast <void**>(&pSP));
_bstr_t lpIPAddress("11.11.11.11");
long iPort=10000;
_bstr_t lpUserID("abcde");
_bstr_t lpPassword("password");
if ( SUCCEEDED ( hr ) )
{
hr = pSP->Login2(lpIPAddress,iPort,lpUserID,lpPassword );
if ( SUCCEEDED ( hr ) )
{
printf("Cool");
}
}else
{
}
pSP->Release();
CoUninitialize();
} catch (_com_error& e)
{
char buf[80];
sprintf(buf, "Error: %S",e.Description());
printf("%s\n",buf);
}
return 0;
}
Since e.Description() prints no info, I attatched visual info about the error.

Many ActiveX controls want to be properly hosted (meaning, the host implements IOleClientSite and related interfaces, and passes the pointer to the control's IOleObject::SetClientSite). Such controls return E_UNEXPECTED for all method calls until the OLE activation dance is performed.
In particular, ActiveX controls developed with MFC usually behave this way; the behavior is baked into MFC framework.
I suspect your control might be one of those. In this case, you wouldn't be able to use it easily in a console app. You would need a windowed application using a framework that implements ActiveX hosting (MFC, ATL, WinForms; others likely exist that I'm not familiar with).

Related

How may I bind a Toast progress bar with my C++ Win32 application?

I'm creating a c++ Win32 application which should show some Toast notifications. One of them contains a progress bar. I need to bind its value with my application in order to update it while the status changes in the currently running operation.
The Toast interface containing the progress bar is defined as follow:
<toast>
<visual>
<binding template='ToastGeneric'>
<text>Backup in progress</text>
<progress title='Working folder' value='0' status='Starting backup...' valueStringOverride='0/1 files' />
</binding>
</visual>
</toast>
To show the Toast notification I call the following function, by passing the above interface in the toastContent string:
bool ShowToastNotification(const std::wstring toastContent)
{
if (!toastContent.length())
return false;
// build XML
::CComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> pDoc;
HRESULT hr = DesktopNotificationManagerCompat::CreateXmlDocumentFromString(toastContent.c_str(), &pDoc);
if (FAILED(hr))
return false;
// create the notifier. Classic Win32 apps MUST use the Compat method to create the notifier
::CComPtr<ABI::Windows::UI::Notifications::IToastNotifier> pNotifier;
hr = DesktopNotificationManagerCompat::CreateToastNotifier(&pNotifier);
if (FAILED(hr))
return false;
// create the Toast notification (using helper method from Compat library)
::CComPtr<ABI::Windows::UI::Notifications::IToastNotification> pToast;
hr = DesktopNotificationManagerCompat::CreateToastNotification(pDoc, &pToast);
if (FAILED(hr))
return false;
// get access to IToastNotification4, which should contain the binding methods
::CComPtr<ABI::Windows::UI::Notifications::IToastNotification4> pToastData;
pToast->QueryInterface(ABI::Windows::UI::Notifications::IID_IToastNotification4, (void**)&pToastData);
ABI::Windows::UI::Notifications::INotificationData* pData = nullptr;
// FIXME how may I create a valid INotificationData here?
// bind the data with the interface
hr = pToastData->put_Data(pData);
if (FAILED(hr))
return false;
// show it
hr = pNotifier->Show(pToast);
if (FAILED(hr))
return false;
return true;
}
As you can see in the FIXME part above, there is a missing part to achieve the binding before showing the Toast notification, and unfortunately there is absolutely NO documentation from Microsoft which explain how to perform that in a simple C++ Win32 application. The below one explain clearly how to perform a such binding, but only in C#:
https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-progress-bar?tabs=builder-syntax
Even without documentation I could find that the IToastNotification4 seems to be a valid interface to attach a INotificationData container to my Toast, similar to what is done in the above mentioned documentation. However I don't know how to create a valid INotificationData instance. I saw that a CreateNotificationDataWithValuesAndSequenceNumber() function exists in the INotificationDataFactory interface, but same thing, I face a cruel miss of documentation about how to obtain a such interface.
Can someone explain me how I may bind my C++ Win32 application with my progress bar on my Toast notification, in order to send it messages to update its interface? Or can someone explain me how to get the above mentioned interfaces, in order to perform something similar to the above mentioned C# documentation? Or at least can someone point me a documentation which may give information about the INotificationData and INotificationDataFactory interfaces, and how to use them to perform the binding with my Toast progress bar?
If a WinRT class can be created from C#, it means it's activatable (or it's associated with another "statics" class which is), which you can check if you go to NotificationData documentation:
[Windows.Foundation.Metadata.Activatable(262144, "Windows.Foundation.UniversalApiContract")]
[Windows.Foundation.Metadata.Activatable(typeof(Windows.UI.Notifications.INotificationDataFactory), 262144, "Windows.Foundation.UniversalApiContract")]
[Windows.Foundation.Metadata.ContractVersion(typeof(Windows.Foundation.UniversalApiContract), 262144)]
[Windows.Foundation.Metadata.MarshalingBehavior(Windows.Foundation.Metadata.MarshalingType.Agile)]
[Windows.Foundation.Metadata.Threading(Windows.Foundation.Metadata.ThreadingModel.Both)]
public sealed class NotificationData
{...}
If it's activatable, then you just have to find it's activation class id, and call RoActivateInstance . The class id is visible in the corresponding .h file (here windows.ui.notifications.h) and it's usually very straightforward: <namespace> + '.' + <class name>:
...
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_Windows_UI_Notifications_NotificationData[] = L"Windows.UI.Notifications.NotificationData";
...
So here is how you can create it:
HRESULT CreateNotificationData(INotificationData** data)
{
if (!data)
return E_INVALIDARG;
*data = nullptr;
IInspectable* instance;
auto hr = RoActivateInstance(HStringReference(RuntimeClass_Windows_UI_Notifications_NotificationData).Get(), &instance);
if (FAILED(hr))
return hr;
hr = instance->QueryInterface(data);
instance->Release();
return hr;
}
PS: using C++/WinRT is usually easier to use than ATL, WRL or WIL for WinRT types.

How to launch OneNote and bring it to the foreground using OLE automation?

I've been struggling bringing OneNote to the foreground using OLE automation. When I run the following code, OneNote loads in the background and I'm not able to bring it to the foreground. I haven't had any problems trying to launch and bring Word, Excel, PowerPoint and Edge to the foreground, however OneNote behaves different. There is very little info about OneNote being automated using OLE and some pages are not longer exist.
Any help would be appreciated. You can download the Onenote14-x86.h file from here
#include "stdafx.h"
#include "onenote14-x86.h"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
IApplication* piOneNote;
CoCreateInstance(__uuidof(Application), NULL, CLSCTX_LOCAL_SERVER, __uuidof(IApplication), (void**)&piOneNote);
if(piOneNote)
{
BSTR temp;
HRESULT hr = piOneNote->GetHierarchy(NULL, hsNotebooks, &temp);
}
}
You can create a new windows with this call
piOneNote->NavigateTo(NULL, NULL, VARIANT_TRUE);

Executing "Show Desktop" from C++

I am designing a system where the user makes a gesture, then my program captures it (using a web cam) and my program looks in a rule system (based on XML) which are the actions that it has to do.
Ok, once I have explained the background, I'd like to know how I could make my program "execute" the Show Desktop button. I'd like to provide the user the possibility to do a gesture and show the desktop. Is it possible? I have been looking the program (.exe) that executes the Show Desktop button and I am afraid that does not exist.
From this MSDN blog post (dated 2004 but surely still valid), you must call ToggleDesktop().
in C#:
// Create an instance of the shell class
Shell32.ShellClass objShel = new Shell32.ShellClass();
// Show the desktop
((Shell32.IShellDispatch4) objShel).ToggleDesktop();
// Restore the desktop
((Shell32.IShellDispatch4) objShel).ToggleDesktop();
EDIT
C++ version:
#include <Shldisp.h>
CoInitialize(NULL);
// Create an instance of the shell class
IShellDispatch4 *pShellDisp = NULL;
HRESULT sc = CoCreateInstance( CLSID_Shell, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pShellDisp );
// Show the desktop
sc = pShellDisp->ToggleDesktop();
// Restore the desktop
sc = pShellDisp->ToggleDesktop();
pShellDisp->Release();
From http://www.codeguru.com/forum/showthread.php?t=310202:
#define MIN_ALL 419
#define MIN_ALL_UNDO 416
int main(int argc, char* argv[])
{
HWND lHwnd = FindWindow("Shell_TrayWnd",NULL);
SendMessage(lHwnd,WM_COMMAND,MIN_ALL,0); // Minimize all windows
Sleep(2000);
SendMessage(lHwnd,WM_COMMAND,MIN_ALL_UNDO,0); // Bring all back up again.
return 0;
}
Hope it helps. It at least does what it should, minimizes all the windows aka. shows desktop.
You need to call ToggleDesktop.
In Windows you can copy the script:
[Shell]
Command=2
IconFile=explorer.exe,3
[Taskbar]
Command=ToggleDesktop
into a file "somefile.scf" and invoke it from the shell by executing "somefile.scf" by hand. This is also possible with C++.

How to prevent crashing if com dll isnt registered

From some old c++ code im trying to use a com dll, it works fine when the dll is registered, but it crahses if the dll isnt registered.
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
IGetTestPtr ptest(__uuidof(tester));
"Use method from the dll"
// Uninitialize COM.
CoUninitialize();
Is it anyway to check if the dll has been registered, before calling IGetTestPtr ptest(__uuidof(tester))?
Or what is the correct way to prevent the crash?
Calling CreateInstance on your object will return an HRESULT that can be tested for success:
IGetTestPtr p = null;
HRESULT hRes = p.CreateInstance( __uuidof(tester) );
bool bSuccess = SUCCEEDED(hRes);
This assumes you've created an interface wrapper around your type library using Visual Studio, where COM Smart Pointers are used in the interface (this gives you the CreateInstance method).
If the DLL is registered, there is a record in HKCR/CLSID/{uuidof(tester)} (curly brackets do matter).
Actually, if it's not, then CoCreateInstance will return an error. Check for this error before using the pointer.
If the COM class is not registered then CoCreateInstance will return REGDB_E_CLASSNOTREG. You should check for general success or failure by using the SUCCEEDED() or FAILED() macros. You also need to create the object properly - see MDSN for an introduction to COM. For example:
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
IGetTestPtr ptr = NULL;
hr = CoCreateInstance(CLSID_MyObjectNULL, CLSCTX_INPROC_SERVER, IID_IMyInterface, ptr)
if (SUCCEEDED(hr))
{
Do something with your COM object
...
// Don't forget to release your interface pointer or the object will leak
ptr->Release();
}
hr = CoUninitialize();
}
return hr;
If I recall correctly this "#import" styled COM framework throws exceptions. Add a try-catch block around the code. Google tells me the exceptions are of type _com_error.
Unless you twiddle the params on #import to prevent this, all failing COM calls are going to throw exceptions. You're going to have to turn this off (#import "raw" interfaces I think does it - look at the #import docs) or get real familiar with these exceptions.

Using an ocx in a console application

I want to quickly test an ocx. How do I drop that ocx in a console application. I have found some tutorials in CodeProject and but are incomplete.
Isn't an OCX an ActiveX User Control? (something that you put onto a form for the user to interact with)?
The easiest way I know of to test COM/ActiveX stuff is to use excel. (Yes I know it sounds dumb, bear with me)
Run Excel, create a new file if it hasn't done this for you
Press Alt+F11 to launch the Visual Basic Editor (if you have excel 2007 it's on the 'Developer' ribbon tab thing
Now that you're in happy visual basic land...
From the Tools menu, select References
Select your OCX/COM object from the list, or click Browse... to find the file if it's not registered with COM - You may be able to skip this step if your OCX is already registered.
From the Insert menu, select UserForm
In the floating Toolbox window, right click and select Additional Controls
Find your OCX in the list and tick it
You can then drag your OCX from the toolbox onto the userform
From the Run menu, run it.
Test your OCX and play around with it.
SAVE THE EXCEL FILE so you don't have to repeat these steps every time.
Sure..it's pretty easy. Here's a fun app I threw together. I'm assuming you have Visual C++.
Save to test.cpp and compile: cl.exe /EHsc test.cpp
To test with your OCX you'll need to either #import the typelib and use it's CLSID (or just hard-code the CLSID) in the CoCreateInstance call. Using #import will also help define any custom interfaces you might need.
#include "windows.h"
#include "shobjidl.h"
#include "atlbase.h"
//
// compile with: cl /EHsc test.cpp
//
// A fun little program to demonstrate creating an OCX.
// (CLSID_TaskbarList in this case)
//
BOOL CALLBACK RemoveFromTaskbarProc( HWND hwnd, LPARAM lParam )
{
ITaskbarList* ptbl = (ITaskbarList*)lParam;
ptbl->DeleteTab(hwnd);
return TRUE;
}
void HideTaskWindows(ITaskbarList* ptbl)
{
EnumWindows( RemoveFromTaskbarProc, (LPARAM) ptbl);
}
// ============
BOOL CALLBACK AddToTaskbarProc( HWND hwnd, LPARAM lParam )
{
ITaskbarList* ptbl = (ITaskbarList*)lParam;
ptbl->AddTab(hwnd);
return TRUE;// continue enumerating
}
void ShowTaskWindows(ITaskbarList* ptbl)
{
if (!EnumWindows( AddToTaskbarProc, (LPARAM) ptbl))
throw "Unable to enum windows in ShowTaskWindows";
}
// ============
int main(int, char**)
{
CoInitialize(0);
try {
CComPtr<IUnknown> pUnk;
if (FAILED(CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**) &pUnk)))
throw "Unabled to create CLSID_TaskbarList";
// Do something with the object...
CComQIPtr<ITaskbarList> ptbl = pUnk;
if (ptbl)
ptbl->HrInit();
HideTaskWindows(ptbl);
MessageBox( GetDesktopWindow(), _T("Check out the task bar!"), _T("StackOverflow FTW"), MB_OK);
ShowTaskWindows(ptbl);
}
catch( TCHAR * msg ) {
MessageBox( GetDesktopWindow(), msg, _T("Error"), MB_OK);
}
CoUninitialize();
return 0;
}
#orion thats so cool. Never thought of it that way.
Well #jschroedl thats was fun indeed.
Testing an activex in console app is fun. But I think its worth not trying down that path. You can call the methods or set and get the properties either through the way #jschroedl had explained or you can call the IDIspatch object through the Invoke function.
The first step is to GetIDsByName and call the function through Invoke and parameters to the function should be an array of VARIANTS in the Invoke formal parameter list.
All is fine and dandy. But once you get to events its downhill from there. Windows application requires a message pump to fire events. On a console you don't have one. I went down the path to implement a EventNotifier for the events just like you implement a CallBack interface in classic C++ way. But the events doesn't get to your implemented interface.
I am pretty sure this cannot be done on a console application. But I am really hoping someone out there will have a different take on events in a console application