#include "stdafx.h"
#include <string>
#include <windows.h>
using namespace std;
int main()
{
string FilePath = "C:\\Documents and Settings\\whatever";
CreateDirectory(FilePath, NULL);
return 0;
}
Error: error C2664: 'CreateDirectory' : cannot convert parameter 1 from 'const char *' to 'LPCTSTR'
How do I make this conversion?
The next step is to set today's date as a string or char and concatenate it with the filepath. Will this change how I do step 1?
I am terrible at data types and conversions, is there a good explanation for 5 year olds out there?
std::string is a class that holds char-based data. To pass a std::string data to API functions, you have to use its c_str() method to get a char* pointer to the string's actual data.
CreateDirectory() takes a TCHAR* as input. If UNICODE is defined, TCHAR maps to wchar_t, otherwise it maps to char instead. If you need to stick with std::string but do not want to make your code UNICODE-aware, then use CreateDirectoryA() instead, eg:
#include "stdafx.h"
#include <string>
#include <windows.h>
int main()
{
std::string FilePath = "C:\\Documents and Settings\\whatever";
CreateDirectoryA(FilePath.c_str(), NULL);
return 0;
}
To make this code TCHAR-aware, you can do this instead:
#include "stdafx.h"
#include <string>
#include <windows.h>
int main()
{
std::basic_string<TCHAR> FilePath = TEXT("C:\\Documents and Settings\\whatever");
CreateDirectory(FilePath.c_str(), NULL);
return 0;
}
However, Ansi-based OS versions are long dead, everything is Unicode nowadays. TCHAR should not be used in new code anymore:
#include "stdafx.h"
#include <string>
#include <windows.h>
int main()
{
std::wstring FilePath = L"C:\\Documents and Settings\\whatever";
CreateDirectoryW(FilePath.c_str(), NULL);
return 0;
}
If you're not building a Unicode executable, calling c_str() on the std::string will result in a const char* (aka non-Unicode LPCTSTR) that you can pass into CreateDirectory().
The code would look like this:
CreateDirectory(FilePath.c_str(), NULL):
Please note that this will result in a compile error if you're trying to build a Unicode executable.
If you have to append to FilePath I would recommend that you either continue to use std::string or use Microsoft's CString to do the string manipulation as that's less painful that doing it the C way and juggling raw char*. Personally I would use std::string unless you are already in an MFC application that uses CString.
Related
I'm trying to write a program capable of renaming files, but I'm encountering a weird issue.
When I write this:
string oldname, newname;
rename(oldname, newname);
Everything works fine. The file is renamed and there are no problems.
But then when I go ahead and try this:
int result;
result = rename(oldname, newname);
if(result)
//stuff
else
//other stuff
The "=" gets a fresh new red underline and I get an error "a value of type "void" cannot be assigned to an entity of type "int"".
I also tried
if(rename(oldname, newname))
//stuff
Then I just get "expression must have bool type (or be convertible to bool)"
Microsoft's documentation says that the rename function returns 0 if successful and nonzero if not successful. After a lot of googling I found countless examples of code that use the second or third snippet without issue, and none of it has helped me understand what might be different in my situation. The language standard is C++17. I can't think of any other relevant details, but just in case, here is a snippet of the actual code with all the "includes":
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#include <vector>
#include <string>
#include <filesystem>
#include <fstream>
#include <time.h>
#include <iostream>
#include <codecvt>
#include <locale>
#include <sstream>
#include <windowsx.h>
#include <Shlobj.h>
using namespace std;
using namespace std::filesystem;
tmp_wstr = oldname + L"\n\nwill be renamed to:\n\n" + newname + L"\n\nWould you like to proceed?";
msgboxID = MessageBox(NULL, tmp_wstr.c_str(), L"Renaming...", MB_YESNO | MB_SYSTEMMODAL);
switch (msgboxID)
{
case IDYES:
result = rename(oldname, newname);
if (result)
{
error = true;
msgboxID = MessageBox(NULL, L"Unable to rename", NULL, MB_OK | MB_SYSTEMMODAL);
}
else
error = false;
break;
case IDNO:
error = true;
break;
}
Here oldname and newname are wstring instead of string, but I have tried using string and the error persists.
You are expecting to call the C standard library function rename() with signature:
int rename(const char*, const char*);
But that function would not be a viable overload for rename(oldname, newname) if oldname and newname are of type std::(w)string, since std::(w)string is not implicitly convertible to const char*.
So, you must be calling a different function named rename(). Since you used:
using namespace std::filesystem;
you are, in fact, calling the following overload of the C++ standard library function std::filesystem::rename() with signature:
void rename(const std::filesystem::path&, const std::filesystem::path&);
which is viable with your arguments, since std::filesystem::path is constructible from std::(w)string.
This function has a void return type, explaining the error messages. As explained in the link, it doesn't return a status code, but instead throws an exception if there is an error.
I'm using the following ultra-super-mega simple code to list all the files in a direcory (Windows 8.1, Visual Studio Express 2013, C++):
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <limits>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <bitset>
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
using namespace std;
void get_file_list(string DATA_DIR)
{
HANDLE hFind;
WIN32_FIND_DATA data;
hFind = FindFirstFile(LPCWSTR(DATA_DIR.c_str()), &data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
printf("%s\n", data.cFileName);
} while (FindNextFile(hFind, &data));
FindClose(hFind);
}
}
int main(int argc, char** argv)
{
string DATA_DIR = "D:\\drobpox\\Dropbox\\BinaryDescriptors\\LFW\\DATA\\*.*";
//string DATA_DIR = "c:\\Users\\GilLevi\\Downloads\\GraphsSURF\\GraphsSURF\\bark\\*.jpg";
string OUT_DIR = "D:\\drobpox\\Dropbox\\BinaryDescriptors\\LFW\\LATCH_TXT_FILES\\LATCH8";
get_file_list(DATA_DIR);
}
However, I "hFind" always equals "INVALID_HANDLE_VALUE". I double checked the path and tried various different paths.
Might the reason be that I'm running a 64bit application and using WIN32_FIND_DATA ?
Thanks in advance,
Gil
Converting a string to a widestring requires you to allocate memory and use string conversion functions.
If you don't want to change the function, the easiest solution is probably to use the non-unicode version of FindFirstFile, by Adding a A to the functionname and struct;
WIN32_FIND_DATAA data;
hFind = FindFirstFileA(DATA_DIR.c_str(), &data);
Since you're using LPCWSTR, you should be using std::wstring, not std::string in your program.
Also, there is no conversion magic when you cast to an LPCWSTR. It is just a dumb 'C' cast that basically does nothing except shut the compiler up.
I have CStrings in my program that contain BYTE information like the following:
L"0x45"
I want to turn this into a BYTE type with value 0x45. How do I do this? All examples I can find are trying to get the literal byte value of the string itself, but I want to take the value contained within the CString and convert THAT to a BYTE. How do I achieve this?
You can use the wcstoul() conversion function, specifying base 16.
e.g.:
#define UNICODE
#define _UNICODE
#include <stdlib.h> // for wcstoul()
#include <iostream> // for console output
#include <atlstr.h> // for CString
int main()
{
CString str = L"0x45";
static const int kBase = 16; // Convert using base 16 (hex)
unsigned long ul = wcstoul(str, nullptr, kBase);
BYTE b = static_cast<BYTE>(ul);
std::cout << static_cast<unsigned long>(b) << std::endl;
}
C:\Temp>cl /EHsc /W4 /nologo test.cpp
Output:
69
As an alternative, you can also consider using new C++11's std::stoi():
#define UNICODE
#define _UNICODE
#include <iostream> // for console output
#include <string> // for std::stoi()
#include <atlstr.h> // for CString
int main()
{
CString str = L"0x45";
static const int kBase = 16; // Convert using base 16 (hex)
int n = std::stoi(str.GetString(), nullptr, kBase);
BYTE b = static_cast<BYTE>(n);
std::cout << static_cast<unsigned long>(b) << std::endl;
}
NOTE
In this case, since std::stoi() expects a const std::wstring& argument, you must explicitly get the const wchar_t* pointer for the CString instance, either using CString::GetString() as I did (and I prefer), or using static_cast<const wchar_t*>(str).
Then, a temporary std::wstring will be built to be passed to std::stoi() for the conversion.
When I compile this code in Visual C++, I got the below error. Can help me solve this issue..
DWORD nBufferLength = MAX_PATH;
char szCurrentDirectory[MAX_PATH + 1];
GetCurrentDirectory(nBufferLength, szCurrentDirectory);
szCurrentDirectory[MAX_PATH +1 ] = '\0';
Error message:
Error 5 error C2664: 'GetCurrentDirectoryW' : cannot convert parameter 2 from 'char [261]' to 'LPWSTR' c:\car.cpp
Your program is configured to be compiled as unicode. Thats why GetCurrentDirectory is GetCurrentDirectoryW, which expects a LPWSTR (wchar_t*).
GetCurrentDirectoryW expects a wchar_t instead of char array. You can do this using TCHAR, which - like GetCurrentDirectory - depends on the unicode setting and always represents the appropriate character type.
Don't forget to prepend your '\0' with an L in order to make the char literal unicode, too!
It seems you have define UNICODE, _UNICODE compiler flags. In that case, you need to change the type of szCurrentDirectory from char to TCHAR.
Headers:
#include <iostream>
#include <fstream>
#include <direct.h>
#include <string.h>
#include <windows.h> //not sure
Function to get current directory:
std::string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
wchar_t currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
std::wstring ws(currentDir);
std::string current_dir(ws.begin(), ws.end());
return std::string(current_dir);
}
To call function:
std::string path = getCurrentDirectoryOnWindows(); //Output like: C:\Users\NameUser\Documents\Programming\MFC Program 5
To make dir (Folder) in current directory:
std::string FolderName = "NewFolder";
std::string Dir1 = getCurrentDirectoryOnWindows() + "\\" + FolderName;
_mkdir(Dir1.c_str());
This works for me in MFC C++.
I'm trying to convert UTF-16 encoded strings to UCS-4
If I understand correctly, C++11 provides this conversion through codecvt_utf16.
My code is something like:
#include <iostream>
#include <locale>
#include <memory>
#include <codecvt>
#include <string>
using namespace std;
int main()
{
u16string s;
s.push_back('h');
s.push_back('e');
s.push_back('l');
s.push_back('l');
s.push_back('o');
wstring_convert<codecvt_utf16<wchar_t>, wchar_t> conv;
wstring ws = conv.from_bytes(reinterpret_cast<const char*> (s.c_str()));
wcout << ws << endl;
return 0;
}
Note: the explicit push_backs to get around the fact that my version of clang (Xcode 4.2) doesn't have unicode string literals.
When the code is run, I get terminate exception. Am I doing something illegal here? I was thinking it should work because the const char* that I passed to wstring_convert is UTF-16 encoded, right? I have also considered endianness being the issue, but I have checked that it's not the case.
Two errors:
1) from_bytes() overload that takes the single const char* expects a null-terminated byte string, but your very second byte is '\0'.
2) your system is likely little-endian, so you need to convert from UTF-16LE to UCS-4:
#include <iostream>
#include <locale>
#include <memory>
#include <codecvt>
#include <string>
using namespace std;
int main()
{
u16string s;
s.push_back('h');
s.push_back('e');
s.push_back('l');
s.push_back('l');
s.push_back('o');
wstring_convert<codecvt_utf16<wchar_t, 0x10ffff, little_endian>,
wchar_t> conv;
wstring ws = conv.from_bytes(
reinterpret_cast<const char*> (&s[0]),
reinterpret_cast<const char*> (&s[0] + s.size()));
wcout << ws << endl;
return 0;
}
Tested with Visual Studio 2010 SP1 on Windows and CLang++/libc++-svn on Linux.