SHFileOperation error 87 - c++

I am trying to copy the contents of the A drive into folder C:\test\disk1. Folder disk1 already exists. The program compiles but when it runs I get error 87. I know error 87 has something to do with an invalid parameter but Im not sure where the problem lies. Has anyone any ideas?
#include <Windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
const wchar_t *const sourceFile = L"A:\\";
const wchar_t *const outputFile = L"C:\\test\\disk1";
SHFILEOPSTRUCTW fileOperation;
memset(&fileOperation, 0, sizeof(SHFILEOPSTRUCTW));
fileOperation.wFunc = FO_COPY;
fileOperation.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR |
FOF_NOERRORUI | FOF_FILESONLY;
fileOperation.pFrom = sourceFile;
fileOperation.pTo = outputFile;
int result = SHFileOperationW(&fileOperation);
if (result != 0)
{
printf("SHFileOperation Failure: Error%u\n", result);
return 1;
}
memset(&fileOperation, 0, sizeof(SHFILEOPSTRUCTW));
printf("OK\n");
return 0;
}

Note the documentation of SHFILEOPSTRUCT and in particular that of pFrom and pTo:
PCZZTSTR pFrom;
PCZZTSTR pTo;
What does PCZZTSTR mean?
pFrom
Type: PCZZTSTR
Note This string must be double-null terminated.
So your fix is to supply an additional trailing zero.
const wchar_t *const sourceFile = L"A:\\\0";
const wchar_t *const outputFile = L"C:\\test\\disk1\0";
Note that Windows API functions accept / as a directory separator, so that can be written as the slightly easier to read:
const wchar_t *const sourceFile = L"A:/\0";
const wchar_t *const outputFile = L"C:/test/disk1\0";
(PCZZSTR is actually a pointer to a list of zero terminated strings which is terminated by an empty string.)

Related

C++ how to find file path of the file I am working on in my program [duplicate]

I want to create a file in the current directory (where the executable is running).
My code:
LPTSTR NPath = NULL;
DWORD a = GetCurrentDirectory(MAX_PATH,NPath);
HANDLE hNewFile = CreateFile(NPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
I get exception at GetCurrentDirectory().
Why am I getting an exception?
I would recommend reading a book on C++ before you go any further, as it would be helpful to get a firmer footing. Accelerated C++ by Koenig and Moo is excellent.
To get the executable path use GetModuleFileName:
TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
Here's a C++ function that gets the directory without the file name:
#include <windows.h>
#include <string>
#include <iostream>
std::wstring ExePath() {
TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
return std::wstring(buffer).substr(0, pos);
}
int main() {
std::cout << "my directory is " << ExePath() << "\n";
}
The question is not clear whether the current working directory is wanted or the path of the directory containing the executable.
Most answers seem to answer the latter.
But for the former, and for the second part of the question of creating the file, the C++17 standard now incorporates the filesystem library which simplifies this a lot:
#include <filesystem>
#include <iostream>
std::filesystem::path cwd = std::filesystem::current_path() / "filename.txt";
std::ofstream file(cwd.string());
file.close();
This fetches the current working directory, adds the filename to the path and creates an empty file. Note that the path object takes care of os dependent path handling, so cwd.string() returns an os dependent path string. Neato.
GetCurrentDirectory does not allocate space for the result, it's up to you to do that.
TCHAR NPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH, NPath);
Also, take a look at Boost.Filesystem library if you want to do this the C++ way.
An easy way to do this is:
int main(int argc, char * argv[]){
std::cout << argv[0];
std::cin.get();
}
argv[] is pretty much an array containing arguments you ran the .exe with, but the first one is always a path to the executable. If I build this the console shows:
C:\Users\Ulisse\source\repos\altcmd\Debug\currentdir.exe
IMHO here are some improvements to anon's answer.
#include <windows.h>
#include <string>
#include <iostream>
std::string GetExeFileName()
{
char buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
return std::string(buffer);
}
std::string GetExePath()
{
std::string f = GetExeFileName();
return f.substr(0, f.find_last_of( "\\/" ));
}
#include <iostream>
#include <stdio.h>
#include <dirent.h>
std::string current_working_directory()
{
char* cwd = _getcwd( 0, 0 ) ; // **** microsoft specific ****
std::string working_directory(cwd) ;
std::free(cwd) ;
return working_directory ;
}
int main(){
std::cout << "i am now in " << current_working_directory() << endl;
}
I failed to use GetModuleFileName correctly. I found this work very well.
just tested on Windows, not yet try on Linux :)
WCHAR path[MAX_PATH] = {0};
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);
Please don't forget to initialize your buffers to something before utilizing them. And just as important, give your string buffers space for the ending null
TCHAR path[MAX_PATH+1] = L"";
DWORD len = GetCurrentDirectory(MAX_PATH, path);
Reference
You should provide a valid buffer placeholder.
that is:
TCHAR s[100];
DWORD a = GetCurrentDirectory(100, s);
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
You can remove the filename from GetModuleFileName() with more elegant way:
TCHAR fullPath[MAX_PATH];
TCHAR driveLetter[3];
TCHAR directory[MAX_PATH];
TCHAR FinalPath[MAX_PATH];
GetModuleFileName(NULL, fullPath, MAX_PATH);
_splitpath(fullPath, driveLetter, directory, NULL, NULL);
sprintf(FinalPath, "%s%s",driveLetter, directory);
Hope it helps!
GetCurrentDirectory() gets the current directory which is where the exe is invoked from. To get the location of the exe, use GetModuleFileName(NULL ...). if you have the handle to the exe, or you can derive it from GetCommandLine() if you don't.
As Mr. Butterworth points out, you don't need a handle.
Why does nobody here consider using this simple code?
TCHAR szDir[MAX_PATH] = { 0 };
GetModuleFileName(NULL, szDir, MAX_PATH);
szDir[std::string(szDir).find_last_of("\\/")] = 0;
or even simpler
TCHAR szDir[MAX_PATH] = { 0 };
TCHAR* szEnd = nullptr;
GetModuleFileName(NULL, szDir, MAX_PATH);
szEnd = _tcsrchr(szDir, '\\');
*szEnd = 0;
I guess, that the easiest way to locate the current directory is to cut it from command line args.
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
std::string cur_dir(argv[0]);
int pos = cur_dir.find_last_of("/\\");
std::cout << "path: " << cur_dir.substr(0, pos) << std::endl;
std::cout << "file: " << cur_dir.substr(pos+1) << std::endl;
return 0;
}
You may know that every program gets its executable name as first command line argument. So you can use this.
Code snippets from my CAE project with unicode development environment:
/// #brief Gets current module file path.
std::string getModuleFilePath() {
TCHAR buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
CT2CA pszPath(buffer);
std::string path(pszPath);
std::string::size_type pos = path.find_last_of("\\/");
return path.substr( 0, pos);
}
Just use the templete CA2CAEX or CA2AEX which calls the internal API ::MultiByteToWideChar or ::WideCharToMultiByte。
if you don't want to use std, you can use this code:
char * ExePath()
{
static char buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );
char * LastSlash = strrchr(buffer, '\\');
if(LastSlash == NULL)
LastSlash = strrchr(buffer, '/');
buffer[LastSlash-buffer] = 0;
return buffer;
}
I simply use getcwd() method for that purpose in Windows, and it works pretty well. The code portion is like following:
char cwd[256];
getcwd(cwd, 256);
string cwd_str = string(cwd);
The <unistd.h> library has to be added though.
To find the directory where your executable is, you can use:
TCHAR szFilePath[_MAX_PATH];
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
If you are using the Poco library, it's a one liner and it should work on all platforms I think.
Poco::Path::current()
On a give Windows C++ IDE I went crude and it was simple, reliable, but slow:
system( "cd" );
String^ exePath = Application::ExecutablePath;<br>
MessageBox::Show(exePath);
In Windows console, you can use the system command CD (Current Directory):
std::cout << "Current Directory = ";
system("cd"); // to see the current executable directory

How to share a directory using C++ so everyone can access

I'm trying to make a program so that when it run, it will create a new folder on C://. I also want to add a feature where the folder can have a shared permission to everyone. So, everyone can access and read/write
I've tried using netshareadd but I always got a compiler warning, how do I get rid of it?
This is creating new directory code :
#include <direct.h>
int main()
{
mkdir("c:/scan");
return 0;
}
This is the netshareadd code :
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <lm.h>
#pragma comment(lib, "Netapi32.lib")
void wmain( int argc, TCHAR *argv[ ])
{
NET_API_STATUS res;
SHARE_INFO_2 p;
DWORD parm_err = 0;
if(argc<2)
printf("Usage: NetShareAdd server\n");
else
{
//
// Fill in the SHARE_INFO_2 structure.
//
p.shi2_netname = TEXT("TESTSHARE");
p.shi2_type = STYPE_DISKTREE; // disk drive
p.shi2_remark = TEXT("TESTSHARE to test NetShareAdd");
p.shi2_permissions = 0;
p.shi2_max_uses = 4;
p.shi2_current_uses = 0;
p.shi2_path = TEXT("C:\\scan");
p.shi2_passwd = NULL; // no password
//
// Call the NetShareAdd function,
// specifying level 2.
//
res=NetShareAdd(argv[1], 2, (LPBYTE) &p, &parm_err);
//
// If the call succeeds, inform the user.
//
if(res==0)
printf("Share created.\n");
// Otherwise, print an error,
// and identify the parameter in error.
//
else
printf("Error: %u\tparmerr=%u\n", res, parm_err);
}
return;
}
22 22 D:\kerja\NETSHARE.cpp [Warning] deprecated conversion from
string constant to 'LPWSTR {aka wchar_t*}' [-Wwrite-strings]
This is the warning that I always got when compiling the netshareadd code
NetShareAdd requires a non const parameter. Some Windows APIs modify the passed buffer (or are way old) so you need a wchar_t*, not a const wchar_t* which is what a L"string" produces.
Solution, copy the const wchar_t* into a vector and pass the vector's data() member to the function (don't forget the null terminator).

How to convert wcstombs to wcstombs_s

How can I convert the following code to use wcstombs_s instead of wcstombs?
char dbcs[1024];
char *pbstr = (char *)pPropVar->bstrVal;
int i = wcstombs(dbcs, pPropVar->bstrVal, *((DWORD *)(pbstr - 4)));
char dbcs[1024];
char *pbstr = (char *)pPropVar->bstrVal;
size_t i;
int err = wcstombs_s(&i, dbcs, 1024, pPropVar->bstrVal, *((DWORD *)(pbstr - 4)));
Note
By the way, you can tell the compiler not to warn about non secure calls:
#define _CRT_SECURE_NO_DEPRECATE

On Windows is there an interface for Copying Folders?

I want to copy folder A and paste to desktop.
I am currently using C++ so preferably an OO interface if available.
On Windows (Win32), you could use SHFileOperation, eg:
SHFILEOPSTRUCT s = { 0 };
s.hwnd = m_hWnd;
s.wFunc = FO_COPY;
s.fFlags = FOF_SILENT;
s.pTo = "C:\\target folder\0";
s.pFrom = "C:\\source folder\\*\0";
SHFileOperation(&s);
Use this
bool CopyDirTo( const wstring& source_folder, const wstring& target_folder )
{
wstring new_sf = source_folder + L"\\*";
WCHAR sf[MAX_PATH+1];
WCHAR tf[MAX_PATH+1];
wcscpy_s(sf, MAX_PATH, new_sf.c_str());
wcscpy_s(tf, MAX_PATH, target_folder.c_str());
sf[lstrlenW(sf)+1] = 0;
tf[lstrlenW(tf)+1] = 0;
SHFILEOPSTRUCTW s = { 0 };
s.wFunc = FO_COPY;
s.pTo = tf;
s.pFrom = sf;
s.fFlags = FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NO_UI;
int res = SHFileOperationW( &s );
return res == 0;
}
Starting with Visual Studio 2015 you can use std::filesystem::copy which is even platform independent since it is available in implementations supporting >= C++17.
#include <exception>
#include <experimental/filesystem> // C++-standard filesystem header file in VS15, VS17.
#include <iostream>
namespace fs = std::experimental::filesystem; // experimental for VS15, VS17.
/*! Copies all contents of path/to/source/directory to path/to/target/directory.
*/
int main()
{
fs::path source = "path/to/source/directory";
fs::path targetParent = "path/to/target";
auto target = targetParent / source.filename(); // source.filename() returns "directory".
try // If you want to avoid exception handling then use the error code overload of the following functions.
{
fs::create_directories(target); // Recursively create target directory if not existing.
fs::copy(source, target, fs::copy_options::recursive);
}
catch (std::exception& e) // Not using fs::filesystem_error since std::bad_alloc can throw too.
{
std::cout << e.what();
}
}
Change the behaviour of fs::copy with std::filesystem::copy_options. I've used std::filesystem::path::filename to retrieve the source directory name without having to type it manually.
(assuming Windows)
Use can use ShFileOperation (or IFileOperation::CopyItem on Vista).
Max.
For a platform agnostic solution, I'd suggest Boost::filesystem. That link is basically the reference material. There is a copy_file method that copies a file from one location to another.
On Windows, the desktop is a special folder:
// String buffer for holding the path.
TCHAR strPath[ MAX_PATH ];
// Get the special folder path.
SHGetSpecialFolderPath(
0, // Hwnd
strPath, // String buffer.
CSIDL_DESKTOPDIRECTORY, // CSLID of folder
FALSE ); // Create if doesn't exists?
Here's an example using SHFileOperation:
http://msdn.microsoft.com/en-us/library/bb776887%28VS.85%29.aspx#example
Here's a quick hack without it:
#import <stdlib.h>
int main(int argc, char *argv[]) {
system("robocopy \"C:\\my\\folder\" \"%userprofile%\\desktop\\\" /MIR");
return 0;
}
it works
#include <iostream>
int main()
{
system("xcopy C:\\Users\\Elmi\\Desktop\\AAAAAA\ C:\\Users\\Elmi\\Desktop\\b\ /e /i /h");
return 0;
}

invalid conversion from ‘const void*’ to ‘const char*’ in tokoyo cabinate table database

i am new to tokyo cabin ate and i compile the example program and i am getting an error can any one tell me why i get this error invalid conversion from ‘const void*’ to ‘const char*’
#include <tcutil.h>
#include <tctdb.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
int main(int argc, char **argv){
TCTDB *tdb;
int ecode, pksiz, i, rsiz;
char pkbuf[256];
const char *rbuf, *name;
TCMAP *cols;
TDBQRY *qry;
TCLIST *res;
/* create the object */
tdb = tctdbnew();
/* open the database */
if(!tctdbopen(tdb, "casket.tct", TDBOWRITER | TDBOCREAT)){
ecode = tctdbecode(tdb);
fprintf(stderr, "open error: %s\n", tctdberrmsg(ecode));
}
/* store a record */
pksiz = sprintf(pkbuf, "%ld", (long)tctdbgenuid(tdb));
cols = tcmapnew3("name", "mikio", "age", "30", "lang", "ja,en,c", NULL);
if(!tctdbput(tdb, pkbuf, pksiz, cols)){
ecode = tctdbecode(tdb);
fprintf(stderr, "put error: %s\n", tctdberrmsg(ecode));
}
tcmapdel(cols);
/* store a record in a naive way */
pksiz = sprintf(pkbuf, "12345");
cols = tcmapnew();
tcmapput2(cols, "name", "falcon");
tcmapput2(cols, "age", "31");
tcmapput2(cols, "lang", "ja");
if(!tctdbput(tdb, pkbuf, pksiz, cols)){
ecode = tctdbecode(tdb);
fprintf(stderr, "put error: %s\n", tctdberrmsg(ecode));
}
tcmapdel(cols);
/* store a record with a TSV string */
if(!tctdbput3(tdb, "abcde", "name\tjoker\tage\t19\tlang\ten,es")){
ecode = tctdbecode(tdb);
fprintf(stderr, "put error: %s\n", tctdberrmsg(ecode));
}
/* search for records */
qry = tctdbqrynew(tdb);
tctdbqryaddcond(qry, "age", TDBQCNUMGE, "20");
tctdbqryaddcond(qry, "lang", TDBQCSTROR, "ja,en");
tctdbqrysetorder(qry, "name", TDBQOSTRASC);
tctdbqrysetlimit(qry, 10, 0);
res = tctdbqrysearch(qry);
for(i = 0; i < tclistnum(res); i++){
rbuf = tclistval(res, i, &rsiz);
cols = tctdbget(tdb, rbuf, rsiz);
if(cols){
printf("%s", rbuf);
tcmapiterinit(cols);
while((name = tcmapiternext2(cols)) != NULL){
printf("\t%s\t%s", name, tcmapget2(cols, name));
}
printf("\n");
tcmapdel(cols);
}
}
tclistdel(res);
tctdbqrydel(qry);
/* close the database */
if(!tctdbclose(tdb)){
ecode = tctdbecode(tdb);
fprintf(stderr, "close error: %s\n", tctdberrmsg(ecode));
}
/* delete the object */
tctdbdel(tdb);
return 0;
}
The example file is obviously intended to be compiled as C, not as C++. The cast rbuf = tclistval(res, i, &rsiz); (rbuf is of type const char*) is valid in C, but in C++, you need to be explicit. It seems like you set up Eclipse to compile the source file as C++ - if the cast is the only error you get, you can solve it like so:
rbuf = (const char*)tclistval(res, i, &rsiz); // explicit cast to const char*
Or change your settings to compile as C.
It might be possible that you need to surround the Tokyo Cabinet header files with extern C { ... } if they don't support inclusion in C++ themselves.
you are trying to fill in one of the columns(char*) in your functions which is of type void* , if you see line at which this error is coming, you will get to know where you are doing.
This is generic c++ error, nothing to do with tokyocabinet, this is what I believe.
--
Cheers
Tokyocabinet looks like a c library. In c, you can cast pointer of any type to (void *) and (void *) to any type. Like this:
int *array = malloc(10*sizeof(int));
In c++, this is forbidden, you have to cast manually:
int *array = (int *)malloc(10*sizeof(int));