5

I am having troubles using SHGetKnownFolderPath() function. I am getting the following error message: Type error in argument 1 to 'SHGetKnownFolderPath'; expected 'const struct _GUID *' but found 'struct _GUID'.

In the KnowFolders.h we have the following relevant definitions:

#define DEFINE_KNOWN_FOLDER(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
    EXTERN_C const GUID name
...
DEFINE_KNOWN_FOLDER(FOLDERID_ProgramFiles,0x905e63b6,0xc1bf,0x494e,0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a);

I am using Pelles C compiler .

This is my sample code:

#include <windows.h>
#include <wchar.h>
#include <KnownFolders.h>
#include <shlobj.h>

int wmain(int argc, wchar_t **argv) {

    PWSTR path = NULL;

    HRESULT hr = SHGetKnownFolderPath(FOLDERID_ProgramFiles, 0, NULL, &path);    

    if (SUCCEEDED(hr)){

        wprintf(L"%ls", path);
    }

    CoTaskMemFree(path);

    return 0;
}

How to fix this error message?

EDIT I have found code examples with SHGetKnownFolderPath(); all of them execute the function without the pointer. For instance:

hr = SHGetKnownFolderPath(FOLDERID_Public, 0, NULL, &pszPath);
if (SUCCEEDED(hr))
{
    wprintf(L"FOLDERID_Public: %s\n", pszPath);
    CoTaskMemFree(pszPath);
}

CppShellKnownFolders.cpp

Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77
  • 3
    It wants a pointer to a GUID, so pass it a pointer. `SHGetKnownFolderPath(&FOLDERID_ProgramFiles, ...);` – Jonathan Potter Jan 27 '16 at 16:39
  • 3
    The error message could hardly be more clear. It says: *Type error in argument 1 to 'SHGetKnownFolderPath'; expected 'const struct _GUID *' but found 'struct _GUID'* That could not be made any more clear. I presume you understand the concept of a type mismatch? – David Heffernan Jan 27 '16 at 16:41
  • @JonathanPotter Already tried. Leads to Unresolved external symbol 'FOLDERID_ProgramFiles'. error. Besides, working examples that I have found do not pass a pointer. – Jan Bodnar Jan 27 '16 at 16:43
  • @JanBodnar show the relevant part of one of these working examples. – Jabberwocky Jan 27 '16 at 16:46
  • Your code compiles and works with my Visual Studio 2013. – Jabberwocky Jan 27 '16 at 16:50
  • @MichaelWalz I have added a link to code example. I am using Pelles C. – Jan Bodnar Jan 27 '16 at 16:52
  • @JanBodnar the code you linked to also compiles fine here a part from the missing symbols in "ressource.h" which you didn't provide, but once the symbols defined it compiles fine with VS2013. – Jabberwocky Jan 27 '16 at 17:00
  • 4
    You need at least one compilation unit that #defines `INITGUID` before including `shlobj.h`. See https://support.microsoft.com/en-us/kb/130869 for an explanation. Be aware that all the examples you have found are based on Visual C++, not the compiler you are using. – Jonathan Potter Jan 27 '16 at 17:01
  • 3
    By the way, if fixing a **compiler** error then causes a **linker** error, it doesn't mean the fix for the compiler error was wrong. It means you have two errors. – Jonathan Potter Jan 27 '16 at 17:03
  • I am starting to get it. SHGetKnownFolderPath's first parameter is REFKNOWNFOLDERID, which is defined as a reference for C++ and as a pointer for C. (Pelles C is a C compiler.) That's why the code example compiled on Visual Studio, where C++ is often used for C programs. – Jan Bodnar Jan 27 '16 at 17:58
  • Once again, could the compiler error have been any more clear. Did you really not understand it. I think you should concentrate on what the error is telling you. – David Heffernan Jan 27 '16 at 19:12
  • 1
    One also wonders why you tagged your question c++. These are two different languages. Are you compiling the code in both C and C++? If so fine. If not, please pick one language, the one you are using. – David Heffernan Jan 27 '16 at 19:13
  • Your update just popped this question up on my feed. I don't understand what the problem you're still having is. It looks like you are getting terribly confused about the difference between C and C++. *They are not the same language.* You are using a C compiler, but studying code samples in C++. That's going to get you into trouble, you can't just copy and paste what the C++ folks do. The Windows API is a C API, so this is all usable from C, but the syntax might look a little different for the COM-based functions, like this. You still can't get it to compile by following Jonathan's advice? – Cody Gray - on strike Jan 30 '16 at 14:53
  • @CodyGray The problem is fixed. I wanted to provide an answer for this question; it might be helpful for someone else. – Jan Bodnar Jan 30 '16 at 14:59

2 Answers2

17

With the help from the comments of Jonathan Potter, I was able to correct the example.

The problem was very subtle. The following code line looks like C, but it is actually C++.

HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &path);

The SHGetKnownFolderPath() function has the following prototype:

STDAPI SHGetKnownFolderPath(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR*);

Its first argument is REFKNOWNFOLDERID.

In the shtypes.h file we find the following:

#ifdef __cplusplus
#define REFKNOWNFOLDERID const KNOWNFOLDERID &
#else
#define REFKNOWNFOLDERID const KNOWNFOLDERID * /*__MIDL_CONST*/
#endif /* __cplusplus */

This means, that in C++ REFKNOWNFOLDERID is a reference and in C it is a pointer. As a consequence, we do not need an ampersand in C++ code for the first parameter. In Visual C++ C code is often compiled with C++ and the distinction between the languages is often blurred.

The second issue, the Unresolved external symbol 'FOLDERID_ProgramFiles'. error. error is fixed by adding #include <initguid.h> before #include <ShlObj.h>. The reason is explained in this article.

So the following code compiles on Pelles C.

#include <windows.h>
#include <initguid.h>
#include <KnownFolders.h>
#include <ShlObj.h>
#include <wchar.h>

int wmain(void) {

    PWSTR path = NULL;

    HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);

    if (SUCCEEDED(hr)) {
        wprintf(L"%ls\n", path);
    }

    CoTaskMemFree(path);

    return 0;
}
Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77
3

It would help to understand that the variable FOLDERID_Documents is actually a GUID structure: it's defined in the GuidDef.h header.

typedef struct {
unsigned long  Data1;
unsigned short Data2;
unsigned short Data3;
byte           Data4[ 8 ];
} GUID;

I had problems with this also. I think the confusion arises from the previous use of CSIDLs which were not structures, but simply a number type. It also would help, if MSDN documentation showed an example. So, I'm including one here:

    #include <windows.h>
    #include <KnownFolders.h>
    #include <shlobj.h>
    #include <stdio.h>

    int main (void)
    { 
        PWSTR path ;
        SHGetKnownFolderPath(&FOLDERID_Public, 0, NULL, &path) ;
        wprintf(L"%s\nSize of FOLDERID: %d bytes\n", path, sizeof(FOLDERID_Public)) ;
        wprintf(L"{%x-%hx-%hx-%x%x%x%x%x%x%x%x}\n", FOLDERID_Public.Data1, FOLDERID_Public.Data2, FOLDERID_Public.Data3, FOLDERID_Public.Data4[0], FOLDERID_Public.Data4[1], FOLDERID_Public.Data4[2], FOLDERID_Public.Data4[3], FOLDERID_Public.Data4[4], FOLDERID_Public.Data4[5], FOLDERID_Public.Data4[6], FOLDERID_Public.Data4[7]) ;
        CoTaskMemFree((LPVOID)path)  ;
        return 0 ;
    }