Using an ocx in a console application - c++

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

Related

How to create a notification balloon on Windows?

I want to create a simple command line tool to post quick notifications like this.
I want the tool to be as simple and small as possible. So I choose to code in CPP, and use Win32 API directly.
I found this guide very useful. But it seems this Shell_NotifyIcon API requires a valid hWnd handler, which means I will have to create a hidden/invisible window in my command line tool, which I'd rather not.
Any better idea on how to create a notification on Windows?
The shell notification API requires that you supply a window handle. So create a message only window and use that as the owner of the notification icon and balloons.
That you would prefer not to create a window in your console app is understandable but the API is what it is. You don't get to re-write system APIs for your convenience. You just have to go along with them.
You can do that easily with no need to use ATL or MFC, just pure Win32 API, which can be a Console application as well.
First you need the icon image. Store it in your resource.h file
#define IDI_BATTERY_IMAGE 101
add an .rc file to your project with the following line
IDI_BATTERY_IMAGE ICON "Battery.ico"
Bonus tip: you can find free images to download, like this one. Just make sure to call it "Battery.ico" and place it in the path of your other source files.
Best if you create a separate pair of .cpp and .h files for the notification balloon functionality.
In your .cpp file place the following code:
// tray icon data
NOTIFYICONDATA m_NID;
BOOL CreateTrayIcon()
{
memset(&m_NID, 0, sizeof(m_NID));
m_NID.cbSize = sizeof(m_NID);
m_NID.uID = IDI_BATTERY_IMAGE;
// set handle to the window that receives tray icon notifications
m_NID.hWnd = GetForegroundWindow();
// fields that are being set when adding tray icon
m_NID.uFlags = NIF_MESSAGE | NIF_ICON;
// set image
m_NID.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_BATTERY_IMAGE));
if (!m_NID.hIcon)
return FALSE;
m_NID.uVersion = NOTIFYICON_VERSION_4;
if (!Shell_NotifyIcon(NIM_ADD, &m_NID))
return FALSE;
return Shell_NotifyIcon(NIM_SETVERSION, &m_NID);
}
BOOL ShowTrayIconBalloon(LPCTSTR pszTitle, LPCTSTR pszText, UINT unTimeout, DWORD dwInfoFlags)
{
m_NID.uFlags |= NIF_INFO;
m_NID.uTimeout = unTimeout;
m_NID.dwInfoFlags = dwInfoFlags;
if (StringCchCopy(m_NID.szInfoTitle, sizeof(m_NID.szInfoTitle), pszTitle) != S_OK)
return FALSE;
if (StringCchCopy(m_NID.szInfo, sizeof(m_NID.szInfo), pszText) != S_OK)
return FALSE;
return Shell_NotifyIcon(NIM_MODIFY, &m_NID);
}
In your header file place the following:
BOOL CreateTrayIcon();
BOOL ShowTrayIconBalloon(LPCTSTR pszTitle, LPCTSTR pszText, UINT unTimeout, DWORD dwInfoFlags);
In your main function add the following code:
CreateTrayIcon();
ShowTrayIconBalloon(L"27 percent remaining", L"Your battary has such and such percentage...", 1000, NULL);
The following code was tested with a simple Console app.

CreateDialog in BHO always fails with error 1813 (resource not found)

I'm working on a BHO written a long time ago in C++, without the use of any of the VS wizards. As a result, this project deviates from the COM conventions and the boilerplate for a COM product. I worked with COM long ago, but never really did any Windows GUI/dialog stuff...
I'm trying to add a dialog box to allow the user to set the values of some new settings:
// serverDialog will be NULL
HWND serverDialog = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PROPPAGE_SETTINGS), NULL, DialogProc);
id (!serverDialog)
{
int error = GetLastError(); //1813
...
}
....
1813 means that the resource cannot be found. The IDD used there is in resource.h, which I manually included where needed.
DialogProc is defined as:
INT_PTR CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return FALSE;
}
Which I know I will have to change later if I want the dialog to actually process messages, but I haven't gotten that far yet. The 1813 error suggests failure before the dialog is even created as does the NULL dialog handle returned.
To add the dialog I used the Add Resource wizard and added a small property page.
I've tried to follow advice here, but to no avail.
Thanks!
You are passing GetModuleHandle(NULL) as the instance of the module that contains the resource. But GetModuleHandle(NULL) defines the executable file module. You need to pass the instance of the module containing your code. This question covers that topic: How do I get the HMODULE for the currently executing code?
You probably ought to pass a window handle to the hWndParent parameter so that the dialog is owned.

Passing Data to Windows Console Control Handler

I am working on writing a simple game engine and I am having trouble handling Windows console events; specifically, I cannot figure out how to pass custom data to the callback handler.
I first call this code to specify my callback function:
SetConsoleCtrlHandler((PHANDLER_ROUTINE)WindowsSystemManager::ConsoleControlHandler, true);
My static-member callback function is defined as:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
if(controlType == CTRL_CLOSE_EVENT){
MessageBox(NULL, L"Close Event Captured", L"Close Event Captured", NULL);
}
return true;
}
Everything works fine - when I click on the close button in the console, this MessageBox pops up. Only problem is, I need to call code that flushes a logging buffer to a log file on this type of shutdown (as well as other clean-up), and the Logger instance is a member in my WindowsSystemManager.
I have dealt with a similar problem of passing custom data to window handles by using SetWindowLongPtr and GetWindowLongPtr successfully, but I can't find any information on how to do this type of thing with console control handlers. Any thoughts?
EDIT: I got this functionality working based on MSalters' suggestions. The final code for the console control handler is here:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
BerserkEngine* engine = (BerserkEngine*)GetWindowLongPtr(GetConsoleWindow(), GWLP_USERDATA);
if(controlType == CTRL_CLOSE_EVENT){
engine->~BerserkEngine();
PostQuitMessage(0);
}
return true;
}
Where I set this custom data pointer in the WindowsSystemManager constructor:
SetWindowLongPtr(GetConsoleWindow(), GWL_USERDATA, (LONG_PTR)this->engine);
I'm not sure why you'd need this. You can have multiple windows, but only one console.
However, GetConsoleWindow will give you the console HWND, on which you might call SetWindowLongPtr. Not very clean (you're not supposed to do this on windows that you don't manage), but it might just work.

how do I use find window and sendmessage in empty visual c++ project (or console app)

I want to make the most simplest application that can communicate via windows send messages (and parse json). I have found a sample code:
CWnd* pWnd = FindWindow("old title");
pWnd->SendMessage(WM_SETTEXT,0,(LPARAM)"New title");
That works... but only if I use MS Visual Studios "create new MFC form application" wizard. How can I make a console application that sends messages to my program? Or can I? What do I need to include/link if I start an empty project or console application?
The goal in pseudocode:
a = ""
while !EOF
a += read(stdin)
commandArray = jsonToArray(a)
CWnd* pWnd = FindWindow("program");
pWnd->SendMessage(WM_COPYDATASTRUCT,0,commandArrayWrappedInCOPYDATASTRUCT);
exit
The annoyance is that the effective part of the code is roughly 20 lines (above), but the wizard generated part is hundreds of lines. And most of them is stuff that I don't understand. Plus, I get a window that I don't need.
EDIT
Final main.cpp (without the json stuff):
/*
This closes calculator
*/
#include <Windows.h>
#include <atlstr.h>
int main (void)
{
HWND HWnd = FindWindow(NULL, CStringW("Calculator"));
SendMessage(HWnd, WM_CLOSE, 0, 0);
return 0;
}
br,
Juha
If you want something so simple, then I'd just forget all about MFC and start with a basic console app from the New Project Wizard. MFC seems rather heavy duty for something so simple.

How to keep global variable value unchanged in ATL project?

I need help on global variable usage in an ActiveX(ATL) project. Basically the ActiveX component function is to navigae to a specified URL in composite control(webbrowser embedded). The URL string is initialize in the beginning and saved in a global variable. here is my source code file of ActiveX project.
(Do not be concerned about the grammar, I just want to show the code flow).
MyComponentInit.cpp
// MyComponentInit.cpp : Implementation of MyComponentInit.cpp
#include "stdafx.h"
#include <ios>
char szURL[1024] = "\0"; // global variable holding URL string
STDMETHODIMP CMyComponentInit::InitPlugin(BSTR url)
{
// convert BSTR to string
......
memcpy(szURL, szUrl, len);
}
MyComponentCtrl.cpp
// MyComponentCtrl.cpp : Implementation of MyComponentCtrl.cpp
#include "stdafx.h"
extern char szURL[1024]
LRESULT CMyComponentCtrl::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
......
m_spWebbrowser->Navigate(szURL, &v, &v, &v, &v);
}
The use of mycomponent ActiveX is in a MFC SDI(Single Doc/View) test application. The flow is like:
In App Initinstance, I called activeX InitPlugin to initialize the URL string.
In a Information dialog window, insert MyComponentCtrl ActiveX, the Information dialog is brought up by clicking Mainframe Information menu item. The goal is when Information dialog window pop up, it can always go to the specified url.
After my MFC test app starts, I click Information dialog menu, the Information dialog window can be up and navigate to the url correctly.
But the problem is if I close the Information dialog, wait fro a while (around 2~3 minutes), I tried to bring up Information dialog again, it could not navigate to the URL. I debug it and found the global variable szURL in MyComponenet project lost its value.
Can you please tell me what should I do to resolve this problem?
Thanks a lot in advance!
Bionicoder
It looks like the application and COM might be releasing and reloading your DLL between the initialization call and the control being displayed. This could happen if the main app has no active instances of any of the DLL's COM components and subsequently calls CoFreeUnusedLibraries().
You can test that by putting a breakpoint or trace from DllMain for fdwReason == DLL_PROCESS_DETACH. If this is the problem, the breakpoint will trigger after the initialization call but before OnInitDialog().
If this is the problem, you can solve it by initializing the control instance with the URL directly, using instance state instead of using a global variable.
You can alternately keep a reference to the initialization interface for the lifetime of the application.