Reputation: 1
I'm new to strings on C++, I'm since hours on this, I've been on lots of forums so I understand what kind of char* are LPSTR, LPCSTR or LPCSTR, but I can't find a way and understand how to build a string with them.
My intend is to use GetCurrentDirectoryA and CopyFileA to copy/paste a file in a new one.
Here is my code :
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
using namespace std;
#define DR drum-
#define NO normal-
#define SO soft-
//main
int main(){
LPCTSTR input;
LPCTSTR output;
LPSTR cd;
LPCSTR src = "source.wav";
if(GetCurrentDirectoryA(strlen(cd), cd)){
input = (LPCTSTR)cd + (LPCTSTR)src;
if(CopyFileA(input, cd + "DR" + "hitclap.wav"))
cout<<"done"<<endl;
else
cout<<"error"<<endl;
}
}
Upvotes: 0
Views: 2791
Reputation: 15144
You can use the following to use the <string>
STL library with the Windows W API:
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
using std::endl;
using std::cout;
using std::cerr;
using tstring = std::basic_string<TCHAR>;
const std::wstring dr = L"drum-";
// OR: const tstring dr = TEXT("drum-");
const std::wstring no = L"normal-";
const std::wstring so = L"soft-";
const std::wstring src = L"drum.wav";
const std::wstring dest = L"hitclap.wav";
int main()
{
const std::vector<wchar_t>::size_type cd_buf_len = GetCurrentDirectoryW( 0, NULL );
assert( cd_buf_len > 0 );
std::vector<wchar_t> cwd( cd_buf_len, 0 );
const DWORD cd_result = GetCurrentDirectoryW( cd_buf_len, cwd.data() );
assert(cd_result);
if (CopyFileW( (cwd.data() + src).c_str(), (cwd.data() + dr + dest).c_str(), FALSE )) {
cout << "Done." << endl;
} else {
cerr << "Error." << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This version is fixed to correct a bug in the initial post: modifying a .c_str()
causes undefined behavior. It’s conceptually simple and uses addition as requested, but is not as efficient as it would be to allocate buffers and copy the source strings to them, or to use +=
. You might therefore really want to write:
constexpr wchar_t src[] = L"drum.wav";
/* … */
std::wstring src_path = cwd.data();
src_path += src;
To use the TCHAR
versions, change wchar_t
to TCHAR
, change L"foo"
to TEXT("foo")
, change std::wstring
to tstring
, change LPWSTR
to LPTSTR
, change GetCurrentDirectoryW
to GetCurrentDirectory
, etc.
You do not, generally, want to mix 8-bit and wide strings in the same program unless you explicitly need to input in one encoding and output in the other. If so, you must explicitly convert, such as by setting the current code page to 65001 (UTF-8) and using std::wstring_convert
.
Upvotes: 0
Reputation: 5477
The API GetCurrentDirectory
doesn't return a new string to you. What it does is you pass it a memory location and it fills that memory location for you with the current directory string.
The problem is you haven't allocated memory, you pass it an uninitialised char*
(LPSTR
), cd
. You also use strlen
on this uninitialised character pointer. Typically, you use a character array with length MAX_PATH
for playing with filenames:
char cd[MAX_PATH];
GetCurrentDirectoryA(sizeof(cd), cd);
A second note is that you cannot use the +
operator to concatenate C strings. Either you go the C route and use strcat
[1] and friends, or you go the C++ route and replace all your char*
s with std::string
and work with that.
Choose one of the two roads and then go and read a tutorial on either char*
-strings in C or std::string
in C++.
To properly understand the LPTSTR
type and its relation to LPSTR
, please see this question & answer I created.
[1] How do I concatenate const/literal strings in C?
Upvotes: 2
Reputation: 393447
Using Boost Filesystem¹ you'd write:
#include <boost/filesystem.hpp>
#include <iostream>
#define dr "drum -"
#define no "normal -"
#define so "soft -"
int main() {
using boost::filesystem::path;
auto input = absolute(path("source.wav"));
auto output = absolute(path(dr "hitclap.wav"));
std::cout << input << " " << output << "\n";
}
Printing
"/tmp/1448053072-1243850518/source.wav" "/tmp/1448053072-1243850518/drum -hitclap.wav"
You can take it from there.
¹ Note: Microsoft Visual C++ ships a version of
<filesystem>
since... VS2010 even I think. So you might not need boost at all to enjoy the lush life :)
Upvotes: 1
Reputation: 525
Whenever I use something that takes or uses LPSTR/LPCTSTR, I tend to use an std::wstring instead:
std::wstring input = _T("");
input.append(_T("Sample Text"));
input.append(std::to_wstring(myint));
std::copy(mystring.begin(), mystring.end(), text.end());
This makes it possible to use a string in place of an LPCTSTR. I don't know if it will work in this case, but I think it will.
EDIT: As @MicroVirus said, you should really go all the way and use TCHAR for everything, that way your program is compatible with both ANSI and Unicode (your functions use ANSI, as denoted by the trailing 'A').
Upvotes: 0
Reputation: 69902
Welcome to the legacy of the 80286 memory model and the evolution from 8-bit characters to (sort of) unicode used by the Windows OS.
LPCSTR means: "long pointer to const string" and today is equivalent to const char*
. Not too many years ago it was equivalent to const char* far
- far being a Microsoft extension that told the compiler that the address could be in a different memory segment (if you really care, google is your friend "segmented memory model 80286")
LPCTSTR means: long pointer to const [either wide or 8-bit, depending on compiler flags] character. e.g. either:
const char*
or const wchar_t*
depending on the build mode.
similarly LPSTR is char *
today but once upon a time was char * far
.
So you can see that the Windows API is actually using raw pointers to c-style strings, which are either const or mutable, and either wide chars or 8-bit chars depending on context and build options.
Upvotes: 1
Reputation: 50016
Signature of GetCurrentDirectory is
DWORD WINAPI GetCurrentDirectory(
_In_ DWORD nBufferLength,
_Out_ LPTSTR lpBuffer
);
lpBuffer
is the pointer to memory buffer where contents should be placed, and nBufferLength is the size of this memory region in TCHARs.
so the correct code would be:
TCHAR szBuffer[MAX_PATH];
GetCurrentDirectory(MAX_PATH, szBuffer);
you must use TCHAR as for non unicode build it will resolve to char, and for unicode it will be wchar_t.
Upvotes: 1