1

I'm trying to build a functionality that copies multiple files with default windows dialog.

I found this examples from microsoft: FileOperationSample.cpp

However I get an error on this line:

IShellItemArray *psia; hr = SHCreateShellItemArray(NULL, psfSampleSrc, c_cMaxFilesToCreate, &rgpidlChildren[0], &psia);

        PITEMID_CHILD rgpidlChildren[c_cMaxFilesToCreate] = { 0 };

        for (UINT i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(rgpidlChildren); i++)
        {
            WCHAR szSampleFileName[MAX_PATH];
            hr = StringCchPrintfW(szSampleFileName, ARRAYSIZE(szSampleFileName), L"%s%u.%s", c_szSampleFileName, i, c_szSampleFileExt);
            if (SUCCEEDED(hr))
            {
                hr = psfSampleSrc->ParseDisplayName(NULL, NULL, szSampleFileName, NULL, (PIDLIST_RELATIVE *)&rgpidlChildren[i], NULL);
            }
        }
        if (SUCCEEDED(hr))
        {
            IShellItemArray *psia;
            hr = SHCreateShellItemArray(NULL, psfSampleSrc, c_cMaxFilesToCreate, &rgpidlChildren[0], &psia);
Anubitum
  • 101
  • 2
  • 5
  • You are probably using a recent VS2017 release. Consider Project > Properties > C/C++ > Language, "Conformance mode" = No. – Hans Passant Dec 01 '18 at 12:29

2 Answers2

4

The sample code compiles without any errors nor warnings with VS2017. However, if I remove #define STRICT_TYPED_ITEMIDS, I get exactly the same error.

Solution:

Make sure, your source code has #define STRICT_TYPED_ITEMIDS before including any Windows headers, ideally at the beginning of your precompiled header (stdafx.h or pch.h, depending on VS version).

Background:

If STRICT_TYPED_ITEMIDS is not defined, the following defines from the shtypes.h are enabled:

#define PITEMID_CHILD LPITEMIDLIST              
#define PCUITEMID_CHILD_ARRAY LPCITEMIDLIST *

So in this case, SHCreateShellItemArray expects a pointer to LPCITEMIDLIST for the 4th parameter, but instead you pass it a pointer to LPITEMIDLIST, which is incompatible with the expected type.

Bonus OldNewThing link:

STRICT_TYPED_ITEMIDS is the shell namespace version of the STRICT macro used by USER and GDI

zett42
  • 25,437
  • 3
  • 35
  • 72
  • 3
    I would add that WinAPI convention has it that types that begin with `LP` are pointers and types that begin with `LPC` are pointers-to-constant. The reason C++ disallows conversions from `LPSTUFF*` to `LPCSTUFF*` is explained in https://stackoverflow.com/questions/2220916/why-isnt-it-legal-to-convert-pointer-to-pointer-to-non-const-to-a-pointer-to , for example. – Wintermute Dec 01 '18 at 10:34
2

Yes, samples from Microsoft sometimes need to be adapted to modern headers from modern SDKs. Usually, the more recent SDK (from Visual Studio or not) you use, the stricter the compilation is.

You can just change rgpidlChildren declaration to (note the 'C', for const):

PCITEMID_CHILD rgpidlChildren[c_cMaxFilesToCreate] = { 0 };
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • 1
    *"samples from Microsoft sometimes need to be adapted to modern headers"* - That's not entirely true. Samples in the MSDN - in the vast majority of cases - assume a C compiler. They don't need to be adjusted to account for changes in the SDK headers. They do need to be adjusted when compiled as a different programming language (like C++). – IInspectable Dec 01 '18 at 11:36
  • @IInspectable - well I guess by "sometimes" I meant "not entirely" and "usually", a cpp file assumes a c++ compiler. – Simon Mourier Dec 01 '18 at 16:18
  • Did you have to modify the sample code to adapt to more recent SDK headers, or did you have to adjust valid C code to compile with a C++ compiler? – IInspectable Dec 02 '18 at 10:50