Making a program using COM in windows

Pages: 123
I am trying to make a program using COM.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <windows.h>
#include <Objbase.h>
#include <Unknwn.h>
using namespace std;

int main(){
	CLSID ClassID;
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	CLSIDFromProgID(OLESTR("InternetExplorer.Application"),&ClassID); //Gets Class ID
	IUnknown* Unknown;
	REFIID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}}; //without this is says that IID_IUnknown is undefined
	HRESULT hr = CoCreateInstance(ClassID, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **) &Unknown);
	//Now there should be an internet explorer window opening
	if(hr == S_OK)
		MessageBox(NULL,"S_OK","Title", MB_OK);
	else if(hr == REGDB_E_CLASSNOTREG)
		MessageBox(NULL,"REGDB_E_CLASSNOTREG","Title", MB_OK); //This is what I keep getting
	else if(hr == CLASS_E_NOAGGREGATION)
		MessageBox(NULL,"CLASS_E_NOAGGREGATION","Title", MB_OK);
	else if(hr == E_NOINTERFACE)
		MessageBox(NULL,"E_NOINTERFACE","Title", MB_OK);
	else if(hr == E_POINTER)
		MessageBox(NULL,"E_POINTER","Title", MB_OK);
	CoUninitialize();
        return 0;
}


My final goal is being able to use COM objects by just knowing their ProgID and nothing else, like I have seen a scriping language do.

thanks
Last edited on
I'd recommend you test HRESULT hr for success/failure after each call to a function where an HRESULT is returned, e.g.,

1
2
3
4
5
6
7
8
9
hr=CLSIDFromProgID(....);
if(SUCCEEDED(hr))
{
   // code if it works...
}
else
{
   // and if it doesn't
}


Your specific problem above is that "InternetExplorer.Application" likely isn't an in process server as specified by CLSCTX_INPROC_SERVER, but rather an out of process local server, i.e., an exe.

However and for sure, the full functionality of Internet Explorer is contained within a COM dll or 'in process server' named ...

"Shell.Explorer"

You can look that up in RegEdit under HKEY_CLASSES_ROOT.

I have posted here already code that shows how to load Microsoft's Web Browser Control within a host app. I could find it for you or repost it I guess.

What you are trying to do though might work if you take care of the items I specified above.
Right now I'm posting this after creating a basic Win32 GUI Host app which hosts the "Shell.Explorer" ActiveX Control which is the heart of Microsoft Internet Explorer. I'm using that app to log in and post here - in other words. This is quite involved and will require several posts to complete, but I'll post all the code necessary. I used Mingw 4.4 from Code::Blocks 10.05 to create the executable. I did that on a Win64 machine with XP Mode installed, so its a 32 bit executable. Here's the code. First the Main.cpp main source code file...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#define  UNICODE                                              //Main.cpp - Web Browser Demo
#define  _UNICODE
#include <windows.h>
#include <tchar.h>
#include <cstdio>
#include "Main.h"
#include "IWebBrowser.h"
const IID IID_WebExplorer  = {0xEAB22AC1,0x30C1,0x11CF,{0xA7,0xEB,0x00,0x00,0xC0,0x5B,0xAE,0x0B}};
HINSTANCE hAtlIns          = NULL;


struct StartOLEProcess                                        // The reason this strange thing - 'StartOLEProcess' is here is that in testing this
{                                                             // thing with Windows 2000/XP I was getting crashes at program termination, i.e., 'x'ing
 StartOLEProcess()                                            // out to end program, caused presumably by either CoUninitialize() or FreeLibrary() not
 {                                                            // synchronizing well with this process's termination code.  So note here that an
  TCHAR szBuffer[256];                                        // instance of StartOLEProcess named 'InitializeOLE' will be created before WinMain()
  CoInitialize(NULL);                                         // even starts, and its destructor will be called after WinMain() exits.  I put the
  GetCurrentDirectory(256,szBuffer);                          // CoInitialize(), LoadLibrary(), CoUninitialize(), and FreeLibrary() calls in this
  _tcscat(szBuffer,_T("\\Atl71.dll"));                          // object's Constructor and Destructor calls, and that seemed to solve the problem.  One
  hAtlIns=LoadLibrary(szBuffer);                              // does what one must, I suppose!
 }

 ~StartOLEProcess()
 {
  CoUninitialize();
  if(hAtlIns)
     FreeLibrary(hAtlIns);
 }
}InitializeOLE;


long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
 PFNATLAXCREATECONTROL pAtlCreateControl=NULL;
 PFNATLAXGETCONTROL pAtlAxGetControl=NULL;
 PFNATLAXWININIT pAtlAxWinInit=NULL;
 IUnknown* ppUnkContainer=NULL;
 IWebBrowser* pWebBrowser=NULL;
 IUnknown* pUnkIExplorer=NULL;
 HWND hCtrl,hContainer;
 BSTR strProgId;
 HRESULT hr;

 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
 hContainer=CreateWindow(_T("static"),_T(""),WS_CHILD|WS_VISIBLE,0,35,1180,750,Wea->hWnd,(HMENU)ID_CONTAINER,Wea->hIns,0);
 if(hAtlIns)
 {
    pAtlAxWinInit=(PFNATLAXWININIT)GetProcAddress(hAtlIns,"AtlAxWinInit");
    if(pAtlAxWinInit)
    {
       hr=pAtlAxWinInit();
       if(SUCCEEDED(hr))
       {
          pAtlCreateControl=(PFNATLAXCREATECONTROL)GetProcAddress(hAtlIns,"AtlAxCreateControl");
          if(pAtlCreateControl)
          {
             strProgId=SysAllocString(_T("Shell.Explorer"));
             hr=pAtlCreateControl(strProgId,hContainer,NULL,&ppUnkContainer);
             if(SUCCEEDED(hr))
             {
                SetWindowLong(Wea->hWnd,0,(long)ppUnkContainer);
                pAtlAxGetControl=(PFNATLAXGETCONTROL)GetProcAddress(hAtlIns,"AtlAxGetControl");
                if(pAtlAxGetControl)
                {
                   hr=pAtlAxGetControl(hContainer,&pUnkIExplorer);
                   if(SUCCEEDED(hr))
                   {
                      SetWindowLong(Wea->hWnd,4,(long)pUnkIExplorer);
                      hr=pUnkIExplorer->QueryInterface(IID_WebExplorer,(void**)&pWebBrowser);
                      if(SUCCEEDED(hr))
                         SetWindowLong(Wea->hWnd,8,(long)pWebBrowser);
                      else
                         return 0;
                      hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,5,5,1000,25,Wea->hWnd,(HMENU)ID_URL,Wea->hIns,0);
                      hCtrl=CreateWindow(_T("button"),_T("Navigate"),WS_CHILD|WS_VISIBLE,1050,5,80,25,Wea->hWnd,(HMENU)BTN_NAVIGATE,Wea->hIns,0);
                   }
                }
             }
          }
       }
    }
 }
 else
    MessageBox(Wea->hWnd,L"Couldn't Load Atl71.dll",L"Failure",MB_ICONERROR);

 return 0;
}


long fnWndProc_OnCommand(lpWndEventArgs Wea)
{
 if(LOWORD(Wea->wParam)==BTN_NAVIGATE)
 {
    TCHAR szBuffer[256];
    HWND hEdit=GetDlgItem(Wea->hWnd,ID_URL);
    GetWindowText(hEdit,szBuffer,256);
    IWebBrowser* pWebBrowser=NULL;
    pWebBrowser=(IWebBrowser*)GetWindowLong(Wea->hWnd,8);
    BSTR strUrl;
    strUrl=SysAllocString(szBuffer);
    if(pWebBrowser)
       pWebBrowser->Navigate(strUrl,NULL,NULL,NULL,NULL);
    SysFreeString(strUrl);
 }

 return 0;
}


long fnWndProc_OnDestroy(lpWndEventArgs Wea)
{
 IUnknown* pUnkIExplorer=NULL;
 IUnknown* ppUnkContainer=NULL;
 IWebBrowser* pWebBrowser=NULL;

 pWebBrowser=(IWebBrowser*)GetWindowLong(Wea->hWnd,8);
 if(pWebBrowser)
    pWebBrowser->Release();
 pUnkIExplorer=(IUnknown*)GetWindowLong(Wea->hWnd,4);
 if(pUnkIExplorer)
    pUnkIExplorer->Release();
 ppUnkContainer=(IUnknown*)GetWindowLong(Wea->hWnd,0);
 if(ppUnkContainer)
    ppUnkContainer->Release();
 PostQuitMessage(0);

 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{

 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("Form1");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=12;
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,100,15,1200,830,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}

Here is Main.h...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//Main.h
#ifndef Main_h
#define Main_h

#define dim(x) (sizeof(x) / sizeof(x[0]))
typedef HRESULT (__stdcall* PFNATLAXWININIT)(void);
typedef HRESULT (__stdcall* PFNATLAXCREATECONTROL)(LPCOLESTR lpszName, HWND hWnd, IStream* pStream, IUnknown** ppUnkContainer);
typedef HRESULT (__stdcall* PFNATLAXGETCONTROL)(HWND hContainer, IUnknown** ppIUnknown);

typedef struct WindowsEventArguments
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
}WndEventArgs, *lpWndEventArgs;

long fnWndProc_OnCreate       (lpWndEventArgs Wea);
long fnWndProc_OnCommand      (lpWndEventArgs Wea);
long fnWndProc_OnDestroy      (lpWndEventArgs Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(lpWndEventArgs);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};

#define ID_CONTAINER          1250
#define BTN_NAVIGATE          1255
#define ID_URL                1265

#endif 
1st part of IWebBrowser.h...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#ifndef SHDocVw_h
#define SHDocVw_h

typedef interface IWebBrowser IWebBrowser;
typedef interface DWebBrowserEvents DWebBrowserEvents;
typedef interface IWebBrowserApp IWebBrowserApp;
typedef interface IWebBrowser2 IWebBrowser2;
typedef interface DWebBrowserEvents2 DWebBrowserEvents2;
typedef interface DShellWindowsEvents DShellWindowsEvents;
typedef interface IShellWindows IShellWindows;
typedef interface IShellUIHelper IShellUIHelper;
typedef interface IShellUIHelper2 IShellUIHelper2;
typedef interface IShellUIHelper3 IShellUIHelper3;
typedef interface DShellNameSpaceEvents DShellNameSpaceEvents;
typedef interface IShellFavoritesNameSpace IShellFavoritesNameSpace;
typedef interface IShellNameSpace IShellNameSpace;
typedef interface IScriptErrorList IScriptErrorList;


typedef enum CommandStateChangeConstants
{
 CSC_UPDATECOMMANDS              = -1,
 CSC_NAVIGATEFORWARD             = 1,
 CSC_NAVIGATEBACK                = 2
}CommandStateChangeConstants;


typedef enum OLECMDID
{
 OLECMDID_OPEN                   = 1,
 OLECMDID_NEW                    = 2,
 OLECMDID_SAVE                   = 3,
 OLECMDID_SAVEAS                 = 4,
 OLECMDID_SAVECOPYAS             = 5,
 OLECMDID_PRINT                  = 6,
 OLECMDID_PRINTPREVIEW           = 7,
 OLECMDID_PAGESETUP              = 8,
 OLECMDID_SPELL                  = 9,
 OLECMDID_PROPERTIES             = 10,
 OLECMDID_CUT                    = 11,
 OLECMDID_COPY                   = 12,
 OLECMDID_PASTE                  = 13,
 OLECMDID_PASTESPECIAL           = 14,
 OLECMDID_UNDO                   = 15,
 OLECMDID_REDO                   = 16,
 OLECMDID_SELECTALL              = 17,
 OLECMDID_CLEARSELECTION         = 18,
 OLECMDID_ZOOM                   = 19,
 OLECMDID_GETZOOMRANGE           = 20,
 OLECMDID_UPDATECOMMANDS         = 21,
 OLECMDID_REFRESH                = 22,
 OLECMDID_STOP                   = 23,
 OLECMDID_HIDETOOLBARS           = 24,
 OLECMDID_SETPROGRESSMAX         = 25,
 OLECMDID_SETPROGRESSPOS         = 26,
 OLECMDID_SETPROGRESSTEXT        = 27,
 OLECMDID_SETTITLE               = 28,
 OLECMDID_SETDOWNLOADSTATE       = 29,
 OLECMDID_STOPDOWNLOAD           = 30,
 OLECMDID_ONTOOLBARACTIVATED     = 31,
 OLECMDID_FIND                   = 32,
 OLECMDID_DELETE                 = 33,
 OLECMDID_HTTPEQUIV              = 34,
 OLECMDID_HTTPEQUIV_DONE         = 35,
 OLECMDID_ENABLE_INTERACTION     = 36,
 OLECMDID_ONUNLOAD               = 37,
 OLECMDID_PROPERTYBAG2           = 38,
 OLECMDID_PREREFRESH             = 39,
 OLECMDID_SHOWSCRIPTERROR        = 40,
 OLECMDID_SHOWMESSAGE            = 41,
 OLECMDID_SHOWFIND               = 42,
 OLECMDID_SHOWPAGESETUP          = 43,
 OLECMDID_SHOWPRINT              = 44,
 OLECMDID_CLOSE                  = 45,
 OLECMDID_ALLOWUILESSSAVEAS      = 46,
 OLECMDID_DONTDOWNLOADCSS        = 47,
 OLECMDID_UPDATEPAGESTATUS       = 48,
 OLECMDID_PRINT2                 = 49,
 OLECMDID_PRINTPREVIEW2          = 50,
 OLECMDID_SETPRINTTEMPLATE       = 51,
 OLECMDID_GETPRINTTEMPLATE       = 52,
 OLECMDID_PAGEACTIONBLOCKED      = 55,
 OLECMDID_PAGEACTIONUIQUERY      = 56,
 OLECMDID_FOCUSVIEWCONTROLS      = 57,
 OLECMDID_FOCUSVIEWCONTROLSQUERY = 58,
 OLECMDID_SHOWPAGEACTIONMENU     = 59,
 OLECMDID_ADDTRAVELENTRY         = 60,
 OLECMDID_UPDATETRAVELENTRY      = 61,
 OLECMDID_UPDATEBACKFORWARDSTATE = 62,
 OLECMDID_OPTICAL_ZOOM           = 63,
 OLECMDID_OPTICAL_GETZOOMRANGE   = 64,
 OLECMDID_WINDOWSTATECHANGED     = 65,
 OLECMDID_ACTIVEXINSTALLSCOPE    = 66,
 OLECMDID_UPDATETRAVELENTRY_DATARECOVERY= 67
}OLECMDID;


typedef enum OLECMDF
{
 OLECMDF_SUPPORTED               = 1,
 OLECMDF_ENABLED                 = 2,
 OLECMDF_LATCHED                 = 4,
 OLECMDF_NINCHED                 = 8,
 OLECMDF_INVISIBLE               = 16,
 OLECMDF_DEFHIDEONCTXTMENU       = 32
}OLECMDF;


typedef enum OLECMDEXECOPT
{
 OLECMDEXECOPT_DODEFAULT         = 0,
 OLECMDEXECOPT_PROMPTUSER        = 1,
 OLECMDEXECOPT_DONTPROMPTUSER    = 2,
 OLECMDEXECOPT_SHOWHELP          = 3
}OLECMDEXECOPT;


typedef enum tagREADYSTATE
{
 READYSTATE_UNINITIALIZED        = 0,
 READYSTATE_LOADING              = 1,
 READYSTATE_LOADED               = 2,
 READYSTATE_INTERACTIVE          = 3,
 READYSTATE_COMPLETE             = 4
}tagREADYSTATE;


typedef enum SecureLockIconConstants
{
 secureLockIconUnsecure          = 0,
 secureLockIconMixed             = 1,
 secureLockIconSecureUnknownBits = 2,
 secureLockIconSecure40Bit       = 3,
 secureLockIconSecure56Bit       = 4,
 secureLockIconSecureFortezza    = 5,
 secureLockIconSecure128Bit      = 6
}SecureLockIconConstants;


typedef enum NewProcessCauseConstants
{
 ProtectedModeRedirect           = 1
}NewProcessCauseConstants;


typedef enum ShellWindowTypeConstants
{
 SWC_EXPLORER                    = 0,
 SWC_BROWSER                     = 1,
 SWC_3RDPARTY                    = 2,
 SWC_CALLBACK                    = 4,
 SWC_DESKTOP                     = 8
}ShellWindowTypeConstants;


typedef enum ShellWindowFindWindowOptions
{
 SWFO_NEEDDISPATCH               = 1,
 SWFO_INCLUDEPENDING             = 2,
 SWFO_COOKIEPASSED               = 4
}ShellWindowFindWindowOptions;


interface IWebBrowser : IDispatch
{
 virtual HRESULT __stdcall GoBack(void)=0;
 virtual HRESULT __stdcall GoForward(void)=0;
 virtual HRESULT __stdcall GoHome(void)=0;
 virtual HRESULT __stdcall GoSearch(void)=0;
 virtual HRESULT __stdcall Navigate(BSTR URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers)=0;
 virtual HRESULT __stdcall Refresh(void)=0;
 virtual HRESULT __stdcall Refresh2(VARIANT* Level)=0;
 virtual HRESULT __stdcall Stop(void)=0;
 virtual HRESULT __stdcall GetApplication(IDispatch** ppDisp)=0;
 virtual HRESULT __stdcall GetParent(IDispatch** ppDisp)=0;
 virtual HRESULT __stdcall GetContainer(IDispatch** ppDisp)=0;
 virtual HRESULT __stdcall GetDocument(IDispatch** ppDisp)=0;
 virtual HRESULT __stdcall GetTopLevelContainer(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall GetType(BSTR* Type)=0;
 virtual HRESULT __stdcall GetLeft(LONG* pl)=0;
 virtual HRESULT __stdcall SetLeft(LONG pl)=0;
 virtual HRESULT __stdcall GetTop(LONG* pl)=0;
 virtual HRESULT __stdcall SetTop(LONG pl)=0;
 virtual HRESULT __stdcall GetWidth(LONG* pl)=0;
 virtual HRESULT __stdcall SetWidth(LONG pl)=0;
 virtual HRESULT __stdcall GetHeight(LONG* pl)=0;
 virtual HRESULT __stdcall SetHeight(LONG pl)=0;
 virtual HRESULT __stdcall GetLocationName(BSTR* LocationName)=0;
 virtual HRESULT __stdcall GetLocationURL(BSTR* LocationURL)=0;
 virtual HRESULT __stdcall GetBusy(VARIANT_BOOL* pBool)=0;
};
2nd Part ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
interface IWebBrowserApp : IWebBrowser
{
 virtual HRESULT __stdcall Quit(void)=0;
 virtual HRESULT __stdcall ClientToWindow(int* pcx, int* pcy)=0;
 virtual HRESULT __stdcall PutProperty(BSTR Property, VARIANT vtValue)=0;
 virtual HRESULT __stdcall GetProperty(BSTR Property, VARIANT* pvtValue)=0;
 virtual HRESULT __stdcall GetName(BSTR* Name)=0;
 virtual HRESULT __stdcall GetHWND(LONG* pHWND)=0;
 virtual HRESULT __stdcall GetFullName(BSTR* FullName)=0;
 virtual HRESULT __stdcall GetPath(BSTR* Path)=0;
 virtual HRESULT __stdcall GetVisible(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall SetVisible(VARIANT_BOOL pBool)=0;
 virtual HRESULT __stdcall GetStatusBar(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall SetStatusBar(VARIANT_BOOL pBool)=0;
 virtual HRESULT __stdcall GetStatusText(BSTR* StatusText)=0;
 virtual HRESULT __stdcall SetStatusText(BSTR StatusText)=0;
 virtual HRESULT __stdcall GetToolBar(int* Value)=0;
 virtual HRESULT __stdcall SetToolBar(int Value)=0;
 virtual HRESULT __stdcall GetMenuBar(VARIANT_BOOL* Value)=0;
 virtual HRESULT __stdcall SetMenuBar(VARIANT_BOOL Value)=0;
 virtual HRESULT __stdcall GetFullScreen(VARIANT_BOOL* pbFullScreen)=0;
 virtual HRESULT __stdcall SetFullScreen(VARIANT_BOOL pbFullScreen)=0;
};


interface IWebBrowser2 : IWebBrowserApp
{
 virtual HRESULT __stdcall Navigate2(VARIANT* URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers)=0;
 virtual HRESULT __stdcall QueryStatusWB(OLECMDID cmdID, OLECMDF* pcmdf)=0;
 virtual HRESULT __stdcall ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT* pvaIn, VARIANT* pvaOut)=0;
 virtual HRESULT __stdcall ShowBrowserBar(VARIANT* pvaClsid, VARIANT* pvarShow, VARIANT* pvarSize)=0;
 virtual HRESULT __stdcall GetReadyState(tagREADYSTATE* plReadyState)=0;
 virtual HRESULT __stdcall GetOffline(VARIANT_BOOL* pbOffline)=0;
 virtual HRESULT __stdcall SetOffline(VARIANT_BOOL pbOffline)=0;
 virtual HRESULT __stdcall GetSilent(VARIANT_BOOL* pbSilent)=0;
 virtual HRESULT __stdcall SetSilent(VARIANT_BOOL pbSilent)=0;
 virtual HRESULT __stdcall GetRegisterAsBrowser(VARIANT_BOOL* pbRegister)=0;
 virtual HRESULT __stdcall SetRegisterAsBrowser(VARIANT_BOOL pbRegister)=0;
 virtual HRESULT __stdcall GetRegisterAsDropTarget(VARIANT_BOOL* pbRegister)=0;
 virtual HRESULT __stdcall SetRegisterAsDropTarget(VARIANT_BOOL pbRegister)=0;
 virtual HRESULT __stdcall GetTheaterMode(VARIANT_BOOL* pbRegister)=0;
 virtual HRESULT __stdcall SetTheaterMode(VARIANT_BOOL pbRegister)=0;
 virtual HRESULT __stdcall GetAddressBar(VARIANT_BOOL* Value)=0;
 virtual HRESULT __stdcall SetAddressBar(VARIANT_BOOL Value)=0;
 virtual HRESULT __stdcall GetResizable(VARIANT_BOOL* Value)=0;
 virtual HRESULT __stdcall SetResizable(VARIANT_BOOL Value)=0;
};


interface IShellWindows : IDispatch
{
 virtual HRESULT __stdcall GetCount(LONG* Count)=0;
 virtual HRESULT __stdcall Item(VARIANT index, IDispatch** Folder)=0;
 virtual HRESULT __stdcall _NewEnum(IUnknown** ppunk)=0;
 virtual HRESULT __stdcall Register(IDispatch* pid, LONG HWND, int swClass, LONG* plCookie)=0;
 virtual HRESULT __stdcall RegisterPending(LONG lThreadId, VARIANT* pvarloc, VARIANT* pvarlocRoot, int swClass, LONG* plCookie)=0;
 virtual HRESULT __stdcall Revoke(LONG lCookie)=0;
 virtual HRESULT __stdcall OnNavigate(LONG lCookie, VARIANT* pvarloc)=0;
 virtual HRESULT __stdcall OnActivated(LONG lCookie, VARIANT_BOOL fActive)=0;
 virtual HRESULT __stdcall FindWindowSW(VARIANT* pvarloc, VARIANT* pvarlocRoot, int swClass, LONG* pHWND, int swfwOptions, IDispatch** ppdispOut)=0;
 virtual HRESULT __stdcall OnCreated(LONG lCookie, IUnknown* punk)=0;
 virtual HRESULT __stdcall ProcessAttachDetach(VARIANT_BOOL fAttach)=0;
};


interface IShellUIHelper : IDispatch
{
 virtual HRESULT __stdcall ResetFirstBootMode(void)=0;
 virtual HRESULT __stdcall ResetSafeMode(void)=0;
 virtual HRESULT __stdcall RefreshOfflineDesktop(void)=0;
 virtual HRESULT __stdcall AddFavorite(BSTR URL, VARIANT* Title)=0;
 virtual HRESULT __stdcall AddChannel(BSTR URL)=0;
 virtual HRESULT __stdcall AddDesktopComponent(BSTR URL, BSTR Type, VARIANT* Left, VARIANT* Top, VARIANT* Width, VARIANT* Height)=0;
 virtual HRESULT __stdcall IsSubscribed(BSTR URL, VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall NavigateAndFind(BSTR URL, BSTR strQuery, VARIANT* varTargetFrame)=0;
 virtual HRESULT __stdcall ImportExportFavorites(VARIANT_BOOL fImport, BSTR strImpExpPath)=0;
 virtual HRESULT __stdcall AutoCompleteSaveForm(VARIANT* Form)=0;
 virtual HRESULT __stdcall AutoScan(BSTR strSearch, BSTR strFailureUrl, VARIANT* pvarTargetFrame)=0;
 virtual HRESULT __stdcall AutoCompleteAttach(VARIANT* Reserved)=0;
 virtual HRESULT __stdcall ShowBrowserUI(BSTR bstrName, VARIANT* pvarIn, VARIANT* pvarOut)=0;
};


interface IShellUIHelper2 : IShellUIHelper
{
 virtual HRESULT __stdcall AddSearchProvider(BSTR URL)=0;
 virtual HRESULT __stdcall RunOnceShown(void)=0;
 virtual HRESULT __stdcall SkipRunOnce(void)=0;
 virtual HRESULT __stdcall CustomizeSettings(VARIANT_BOOL fSQM, VARIANT_BOOL fPhishing, BSTR bstrLocale)=0;
 virtual HRESULT __stdcall SqmEnabled(VARIANT_BOOL* pfEnabled)=0;
 virtual HRESULT __stdcall PhishingEnabled(VARIANT_BOOL* pfEnabled)=0;
 virtual HRESULT __stdcall BrandImageUri(BSTR* pbstrUri)=0;
 virtual HRESULT __stdcall SkipTabsWelcome(void)=0;
 virtual HRESULT __stdcall DiagnoseConnection(void)=0;
 virtual HRESULT __stdcall CustomizeClearType(VARIANT_BOOL fSet)=0;
 virtual HRESULT __stdcall IsSearchProviderInstalled(BSTR URL, unsigned int* pdwResult)=0;
 virtual HRESULT __stdcall IsSearchMigrated(VARIANT_BOOL* pfMigrated)=0;
 virtual HRESULT __stdcall DefaultSearchProvider(BSTR* pbstrName)=0;
 virtual HRESULT __stdcall RunOnceRequiredSettingsComplete(VARIANT_BOOL fComplete)=0;
 virtual HRESULT __stdcall RunOnceHasShown(VARIANT_BOOL* pfShown)=0;
 virtual HRESULT __stdcall SearchGuideUrl(BSTR* pbstrUrl)=0;
};


interface IShellUIHelper3 : IShellUIHelper2
{
 virtual HRESULT __stdcall AddService(BSTR URL)=0;
 virtual HRESULT __stdcall IsServiceInstalled(BSTR URL, BSTR Verb, unsigned int* pdwResult)=0;
 virtual HRESULT __stdcall InPrivateFilteringEnabled(VARIANT_BOOL* pfEnabled)=0;
 virtual HRESULT __stdcall AddToFavoritesBar(BSTR URL, BSTR Title, VARIANT* Type)=0;
 virtual HRESULT __stdcall BuildNewTabPage(void)=0;
 virtual HRESULT __stdcall SetRecentlyClosedVisible(VARIANT_BOOL fVisible)=0;
 virtual HRESULT __stdcall SetActivitiesVisible(VARIANT_BOOL fVisible)=0;
 virtual HRESULT __stdcall ContentDiscoveryReset(void)=0;
 virtual HRESULT __stdcall IsSuggestedSitesEnabled(VARIANT_BOOL* pfEnabled)=0;
 virtual HRESULT __stdcall EnableSuggestedSites(VARIANT_BOOL fEnable)=0;
 virtual HRESULT __stdcall NavigateToSuggestedSites(BSTR bstrRelativeUrl)=0;
 virtual HRESULT __stdcall ShowTabsHelp(void)=0;
 virtual HRESULT __stdcall ShowInPrivateHelp(void)=0;
};
Last part...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
interface IShellFavoritesNameSpace : IDispatch
{
 virtual HRESULT __stdcall MoveSelectionUp(void)=0;
 virtual HRESULT __stdcall MoveSelectionDown(void)=0;
 virtual HRESULT __stdcall ResetSort(void)=0;
 virtual HRESULT __stdcall NewFolder(void)=0;
 virtual HRESULT __stdcall Synchronize(void)=0;
 virtual HRESULT __stdcall Import(void)=0;
 virtual HRESULT __stdcall Export(void)=0;
 virtual HRESULT __stdcall InvokeContextMenuCommand(BSTR strCommand)=0;
 virtual HRESULT __stdcall MoveSelectionTo(void)=0;
 virtual HRESULT __stdcall GetSubscriptionsEnabled(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall CreateSubscriptionForSelection(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall DeleteSubscriptionForSelection(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall SetRoot(BSTR bstrFullPath)=0;
};




interface IShellNameSpace : IShellFavoritesNameSpace
{
 virtual HRESULT __stdcall GetEnumOptions(LONG* pgrfEnumFlags)=0;
 virtual HRESULT __stdcall SetEnumOptions(LONG pgrfEnumFlags)=0;
 virtual HRESULT __stdcall GetSelectedItem(IDispatch** pItem)=0;
 virtual HRESULT __stdcall SetSelectedItem(IDispatch* pItem)=0;
 virtual HRESULT __stdcall GetRoot(VARIANT* pvar)=0;
 virtual HRESULT __stdcall SetRoot(VARIANT pvar)=0;
 virtual HRESULT __stdcall GetDepth(int* piDepth)=0;
 virtual HRESULT __stdcall SetDepth(int piDepth)=0;
 virtual HRESULT __stdcall GetMode(unsigned int* puMode)=0;
 virtual HRESULT __stdcall SetMode(unsigned int puMode)=0;
 virtual HRESULT __stdcall GetFlags(unsigned int* pdwFlags)=0;
 virtual HRESULT __stdcall SetFlags(unsigned int pdwFlags)=0;
 virtual HRESULT __stdcall SetTVFlags(unsigned int dwFlags)=0;
 virtual HRESULT __stdcall GetTVFlags(unsigned int* dwFlags)=0;
 virtual HRESULT __stdcall GetColumns(BSTR* bstrColumns)=0;
 virtual HRESULT __stdcall SetColumns(BSTR bstrColumns)=0;
 virtual HRESULT __stdcall GetCountViewTypes(int* piTypes)=0;
 virtual HRESULT __stdcall SetViewType(int iType)=0;
 virtual HRESULT __stdcall SelectedItems(IDispatch** ppid)=0;
 virtual HRESULT __stdcall Expand(VARIANT var, int iDepth)=0;
 virtual HRESULT __stdcall UnselectAll(void)=0;
};


interface IScriptErrorList : IDispatch
{
 virtual HRESULT __stdcall advanceError(void)=0;
 virtual HRESULT __stdcall retreatError(void)=0;
 virtual HRESULT __stdcall canAdvanceError(LONG* pfCanAdvance)=0;
 virtual HRESULT __stdcall canRetreatError(LONG* pfCanRetreat)=0;
 virtual HRESULT __stdcall getErrorLine(LONG* plLine)=0;
 virtual HRESULT __stdcall getErrorChar(LONG* plChar)=0;
 virtual HRESULT __stdcall getErrorCode(LONG* plCode)=0;
 virtual HRESULT __stdcall getErrorMsg(BSTR* pstr)=0;
 virtual HRESULT __stdcall getErrorUrl(BSTR* pstr)=0;
 virtual HRESULT __stdcall getAlwaysShowLockState(LONG* pfAlwaysShowLocked)=0;
 virtual HRESULT __stdcall getDetailsPaneOpen(LONG* pfDetailsPaneOpen)=0;
 virtual HRESULT __stdcall setDetailsPaneOpen(LONG fDetailsPaneOpen)=0;
 virtual HRESULT __stdcall getPerErrorDisplay(LONG* pfPerErrorDisplay)=0;
 virtual HRESULT __stdcall setPerErrorDisplay(LONG fPerErrorDisplay)=0;
};

#endif 
To get this to work, you need some version of AtlXX.dll, where XX is 71, 80, 90, or something. Don't believe I've ever got it to work with just Atl.dll, for whatever reason. If you look up in StartOLEProcess() near the top of Main.cpp you'll see I'm trying to do a LoadLibrary() call on Atl71.dll. Note the dll needs to be in the working or same directory where the exe is located.

The Atl.dll file provides something teermed an "ActiveX Control Container". In Win32 C or C++ projects where there is no visual designer involved one needs various routines to handle some of the negotiation that's involved between the siting of the ActiveX Control in the host, and the control itself.

Add link libraries ole32.lib, oleaut32.lib, and uuid.lib.

If the browser shows up, and you're connected to the internet, type a url in the text box at top and hit the 'Navigate' button.
Last edited on
But I havn't forgotten your original attempt to start the "InternetExplorer.Application". Here is how to do it. But note you still need my IWebBrowser.h file if you want the IExplorer.exe instance to become visible, because SetVisible is one of the methods of the IWebBrowser interface...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <windows.h>
#include <cstdio>
#include "IWebBrowser.h"

int main()
{
 const CLSID CLSID_IE_Application = {0x0002DF01,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID   IID_IEApplication    = {0x0002DF05,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IWebBrowserApp* pApp             = NULL;
 HRESULT hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 {
    printf("CoInitialize() Succeeded!\n");
    hr = CoCreateInstance(CLSID_IE_Application, NULL, CLSCTX_LOCAL_SERVER, IID_IEApplication, (void **) &pApp);
    if(SUCCEEDED(hr))
    {
       printf("pApp = 0x%p\n",pApp);
       hr=pApp->SetVisible(1);
       getchar();
       pApp->Release();
    }
    else
       printf("CoCreateInstance() Failed!\n");
    CoUninitialize();
 }
 else
    printf("CoInitialize() Failed!\n");
 getchar();

 return 0;
}
Thanks for quick response.

I tried the code in the last post, and made IWebBrowser.h. The code compiled on the first try and the application worked! Very nice!

Your code cleared much of the fog of COM objects. I see that I have to declare functions for changing properties of the object (such as SetVisible()).
However, one the things that threw me off while studying COM was that a scripting language I like to use (which is built in C++) is able to call COM without the need for anything except the ProgID. I'm not sure how they did that; I don't think the makers included a header file and information for each class of COM objects it supports on its own.

I will try to use your imbedded shell object example.

Another noob question:
freddie1 wrote:
I used Mingw 4.4
Is there a way to get the Mingw version or do you just remember it from downloading it?


If case you do want to pursue the scripting language I'm talking about here is some information. The scripting language is called AutoHotkey and is made for doing easy windows automation but has lots of added other features as well.
http://ahkscript.org/docs/commands/ComObjCreate.htm - Command for creating COM objects (see example at the bottom)
http://www.autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/page-2?&#entry362159 - a bigger InternetExplorer.Application example
https://github.com/Lexikos/AutoHotkey_L/ - the build for AutoHotkey (which is in C++), in case it might be helpful.

thank you again

However, one the things that threw me off while studying COM was that a scripting language I like to use (which is built in C++) is able to call COM without the need for anything except the ProgID. I'm not sure how they did that; I don't think the makers included a header file and information for each class of COM objects it supports on its own.


A very basic and fundamental dichotomy one must face when dealing with utilizing COM components/objects is the distinction between making direct VTable calls on the object, such as I did above in calling pApp->SetVisible(1), and using the IDispatch OLE Automation interface. Many scripting languages such as JScript, VB Script, possibly the one you mentioned, are not able to call objects through the direct VTable interface, so the IDispatch form is used. One of the drawbacks to this is that in terms of in process dll servers it is like a hundred times slower than direct access.

Taking the example above of IExplorer.exe, using IDispatch access wouldn't make much difference in speed because the bottleneck there wouldn't be the function call itself so much as marshalling the function call across process boundaries. In your original program or the last one I posted, the compilation of that program results in an exe that essentially drives another exe, i.e., IExplorer.exe. So using direct VTable calls the calls nonetheless must be marshalled across process boundaries, which is fairly slow.

Now in that 1st version I posted, the resulting executable does not start IExplorer.exe, but rather loads the ActiveX Control ( "Shell.Explorer" ) right into its process space - its a dll that gets loaded, and can make direct VTable calls.

Now the situation with scripting languages being easier to use seemingly without the need for header files - well, that takes some explaining, and I'd recommend you study up on it if interested. But here is a whirlwind explanation. Microsoft intended COM to be a programming language agnostic object model. They wanted it to work in C, C++, Visual Basic, PowerBASIC, Auto-HotKey, whatever. One possible way of working towards that would have been to create seperate header files for each language declaring the method calls. However, they did something about a hundred times slicker than that. They created a seperate interface definition language ( IDL ) for describing the interfaces of an object, and they wrote a special compiler to compile this interface definition language into a binary form. This binary form is known as a Type Library. Here is an example of what the IDL looks like for the IWebBrowserApp Interface...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[odl, uuid(0002DF05-0000-0000-C000-000000000046), helpstring("Web Browser Application Interface."), hidden, dual, oleautomation] interface IWebBrowserApp : IWebBrowser
{
 [id(0x0000012c), helpstring("Exits application and closes the open document.")] HRESULT Quit();
 [id(0x0000012d), helpstring("Converts client sizes into window sizes.")] HRESULT ClientToWindow([in, out] int* pcx, [in, out] int* pcy);
 [id(0x0000012e), helpstring("Associates vtValue with the name szProperty in the context of the object.")] HRESULT PutProperty([in] BSTR Property, [in] VARIANT vtValue);
 [id(0x0000012f), helpstring("Retrieve the Associated value for the property vtValue in the context of the object.")] HRESULT GetProperty([in] BSTR Property, [out, retval] VARIANT* pvtValue);
 [id(00000000), propget, helpstring("Returns name of the application.")] HRESULT Name([out, retval] BSTR* Name);
 [id(0xfffffdfd), propget, helpstring("Returns the HWND of the current IE window.")] HRESULT HWND([out, retval] long* pHWND);
 [id(0x00000190), propget, helpstring("Returns file specification of the application, including path.")] HRESULT FullName([out, retval] BSTR* FullName);
 [id(0x00000191), propget, helpstring("Returns the path to the application.")] HRESULT Path([out, retval] BSTR* Path);
 [id(0x00000192), propget, helpstring("Determines whether the application is visible or hidden.")] HRESULT Visible([out, retval] VARIANT_BOOL* pBool);
 [id(0x00000192), propput, helpstring("Determines whether the application is visible or hidden.")] HRESULT Visible([in] VARIANT_BOOL pBool);
 [id(0x00000193), propget, helpstring("Turn on or off the statusbar.")] HRESULT StatusBar([out, retval] VARIANT_BOOL* pBool);
 [id(0x00000193), propput, helpstring("Turn on or off the statusbar.")] HRESULT StatusBar([in] VARIANT_BOOL pBool);
 [id(0x00000194), propget, helpstring("Text of Status window.")] HRESULT StatusText([out, retval] BSTR* StatusText);
 [id(0x00000194), propput, helpstring("Text of Status window.")] HRESULT StatusText([in] BSTR StatusText);
 [id(0x00000195), propget, helpstring("Controls which toolbar is shown.")] HRESULT ToolBar([out, retval] int* Value);
 [id(0x00000195), propput, helpstring("Controls which toolbar is shown.")] HRESULT ToolBar([in] int Value);
 [id(0x00000196), propget, helpstring("Controls whether menubar is shown.")] HRESULT MenuBar([out, retval] VARIANT_BOOL* Value);
 [id(0x00000196), propput, helpstring("Controls whether menubar is shown.")] HRESULT MenuBar([in] VARIANT_BOOL Value);
 [id(0x00000197), propget, helpstring("Maximizes window and turns off statusbar, toolbar, menubar, and titlebar.")] HRESULT FullScreen([out, retval] VARIANT_BOOL* pbFullScreen);
 [id(0x00000197), propput, helpstring("Maximizes window and turns off statusbar, toolbar, menubar, and titlebar.")] HRESULT FullScreen([in] VARIANT_BOOL pbFullScreen);
};


Note it looks kind of like C but not exactly. Here is what that interface looks like when actually converted to C/C++ code, as can be seen in IWebBrowser.h...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface IWebBrowserApp : IWebBrowser
{
 virtual HRESULT __stdcall Quit(void)=0;
 virtual HRESULT __stdcall ClientToWindow(int* pcx, int* pcy)=0;
 virtual HRESULT __stdcall PutProperty(BSTR Property, VARIANT vtValue)=0;
 virtual HRESULT __stdcall GetProperty(BSTR Property, VARIANT* pvtValue)=0;
 virtual HRESULT __stdcall GetName(BSTR* Name)=0;
 virtual HRESULT __stdcall GetHWND(LONG* pHWND)=0;
 virtual HRESULT __stdcall GetFullName(BSTR* FullName)=0;
 virtual HRESULT __stdcall GetPath(BSTR* Path)=0;
 virtual HRESULT __stdcall GetVisible(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall SetVisible(VARIANT_BOOL pBool)=0;
 virtual HRESULT __stdcall GetStatusBar(VARIANT_BOOL* pBool)=0;
 virtual HRESULT __stdcall SetStatusBar(VARIANT_BOOL pBool)=0;
 virtual HRESULT __stdcall GetStatusText(BSTR* StatusText)=0;
 virtual HRESULT __stdcall SetStatusText(BSTR StatusText)=0;
 virtual HRESULT __stdcall GetToolBar(int* Value)=0;
 virtual HRESULT __stdcall SetToolBar(int Value)=0;
 virtual HRESULT __stdcall GetMenuBar(VARIANT_BOOL* Value)=0;
 virtual HRESULT __stdcall SetMenuBar(VARIANT_BOOL Value)=0;
 virtual HRESULT __stdcall GetFullScreen(VARIANT_BOOL* pbFullScreen)=0;
 virtual HRESULT __stdcall SetFullScreen(VARIANT_BOOL pbFullScreen)=0;
};


Do you see those hex numbers in the IDL, e.g., 0x0000012c for the Quit() method? Those are Dispatch IDs, and they are used in the IDispatch Interface to call the methods on the object instead of the direct function calls. The scripting languages in many cases make the translations behind the scenes so the user can manage it without having a clue as to how its really working. That's why its easy.

continued...
Last edited on
Then there's the issue of early binding verses late binding. Using 'late binding' its possible to make function calls on the object without any header file info.

Recently I posted a lot here at www.cplusplus.com where a user was attempting to automate Microsoft Excel. I'll find some of those links for you. They show how to automate Excel using the 'scripting' technique of IDispatch...

(I'll get link in a second...)

one link...

http://www.cplusplus.com/forum/windows/125996/

another more recent ...

http://www.cplusplus.com/forum/windows/164379/

At that last link andyweskin provided some good help which will work if you are using MS VC++.

Where that IWebBrowser.h file came from is that I wrote a lot of complex code to read an object's Type Library and create a C or C++ header file. If you want that code I can provide it. However, Microsoft's Visual Studio product contains the functionality to do that. My code is necessary if you are using the Mingw compiler however. I do it my way because I essentially do everything my way, and I don't care for the ugly convoluted outputs of the Microsoft products.

I have Code::Blocks 10.05 installed in XP Mode on my Win 7 x64 box. In the C:\Program Files\CodeBlocks\Mingw directory is the Mingw readme.txt file where the compiler version is mentioned. No doubt there is a compiler switch that reveals that too, but offhand I don't recall what it is. I think its 4.4 or 4.3 or somewhere around there.

On my x64 Win 7 I'm using Mingw 4.8, and I have the Code::Blocks IDE set up to produce x64 executables. I used my older Mingw 4.4 x86 compiler here for your code because I wasn't sure "Shell.Explorer" had a 64 bit version to be loaded by a 64 bit exe in my in process example above.

I'm big on writing small code. That's one reason I tend to use older compilers. That in process example above creates a 9 k executable above. Can you imagine that? A 9 K executable that uses Microsoft's Internet Explorer ActiveX Control! That's the app I used to actually post all this code.
Last edited on
No better way to make the distinction clear between COM and direct Vtable Access verses IDispatch access than with an example with which you are already familiar. In my last code post was this which required the IWebBrowser.h file so that the compiler could understand the pApp->SetVisible(1) call…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <windows.h>
#include <cstdio>
#include "IWebBrowser.h"

int main()
{
 const CLSID      CLSID_IE_Application = {0x0002DF01,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID        IID_IEApplication    = {0x0002DF05,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IWebBrowserApp*  pApp                 = NULL;
 HRESULT          hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 {
    printf("CoInitialize() Succeeded!\n");
    hr = CoCreateInstance(CLSID_IE_Application, NULL, CLSCTX_LOCAL_SERVER, IID_IEApplication, (void **) &pApp);
    if(SUCCEEDED(hr))
    {
       printf("pApp = 0x%p\n",pApp);
       hr=pApp->SetVisible(1);
       getchar();
       pApp->Release();
    }
    else
       printf("CoCreateInstance() Failed!\n");
    CoUninitialize();
 }
 else
    printf("CoInitialize() Failed!\n");
 getchar();

 return 0;
}


Here is what that program looks like using only the IDispatch part of the dual interface. Note the lack of include file IWebBrowser.h…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <windows.h>
#include <cstdio>

int main()
{
 const CLSID      CLSID_IE_Application = {0x0002DF01,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID        IID_IEApplication    = {0x0002DF05,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IDispatch*       pApp                 = NULL;
 VARIANT          vArgArray[1];
 DISPPARAMS       DispParams;
 DISPID           dispidNamed;
 VARIANT          vResult;
 LCID             lcid;
 HRESULT          hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 {
    printf("CoInitialize() Succeeded!\n");
    hr = CoCreateInstance(CLSID_IE_Application, NULL, CLSCTX_LOCAL_SERVER, IID_IEApplication, (void **) &pApp);
    if(SUCCEEDED(hr))
    {
       printf("pApp = 0x%p\n",pApp);
       VariantInit(&vArgArray[0]);
       lcid                            = GetUserDefaultLCID();
       vArgArray[0].vt                 = VT_BOOL;
       vArgArray[0].boolVal            = TRUE;
       dispidNamed                     = DISPID_PROPERTYPUT;
       DispParams.rgvarg               = vArgArray;
       DispParams.rgdispidNamedArgs    = &dispidNamed;
       DispParams.cArgs                = 1;
       DispParams.cNamedArgs           = 1;
       VariantInit(&vResult);
       pApp->Invoke(0x00000192,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);
       getchar();
       pApp->Release();
    }
    else
       printf("CoCreateInstance() Failed!\n");
    CoUninitialize();
 }
 else
    printf("CoInitialize() Failed!\n");
 getchar();

 return 0;
}


Using Mingw 4.4.1 I’m seeing a 7K executable on that. Not bad. If you’ve never faced this stuff before I expect its pretty intimidating. C++ programmers hate IDispatch calls. Actually, I’ve been doing this stuff for a pretty long time, and I still find it intimidating.

It can be made somewhat more palatable by wrapping the IDispatch stuff up into function calls like so…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <windows.h>
#include <cstdio>

void SetVisible(IDispatch* pApp, LCID lcid)
{
 VARIANT         vArgArray[1];
 DISPPARAMS      DispParams;
 DISPID          dispidNamed;
 VARIANT         vResult;

 VariantInit(&vArgArray[0]);
 vArgArray[0].vt                = VT_BOOL;
 vArgArray[0].boolVal           = TRUE;
 dispidNamed                    = DISPID_PROPERTYPUT;
 DispParams.rgvarg              = vArgArray;
 DispParams.rgdispidNamedArgs   = &dispidNamed;
 DispParams.cArgs               = 1;
 DispParams.cNamedArgs          = 1;
 VariantInit(&vResult);
 pApp->Invoke(0x00000192,IID_NULL,lcid,DISPATCH_PROPERTYPUT,&DispParams,&vResult,NULL,NULL);
}

int main()
{
 const CLSID      CLSID_IE_Application = {0x0002DF01,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 const IID        IID_IEApplication    = {0x0002DF05,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
 IDispatch*       pApp                 = NULL;
 LCID             lcid;
 HRESULT          hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 {
    printf("CoInitialize() Succeeded!\n");
    hr = CoCreateInstance(CLSID_IE_Application, NULL, CLSCTX_LOCAL_SERVER, IID_IEApplication, (void **) &pApp);
    if(SUCCEEDED(hr))
    {
       printf("pApp = 0x%p\n",pApp);
       lcid=GetUserDefaultLCID();
       SetVisible(pApp,lcid);
       getchar();
       pApp->Release();
    }
    else
       printf("CoCreateInstance() Failed!\n");
    CoUninitialize();
 }
 else
    printf("CoInitialize() Failed!\n");
 getchar();

 return 0;
}


If you are just starting this COM work and wish to continue, then two tools you should become familiar with are RegEdit.exe, which should be in your system directory, and OleView.exe, which used to be part of Microsoft’s older Visual Studio installations. Seems to me I heard or read somewhere that Microsoft wasn’t supplying OleView anymore with the newer VS versions. Shame on them if they aren’t. This is a must have for serious COM work.
OleView is provided as part of the Windows SDK -- I can see both a x86 and x64 build of the tool in version 8.1 of the SDK.

Andy
I tried your IDispatch examples but got errors when I tried to compile them (the same errors from both).

F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0xfa): undefined reference to `__imp_VariantInit'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x14a): undefined reference to `__imp_VariantInit'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.rdata$.refptr.GUID_NULL[.refptr.GUID_NULL]+0x0): undefined reference to `GUID_NULL'
F:\C++\Dev-C++\COM test 9 IDispatch\collect2.exe	[Error] ld returned 1 exit status
25		F:\C++\Dev-C++\COM test 9 IDispatch\Makefile.win	recipe for target 'Project1.exe' failed


I also tried your shell example above but also got errors
F:\C++\Dev-C++\Shell Example\main.cpp	In function 'long int fnWndProc_OnCreate(lpWndEventArgs)':
61	49	F:\C++\Dev-C++\Shell Example\main.cpp	[Error] cast from 'IUnknown*' to 'long int' loses precision [-fpermissive]
68	55	F:\C++\Dev-C++\Shell Example\main.cpp	[Error] cast from 'IUnknown*' to 'long int' loses precision [-fpermissive]
71	58	F:\C++\Dev-C++\Shell Example\main.cpp	[Error] cast from 'IWebBrowser*' to 'long int' loses precision [-fpermissive]
F:\C++\Dev-C++\Shell Example\main.cpp	In function 'long int fnWndProc_OnCommand(lpWndEventArgs)':
98	56	F:\C++\Dev-C++\Shell Example\main.cpp	[Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]
F:\C++\Dev-C++\Shell Example\main.cpp	In function 'long int fnWndProc_OnDestroy(lpWndEventArgs)':
116	53	F:\C++\Dev-C++\Shell Example\main.cpp	[Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]
119	52	F:\C++\Dev-C++\Shell Example\main.cpp	[Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]
122	53	F:\C++\Dev-C++\Shell Example\main.cpp	[Warning] cast to pointer from integer of different size [-Wint-to-pointer-cast]
28		F:\C++\Dev-C++\Shell Example\Makefile.win	recipe for target 'main.o' failed

I have MinGW 4.9.2 and Orwell Dev-C++ 5.11 IDE.

I don't have any idea really of how to fix either of those. Would going to MinGW 4.4.1 make them work?

thanks
Mingw 4.9 produces either x86 or x64 code depending on the switches fed into the compiler. Are you running x64? That's what those errors look like. For example, ...

cast from 'IUnknown*' to 'long int' loses precision

...sounds like an x64 8 byte pointer address being crunched into 4 bytes which I believe a long int is in x64.

In the case of my ActiveX Container example above, I specifically used the older compiler in XP Mode on my x64 box because I have MinGW 4.8 set up on my Code::Blocks installation to produce x64 binaries, and an x64 binary can't very easily load an x86 dll into its address space. And I really don't know what the situation is with "Shell.Explorer" (IE ActiveX Dll) on Win 7 installations in terms of whether there is both an x86 version for 32 bit exes and an x64 version for 64 bit exes, or whatever. I simply never cared to check. So to spare myself checking it out or researching the matter I opted to use my older 32 bit only Mingw.

If you are configured to be making x64 executables, it may solve those errors by reconfiguring to create x86 code. My remarks above relate strictly to the first code I posted where I'm using Atl and Shell.Explorer.

In terms of ...

undefined reference to `__imp_VariantInit

...that's a linker error. Are you linking against libole32.lib, liboleaut32.lib, and libuuid.lib? VariantInit() is in one of the 1st two I think.

Andy,

Thanks for the info on OleView. Don't remember how I came by that bad info. Glad to hear that's still included.

If it still won't work Firecannon, I'll try it on a Mingw 4.9 installation I have on my wife's little netbook. Oh! That's 64 bit only I just recalled. But I could compile it both ways to see if that's the issue.

If someone here wants to jump in here that has specific knowledge about the x86 verses x64 issue with "Shell.Explorer" I'd appreciate it. The other issue there is that example of mine is using Atl71.dll, or Atl80.dll, or Atl90.dll, or whatever as an ActiveX Control Container, so that would also have to exist in x64 binary form to work. And it might. I just don't know. Lot of iffs! Now maybe you see why I was so adament about producing a 32 bit executable example! Its kind of a can of worms.
Mingw 4.9 produces either x86 or x64 code depending on the switches fed into the compiler. Are you running x64? That's what those errors look like.
Why didn't I think of that? That didn't even cross my mind! I read that you were using a x86 compiler, but it never occured to me to switch mine. Somehow I knew one of the things I was doing wrong was a facepalmer...
Now I'm using a x86 compiler. To be precise, I'm using TDM-GCC 4.9.2 32-bit Release.

...that's a linker error. Are you linking against libole32.lib, liboleaut32.lib, and libuuid.lib? VariantInit() is in one of the 1st two I think.
I didn't know I needed the second two. Now I'm linking to them.

However, switching to x86 gave me a bunch of errors when compiling the IDispatch example.
C:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\bin\ld.exe	i386:x86-64 architecture of input file `Untitled2.o' is incompatible with i386 output
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0xc): undefined reference to `_main'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x86): undefined reference to `_imp_CoInitialize'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0xca): undefined reference to `_imp_CoCreateInstance'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0xfa): undefined reference to `_imp_VariantInit'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x103): undefined reference to `_imp_GetUserDefaultLCID'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x14a): undefined reference to `_imp_VariantInit'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x1a7): undefined reference to `getchar'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x1d3): undefined reference to `_imp_CoUninitialize'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text+0x1e8): undefined reference to `getchar'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.text$_Z6printfPKcz[_Z6printfPKcz]+0x32): undefined reference to `_mingw_vprintf'
F:\C++\Dev-C++\COM test 9 IDispatch\Untitled2.o	Untitled2.cpp:(.rdata$.refptr.GUID_NULL[.refptr.GUID_NULL]+0x0): undefined reference to `GUID_NULL'
C:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\lib32\libmingw32.a(lib32_libmingw32_a-crt0_c.o)	In function `main':
18		C:\crossdev\src\mingw-w64-v3-git\mingw-w64-crt\crt\crt0_c.c	undefined reference to `WinMain@16'
F:\C++\Dev-C++\COM test 9 IDispatch\collect2.exe	[Error] ld returned 1 exit status
25		F:\C++\Dev-C++\COM test 9 IDispatch\Makefile.win	recipe for target 'Project1.exe' failed
I once again don't know how to fix these.
For more specifics, according to Dev-C++, there are no commands (flags) for the compiler, and the commands for the linker are -static-libgcc -lole32 -loleaut32 -luuid

thank you for your patience
Been working on it Firecannon. And thinking about it. Actually, that Shell.Explorer in process example is quite old and from long before I started working with 64 bit. Its absolutely solid 32 bit code though. I'll talk more about that later, as that's the one I'm most interested in seeing if I can get it working as 64 bit.

But right now you seem most interested in the IDispatch example, so I'll discuss that. I think you may be having difficulties with linking against the correct versions of the libs for the architecture you are using. It can get pretty confusing. Especially when using an IDE. Fact is, I have less trouble with it when compiling from the command line than when using an IDE, because when using the command line there is just a symbol or two difference between x86 compiles and x64, and when you feed in the proper symbol or two the compiler automatically links against the correct libs, which are in completely different locations for x86 and x64.

For example, here is what my mingw (4.8 I think) directory structure looks like...

C:\TDM-GCC-64
C:\TDM-GCC-64\x86_64-w64-mingw32
C:\TDM-GCC-64\x86_64-w64-mingw32\lib <<< 64 bit libs
C:\TDM-GCC-64\x86_64-w64-mingw32\lib32 <<< 32 bit libs

So however you do the setup using your IDE, you have to be really, really careful you're selecting the libs from the correct directory. You do realize that they are all duplicated don't you? For example, there are two libole32.a files - one 32 bit and one 64 bit. They are in different directories, naturally, because you can't have two files of the same name in the same directory.

But it can even get more confusing than that. Let me tell you about a situation I run into when using the Code::Blocks IDE. And I think some of this is going on with you too about that very top error message you just posted. The IDE gets obj files mixed up between 32 bit and 64 bit. Here's what happens to me. As you know, I have several mingw installations on my various computers of various vintages. I have found to my dismay that I can't copy a folder containing the various files that are part of a build from an x86 installation to an x64 installation. For one thing, as I said above, the lib paths are different. For another, any *.obj files in a folder from the other architecture are used by the architecture you've just changed to. So the IDE is mixing up x86 objs with x64 objs. It's pretty miserable.

To make a long story short, what I have found it best to do when moving projects between x86 and x64 is delete everything in the folder relating to the IDE and just leave the source code files, i.e., the *.cpp, *.h files, etc. Then copy the folder to another location where the IDE relating to that architecture will look for it. I don't know if that sounds bizarre to you or not. All I can say is that it works for me and that's what I do.

By the way, Microsoft's Visual Studio deals better with this, in that it creates unbelievably complicated directory schemes to handle it. I'm giving the devil his due here because I'm not a big fan of Microsoft programming products. I'm just being honest about it. I really think some of this stuff I've just mentioned is going on with your compilation/linkage problems, as I've seen all that stuff before in sorting out my woes. You need the patience of Job for this stuff.

I'll discuss some other issues tomorrow that I think I've resolved concerning converting my ActiveX Control Example to x64. I'm pretty sure I can do it.
That IDispatch code I posted is absolutely solid Firecannon. Keep working with it fighting the lib thing and I'm sure you'll get it.

You know, this business of posting code here is tricky due to all the various IDEs, compilers, and such that folks use. For myself, I mostly work in 64 bit now, but I test just about everything I do with x86 and x64 with both mingw and MS VC++ - also x86 and x64. Drives me batty some times.
I got it working!

In the list of my directories for my libraries, there was an invalid path to a folder. That was it. It was a crazy lucky guess.

You do realize that they are all duplicated don't you?
No, I didn't.

Update: Now the shell.explorer example compiles. It says can't load alt71.dll when it runs, but that's to be expected. I tried to reproduce the error by adding the invalid path to the library directory list, but it still compiled. Puzzling... I guess the moral of the story is that IDEs are not to be trusted.

I've also gone through and made sure that all the rest of the paths to directories are valid.

For the record, programming is new to me. I'm used to the scripting language I talked about earlier (AutoHotkey), and that's the only other programming language I really know, and its how I got started into programming. In AutoHotkey, the problems I have are completely different from the ones here. Most of them are runtime errors, since it is interpreted. This is new experience, so I can't see how many more problems in compilation there's going to be as much as will in say, 3 years from now (assuming I do lots of C++). That's why I keep wondering if there's some secret to getting programs to compile.

thanks
Pages: 123