Error using COM; IID_IFileOpenDialog not declared; GCC

Hello,

I've been looking into learning the windows API lately (again), and I'm currently dealing with COM interfaces; when I try the examples in this page https://msdn.microsoft.com/en-us/library/windows/desktop/ff485843(v=vs.85).aspx, however, I get an compiler error saying IID_IFileOpenDialog was not declared.

Here's the relevant line:

1
2
3
code = CoCreateInstance(CLSID_FileOpenDialog, NULL,
			CLSCTX_ALL, IID_IFileOpenDialog,
			reinterpret_cast<void**>(&pFileOpen));


Since I'm using GCC - more specifically, mingw64 - I'm wondering if this is a bug with the implementation, or if the tutorial is just outdated, and if things are done in a different way now-a-days.

Skimming the header file "shobjidl.h", which I do have included, I did find the line

DEFINE_GUID(IID_IFileOpenDialog, 0xd57c7288, 0xd4ad, 0x4768, 0xbe,0x02, 0x9d,0x96,0x95,0x32,0xd9,0x60);

but the compiler never seems to reach it, so I'm guessing it is nested inside a tricky preprocessor conditional I can't find.

Thank you in advance for the help.
Last edited on
I don't use the COM (IFileOpen) version of the Open/Save File Dialogs, even though I suppose I should. I'm aware of them - just never used them. But your question prompted me to look into it. I use both Visual Studio and Mingw. This worked with VC9 from Visual Studio 2008 (which, confusingly, is actually VC15 in terms of official versions)...

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
// Main.cpp (OpenFile.cpp)
// cl Main.cpp /O1 /Os /MT /FeOpenFile.exe Kernel32.lib User32.lib ole32.lib oleaut32.lib uuid.lib
// g++ Main.cpp -oOpenFile_MinGW64.exe -mwindows -m64 -s -Os -lkernel32 -luser32 -lole32 -loleaut32 -luuid
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif   
#include <windows.h>
#include <Shobjidl.h>
#include "Main.h"


LRESULT __stdcall fnWndProc_OnCreate(WndEventArgs& Wea)
{
 HRESULT hr;
 
 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
    Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 else
    return -1;
   
 return 0;
}


LRESULT __stdcall fnWndProc_OnLButtonDown(WndEventArgs& Wea)
{
 IFileOpenDialog* pFileOpen = NULL;
 HRESULT hr;
 
 hr=CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void**)(&pFileOpen));
 if(SUCCEEDED(hr))
 { 
    MessageBox(Wea.hWnd,L"CoCreateInstance() Succeeded!",L"Event Report!",MB_OK);
    pFileOpen->Release();    
 }
 else
    MessageBox(Wea.hWnd,L"CoCreateInstance() Failed!",L"Event Report!",MB_OK);
   
 return 0;
}


LRESULT __stdcall fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 CoUninitialize();
 PostQuitMessage(0);
 
 return 0;
}



LRESULT __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(size_t 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)
{
 wchar_t szClassName[]=L"OpenFile";
 HWND hWnd=NULL;
 MSG messages;
 WNDCLASS wc;
 
 memset(&wc,0,sizeof(WNDCLASS));
 wc.lpszClassName = szClassName,                     wc.lpfnWndProc   = fnWndProc;
 wc.hIcon         = LoadIcon(NULL,IDI_APPLICATION),  wc.hInstance     = hIns;
 wc.hCursor       = LoadCursor(NULL,IDC_ARROW),      wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
 RegisterClass(&wc);
 hWnd=CreateWindow(szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 if(hWnd)
 { 
    ShowWindow(hWnd,iShow);
    while(GetMessage(&messages,NULL,0,0))
    {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
    }
 }

 return (int)messages.wParam;
}


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
//Main.h
#ifndef Main_h
#define Main_h

#define dim(x) (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                  hWnd;
 WPARAM                wParam;
 LPARAM                lParam;
 HINSTANCE             hIns;
};

LRESULT __stdcall      fnWndProc_OnCreate      (WndEventArgs& Wea);
LRESULT __stdcall      fnWndProc_OnLButtonDown (WndEventArgs& Wea);
LRESULT __stdcall      fnWndProc_OnDestroy     (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int          iMsg;
 LRESULT               (__stdcall* fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,           fnWndProc_OnCreate},
 {WM_LBUTTONDOWN,      fnWndProc_OnLButtonDown},
 {WM_DESTROY,          fnWndProc_OnDestroy}
};
#endif 


What all that (the above) is, is a simple GUI that, when you click anywhere on the Form/window/dialog, attempts to use CoCreateInstance() to instantiate a pointer to an IOpenFileDialog object, which is a pointer to one of the interfaces (structs) contained within the greater CLSID_FileOpenDialog objects. The Form only has message handling procedures for WM_CREATE, WM_LBUTTONDOWN, and WM_DESTROY.

When I attempted to try it with Mingw I got about the same errors you did. I have various old versions of GCC installed on several of the various boxes I use. Specifically, the ereror I got was on TDM GCC 4.8.

I have to look into it further to see just what the issue is, that is, if you haven't figurred it out yet.

When I ran the VC version though it worked perfect. The Message Box came up saying that my CoCreateInstance() call succeeded.
Got it to work with Visual Studio. Having same problem as you with GCC. I could look into it further if you haven't already got it???
I threw several hours of quality time at this, that is, trying to get full IFileOpen COM functionality with TDM-GCC 4.8, x64, and largely failed. One thing I tried was using Microsoft's headers instead of the ones supplied with GCC, but to no avail. That surprised me greatly. I thought sure the problem would be with the headers, but now I'm not so sure. I did finally manage to get CoCreateInstance() to succeed and give me an IFileOpen*, but I was unable to use it in any way.

I spent a little time on the internet searching for solutions, and it does appear others have had this problem, but, far as I could see, no one solved it.

At this time I'm not willing to put any more time into searching for a solution. The fact of the matter for me is that I gave up on MinGW several years back, even though it was my primary build system for a lot of years. The reason I gave up on it was the bloated size of C++ executables produced by these compilers, since the adoption of post C99 C++ Standards.

However, I did want to finally work a bit with the IFileOpen COM functionality; I figured it was something I ought to finally look at, even though I had always used the commdlg.h and comdlg32.lib/comdlg32.dll GetOpenFileName() functionality.

I use PowerBASIC a lot, and knew Jose Roca had provided a demo of IFileOpen, so I converted his code pretty much line for line to C++. Here would be that....

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
// cl Ex03.cpp /O1 /Os /GS- TCLib.lib kernel32.lib ole32.lib uuid.lib
//  3,584 Bytes VC15 (Visual Studio 2008); UNICODE; x64; TCLib Linkage
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif
#include <windows.h>
#include <Shobjidl.h>
#include "string.h"
#include "stdio.h"

int main()
{
 COMDLG_FILTERSPEC ComDlgFS[3] = {{L"C++ code files", L"*.cpp;*.h;*.rc"},{L"Executable Files", L"*.exe;*.dll"}, {L"All Files",L"*.*"}};
 IFileOpenDialog*  pFileOpen   = NULL;
 IShellItem*       pShellItem  = NULL;
 wchar_t*          ppszName    = NULL;
  
 CoInitialize(NULL);
 CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void**)(&pFileOpen));
 pFileOpen->SetFileTypes(3,ComDlgFS);  
 pFileOpen->SetTitle(L"A Single Selection Dialog");
 pFileOpen->Show(0); 
 pFileOpen->GetResult(&pShellItem);
 pShellItem->GetDisplayName(SIGDN_FILESYSPATH,&ppszName);
 wprintf(L"%s\n",ppszName);                    
 CoTaskMemFree(ppszName);
 pShellItem->Release();
 pFileOpen->Release();    
 CoUninitialize();
 getchar();
 
 return 0;
}

#if 0
C:\Code\VStudio\VC++9\IFileOpen\Ex01>cl Ex03.cpp /O1 /Os /GS- TCLib.lib kernel32.lib ole32.lib oleaut32.lib uuid.lib
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.21022.08 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

Ex03.cpp
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:Ex03.exe
Ex03.obj
TCLib.lib
kernel32.lib
ole32.lib
oleaut32.lib
uuid.lib

C:\Code\VStudio\VC++9\IFileOpen\Ex01>dir
 Volume in drive C is OSDisk
 Volume Serial Number is 3E79-B713

 Directory of C:\Code\VStudio\VC++9\IFileOpen\Ex01

07/08/2017  09:37 AM    <DIR>          .
07/08/2017  09:37 AM    <DIR>          ..
07/08/2017  09:30 AM             2,712 Ex01.cpp
07/08/2017  09:34 AM             3,369 Ex02.cpp
07/08/2017  09:37 AM             1,068 Ex03.cpp
07/08/2017  09:37 AM             3,584 Ex03.exe
07/08/2017  09:37 AM             3,326 Ex03.obj
07/06/2016  02:15 PM               485 malloc.h
07/29/2016  01:57 PM               131 math.h
07/06/2016  02:16 PM               309 memory.h
08/01/2016  08:41 AM             1,313 stdio.h
06/29/2016  02:04 PM             1,512 stdlib.h
05/26/2017  10:58 AM             1,841 string.h
05/26/2017  10:49 AM             1,812 tchar.h
07/06/2017  03:06 PM            41,750 TCLib.lib
07/08/2017  09:09 AM            18,843 tmp.txt
              14 File(s)         82,055 bytes
               2 Dir(s)  166,086,619,136 bytes free

C:\Code\VStudio\VC++9\IFileOpen\Ex01>Ex03
C:\Code\VStudio\VC++9\IFileOpen\Ex01\Ex03.exe
#endif 


You can see a dir directory dump immediately after my invocation at the command line, and I'm getting a 3,584 byte stand alone executable in x64 using my custom C Runtime substitute.

The above program has no error checking. I wouldn't recommend that at all. Here is the same program with error checking...

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
// cl Ex02.cpp /O1 /Os /GS- TCLib.lib kernel32.lib ole32.lib oleaut32.lib uuid.lib
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif
#include <windows.h>
#include <Shobjidl.h>
#include "string.h"
#include "stdio.h"

int main()
{
 COMDLG_FILTERSPEC ComDlgFS[3] = {{L"C++ code files", L"*.cpp;*.h;*.rc"},{L"Executable Files", L"*.exe;*.dll"}, {L"All Files",L"*.*"}};
 IFileOpenDialog*  pFileOpen   = NULL;
 IShellItem*       pShellItem  = NULL;
 wchar_t*          ppszName    = NULL;
 HRESULT           hr;
 
 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 { 
    hr=CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void**)(&pFileOpen));
    if(SUCCEEDED(hr))
    { 
       hr=pFileOpen->SetFileTypes(3,ComDlgFS);  
       if(SUCCEEDED(hr))
       {
          hr=pFileOpen->SetTitle(L"A Single Selection Dialog");
          if(SUCCEEDED(hr))
          {
             hr=pFileOpen->Show(0); 
             if(SUCCEEDED(hr))
             {
                hr=pFileOpen->GetResult(&pShellItem);
                if(SUCCEEDED(hr))
                {
                   hr=pShellItem->GetDisplayName(SIGDN_FILESYSPATH,&ppszName);
                   if(SUCCEEDED(hr))
                   {
                      wprintf(L"%s\n",ppszName);                    
                      CoTaskMemFree(ppszName);
                   }   
                   pShellItem->Release();
                }               
             }            
          }         
       }      
       pFileOpen->Release();    
    }
    CoUninitialize();
 }   
 getchar();
 
 return 0;
}


The above works, of course with Visual Studio. Here is a full GUI example where a button click brings up the IFileOpen Dialog Box, and whatever selection there is gets written to a text box under it...

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
// Main.cpp
// cl Main.cpp /O1 /Os /GS- /FeOpenFile.exe TCLib.lib Kernel32.lib user32.lib ole32.lib uuid.lib
// cl Main.cpp /O1 /Os /MT /FeOpenFile.exe Kernel32.lib User32.lib ole32.lib uuid.lib
// 40,448 Bytes VC15 (VStudio 2008); x64; UNICODE; C Runtime Linkage
//  5,120 Bytes VC15 (VStudio 2008); x64; UNICODE; TCLib Linkage
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif   
#include <windows.h>
#include <Shobjidl.h>
#include "Main.h"


LRESULT __stdcall fnWndProc_OnCreate(WndEventArgs& Wea)
{
 HWND    hCtrl = NULL;
 HRESULT hr;

 hr=CoInitialize(NULL);
 if(SUCCEEDED(hr))
 { 
    Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
    hCtrl=CreateWindowEx(0,L"button",L"Open File...",WS_CHILD|WS_VISIBLE,185,30,125,30,Wea.hWnd,(HMENU)IDC_OPEN,Wea.hIns,0);
    hCtrl=CreateWindowEx(WS_EX_CLIENTEDGE,L"edit",L"",WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL,10,100,460,25,Wea.hWnd,(HMENU)IDC_FILE,Wea.hIns,0);
 }   
 else
    return -1;
   
 return 0;
}


void btnOpen_Click(WndEventArgs& Wea)
{
 COMDLG_FILTERSPEC ComDlgFS[3] = {{L"C++ code files", L"*.cpp;*.h;*.rc"},{L"Executable Files", L"*.exe;*.dll"}, {L"All Files",L"*.*"}};
 IFileOpenDialog*  pFileOpen   = NULL;
 IShellItem*       pShellItem  = NULL;
 wchar_t*          ppszName    = NULL;
 HWND              hCtrl       = NULL; 
 
 CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void**)(&pFileOpen));
 pFileOpen->SetFileTypes(3,ComDlgFS);  
 pFileOpen->SetTitle(L"A Single Selection Dialog");
 pFileOpen->Show(0); 
 pFileOpen->GetResult(&pShellItem);
 pShellItem->GetDisplayName(SIGDN_FILESYSPATH,&ppszName);
 hCtrl=GetDlgItem(Wea.hWnd,IDC_FILE);
 SetWindowText(hCtrl,ppszName); 
 CoTaskMemFree(ppszName);
 pShellItem->Release();
 pFileOpen->Release();    
} 


LRESULT __stdcall fnWndProc_OnCommand(WndEventArgs& Wea)
{
 switch(LOWORD(Wea.wParam))
 {
   case IDC_OPEN:
   {
        btnOpen_Click(Wea);
        break;
   } 
 } 
      
 return 0;
}


LRESULT __stdcall fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 CoUninitialize();
 PostQuitMessage(0);
 
 return 0;
}


LRESULT __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(size_t 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)
{
 wchar_t szClassName[]=L"OpenFile";
 HWND hWnd=NULL;
 MSG messages;
 WNDCLASS wc;
 
 memset(&wc,0,sizeof(WNDCLASS));
 wc.lpszClassName = szClassName,                     wc.lpfnWndProc   = fnWndProc;
 wc.hIcon         = LoadIcon(NULL,IDI_APPLICATION),  wc.hInstance     = hIns;
 wc.hCursor       = LoadCursor(NULL,IDC_ARROW),      wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
 RegisterClass(&wc);
 hWnd=CreateWindow(szClassName,szClassName,WS_OVERLAPPEDWINDOW,300,400,500,225,HWND_DESKTOP,0,hIns,0);
 if(hWnd)
 { 
    ShowWindow(hWnd,iShow);
    while(GetMessage(&messages,NULL,0,0))
    {
       TranslateMessage(&messages);
       DispatchMessage(&messages);
    }
 }

 return (int)messages.wParam;
}


And here's the include file 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
//Main.h
#ifndef Main_h
#define Main_h

#define dim(x)         (sizeof(x) / sizeof(x[0]))
#define IDC_OPEN       2000
#define IDC_FILE       2005

struct WndEventArgs
{
 HWND                  hWnd;
 WPARAM                wParam;
 LPARAM                lParam;
 HINSTANCE             hIns;
};

LRESULT __stdcall      fnWndProc_OnCreate      (WndEventArgs& Wea);
LRESULT __stdcall      fnWndProc_OnCommand     (WndEventArgs& Wea);
LRESULT __stdcall      fnWndProc_OnDestroy     (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int          iMsg;
 LRESULT               (__stdcall* fnPtr)(WndEventArgs&);
};

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


I also developed a High DPI Aware version of the above, but won't post it unless somebody asks.
Hello guys, thank you for all the replies.

It seems pretty clear that this is an issue with GCC, so instead of wasting more time I've decided to build things using microsoft's compiler.

Cheers.
Topic archived. No new replies allowed.