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);
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
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 };
Related
I am starting to work with WIA 2.0 and, as so many others, have started from the MS provided tutorial & example code (see this http://msdn.microsoft.com/en-us/library/ms629848%28v=VS.85%29.aspx).
Unlike the others what I have been unable to find is where the GUIDs CLSID_WiaDevMgr2 & IID_IWiaDevMgr2 are defined.
My code compiles - the variables are declared in wia_lh.h - but fails to build with error messages that these two symbols are unresolved i.e. not defined.
HRESULT CWiaSP::CreateWiaDeviceManager()
{
pWiaDevMgr = NULL;
HRESULT hr = CoCreateInstance( CLSID_WiaDevMgr2, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr2, (void**)&pWiaDevMgr );
return hr;
}
How to identify the GUID value for these: can this be done programmatically, or are they well known values that are defined somewhere?
I was trying to compile some example code from MSDN with GCC on Windows 7 (please ignore the use of goto and the terrible formatting; it's not my code):
#include <stdio.h>
#include <windows.h>
typedef struct _TOKEN_ELEVATION {
DWORD TokenIsElevated;
} TOKEN_ELEVATION, *PTOKEN_ELEVATION;
BOOL IsProcessElevated()
{
BOOL fIsElevated = FALSE;
DWORD dwError = ERROR_SUCCESS;
HANDLE hToken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
dwError = GetLastError();
goto Cleanup;
}
TOKEN_ELEVATION elevation;
DWORD dwSize;
if (!GetTokenInformation(hToken, TokenElevation, &elevation,
sizeof(elevation), &dwSize))
{
dwError = GetLastError();
goto Cleanup;
}
fIsElevated = elevation.TokenIsElevated;
Cleanup:
if (hToken)
{
CloseHandle(hToken);
hToken = NULL;
}
if (ERROR_SUCCESS != dwError)
{
throw dwError;
}
return fIsElevated;
}
int main()
{
try
{
if (IsProcessElevated())
wprintf (L"Process is elevated\n");
else
wprintf (L"Process is not elevated\n");
}
catch (DWORD dwError)
{
wprintf(L"IsProcessElevated failed w/err %lu\n", dwError);
}
}
I kept getting the error TokenElevation was not declared in this scope. While trying to figure it out I saw that the TokenElevation member of the TOKEN_INFORMATION_CLASS struct was between two #ifdef tags:
typedef enum _TOKEN_INFORMATION_CLASS {
TokenUser=1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
//#if (_WIN32_WINNT >= 0x0600)
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
//#endif
MaxTokenInfoClass
} TOKEN_INFORMATION_CLASS;
I commented these out and the code compiled without errors or warnings. My question is really two questions. Is their a better way to do this (define something in my code?) and, in the long run, will editing header files hurt me?
Editing the headers will hurt because your code is no longer being built against an external library you simply depend on. Instead you have effectively made that external code part of your project, and now you have to manage it like other source code in your project. You should keep it in your version control system, for example.
Yes, there is a better way: you can simply define _WIN32_WINNT as the Windows code expects it to be defined. Visual Studio projects define this macro by default, but you have to do that manually when building with gcc on Windows.
This page defines the values for each version of Windows.
Yes, you can edit and change GCC header files.
Be aware that when GCC upgrades, your changes may be lost. You would have to merge your changes into the newer header files.
For this reason, common rule of thumb is not to modify compiler header files.
Edit 1:
Also, if you share your code, you will need to have the clients make the same mods to the GCC header files that you did. Some clients may not want their compiler header files changed. Same rules apply when you have other people working on the same project.
Also, will your changes affect future projects? Future projects may use the GCC header files also.
You can modify them but it is usually a bad idea, because it will make you compilation difficult to repeat.
In this particular case, the right solution is just to define _WIN32_WINNT as 0x0600 or higher. This macro is used to specify the Windows version you are targeting, and you clearly are targeting at least version 6, or you would not be able to use this value. The Windows SDK header files use this macro to conditially include declarations available in every version of Windows, so you cannot use a function/field/enum value from Windows 8 in a program intended to run in Windows 7, for example.
So just add -D_WIN32_WINNT=0x0600 to your compilation command and leave the header files alone...
I need to be able to read the target of a shortcut (a .lnk file).
I have Googled this and found numerous results that I have found to be helpful:
http://cboard.cprogramming.com/windows-programming/62962-ishelllink-getpath-dev-cplusplus.html
http://www.go4answers.com/Example/get-shortcut-target-cpp-win64-216615.aspx
http://msdn.microsoft.com/en-us/library/bb776891%28VS.85%29.aspx
http://www.codeproject.com/KB/shell/create_shortcut.aspx
Some of these web pages don't mention which header files I need, and I am unaware how to find this information out.
The code that I am currently trying to get working is this:
#include <windows.h>
#include <string>
#include <objidl.h> /* For IPersistFile */
#include <shlobj.h> /* For IShellLink */
using namespace std;
int main(void)
{
IShellLink* psl;
wchar_t* tempStr = new wchar_t[MAX_PATH];
string path = "E:\\shortcuts\\myshortcut.lnk";
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &psl);
if (SUCCEEDED(hr))
{
IPersistFile* ppf;
hr = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
if (SUCCEEDED(hr))
{
hr = ppf->Load(path.c_str(), STGM_READ);
if (SUCCEEDED(hr))
{
WIN32_FIND_DATA wfd;
psl->GetPath(tempStr, MAX_PATH, &wfd, SLGP_UNCPRIORITY | SLGP_RAWPATH);
}
}
}
return 0;
}
You can probably see that this is mainly from one of the websites above, however they did not mention which headers they used, so I had a good guess (which seems to be working) at which ones to use.
Currently the errors I am getting are:
In function 'int main()':
24|error: no matching function for call to 'IPersistFile::Load(const char*, int)'
29|error: no matching function for call to 'IShellLinkA::GetPath(wchar_t*&, int, WIN32_FIND_DATA*, int)'
||=== Build finished: 2 errors, 0 warnings ===|
I was hoping that someone may be able to give me some advice on this, whether it is just pointing me to some better links or, even better, possibly explaining the above code, how to find out which headers to use and where I am going wrong, or an entirely different solution that achieves the same result.
All headers are fine, but you are using wide (wchar_t based) and 'normal' (char based) strings incorrectly: IPersistFile::Load takes a wide string while IShellLinkA::GetPath takes a normal string.
Using this should compile:
IShellLinkA* psl; //specify the ansi version explicitely
CoInitialize( 0 ); //you forgot this, needed for all COM calls to work
char* tempStr = new char[ MAX_PATH ];
std::wstring path = L"E:\\shortcuts\\myshortcut.lnk";
Also if you just want the path, you can just pass 0 instead of a pointer to a WIN32_FIND_DATA.
i want to read a file.. but.. when i debug my program it runs but a pop up appears and says system programming has stopped working and in the console, it`s written that Press enter to close the program. my code is ::
// System Programming.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hin;
HANDLE hout;
TCHAR buff[20]= {'q','2','3'};
TCHAR buff2[20]={'a','v'};
hin = CreateFile(_T("Abid.txt"),GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hin == INVALID_HANDLE_VALUE)
{
cout<<"error";
}
WriteFile(hin,buff,40,0,NULL);
CloseHandle(hin);
hout = CreateFile(_T("Abid.txt"),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hout == INVALID_HANDLE_VALUE)
{
cout<<"error";
}
ReadFile(hout,buff2,40,0,NULL);
CloseHandle(hout);
return 0;
}
According to MSDN, lpNumberOfBytesWritten paremeter can be NULL only when the lpOverlapped parameter is not NULL. So the calls should be
DWORD nWritten;
WriteFile(hin, buff, 40, &nWritten, NULL);
and
DWORD nRead;
ReadFile(hout, buff2, 40, &nRead, NULL);
Also, rename hin and hout.
Others have already answered your question. This is about the code.
// Your code:
// System Programming.cpp : Defines the entry point for the console application.
//
Just remove that comment. It isn't true. :-) The entry point for your program is where the machine code starts executing, and with the Microsoft toolchain it's specified by the /entry linker option.
Note that Microsoft's documentation is generally confused about entry points, e.g. it has always, one way or other, documented incorrect signature for entry point.
It's one of the most infamous Microsoft documentation errors, and, given that it's persisted, in various forms, for 15 years, I think it says something (not sure exactly what, though).
// Your code:
#include "stdafx.h"
You don't need this automatically generated header. Instead use <windows.h>. A minimal way to include <windows.h> for your program would be
#undef UNICODE
#define UNICODE
#include <windows.h>
For C++ in general you'll want to also make sure that STRICT and NOMINMAX are defined before including <windows.h>. With modern tools at least STRICT is defined by default, but it doesn't hurt to make sure. Without it some of declarations won't compile with a C++ compiler, at least not without reinterpret casts, e.g. dialog procedures.
// Your code:
#include "iostream"
using namespace std;
Almost OK.
Do this:
#include <iostream>
using namespace std;
The difference is where the compiler searches for headers. With quoted name it searches in some additional places first (and that's all that the standard has to say about it). With most compilers those additional places include the directory of the including file.
// Your code:
int _tmain(int argc, _TCHAR* argv[])
Oh no! Don't do this. It's a Microsoft "feature" that helps support Windows 9.x. And it's only relevant when you're using MFC linked dynamically and you're targeting Windows 9.x; without MFC in the picture you'd just use the Microsoft Unicode layer.
Area you really targeting Windows 9.x with an app using dynamically linked MFC?
Instead, do ...
int main()
... which is standard, or use the Microsoft language extension ...
int wMain( int argc, wchar_t* argv[] )
... if you want to handle command line arguments the "easy" way.
// Your code:
{
HANDLE hin;
HANDLE hout;
TCHAR buff[20]= {'q','2','3'};
TCHAR buff2[20]={'a','v'};
The TCHAR stuff is just more of that MFC in Windows 9.x support stuff.
Apart from being totally unnecessary (presumably, you're not really targeting Windows 9.x, are you?), it hides your intention and hurts the eyes.
Did you mean ...
char buff[20] = {'q', '2', '3'};
... perhaps?
// Your code:
hin = CreateFile(_T("Abid.txt"),GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hin == INVALID_HANDLE_VALUE)
{
cout<<"error";
}
As others have mentioned, OPEN_EXISTING isn't logical when you're creating the file, and the count pointer argument can't be 0 for your usage.
When using <windows.h>, with UNICODE defined as it should be, the filename argument should be specifed as L"Abid.txt".
Cheers & hth.,
The problem is that you're passing a NULL pointer in for the lpNumberOfBytesWritten/lpNumberOfBytesread parameter. While this is an optional parameter, there's a condition:
This parameter can be NULL only when the lpOverlapped parameter is not NULL
Also, you may have the size of your buffers wrong:
WriteFile(hin,buff,40,0,NULL); // says that buff has 40 bytes
ReadFile(hout,buff2,40,0,NULL); // says that buff2 has 40 bytes
But if you're compiling for ANSI instead of UNICODE, these will only be 20 bytes in size.
You should probably use sizeof(buff) and sizeof(buff2) instead.
Assuming your initial code attempts to create the file as a new file, then you cannot use OPEN_EXISTING, you have to use OPEN_ALWAYS (or some other creational variant) on this call.
The OPEN_EXISTING usage for readback will be OK.
btw once this is fixed the WriteFile calls causes an access violation, as you are trying to write more bytes that your array contains.
When I try to compile my code with the function GetLongPathName(), the compiler tells me that the function is undeclared.
I have already read the MSDN documentation located # http://msdn.microsoft.com/en-us/library/aa364980%28VS.85%29.aspx. But, even though I included those header files, I am still getting the undeclared function error. Which header file(s) am I supposed to include when using the function?
#include <Windows.h>
#include <WinBase.h>
#define DLLEXPORT extern "C" __declspec(dllexport)
DLLEXPORT char* file_get_long(char* path_original)
{
long length = 0;
TCHAR* buffer = NULL;
if(!path_original)
{
return "-10";
}
length = GetLongPathName(path_original, NULL, 0);
if(length == 0)
{
return "-10";
}
buffer = new TCHAR[length];
length = GetLongPathName(path_original, buffer, length);
if(length == 0)
{
return "-10";
}
return buffer;
}
And, if it makes a difference, I am currently compiling using Dev-C++ on a Windows Vista 64-bit.
Dev-C++'s support of the Windows API is not complete. Actually, it's not even close. It is entirely likely that the GetLongPathName function is not declared in winbase.h that is shipped with that compiler (Actually an old version of MinGW).
You can use the free compiler which ships with the Windows SDK to work around the problem. It is the same compiler that ships with Visual Studio, though it is commandline only.
You can also use Visual C++ Express Edition, which is free and provides features similar to DevCPP.