cannot convert argument 1 from wchar to lpcstr - c++

Can't change the whole project to unicode.
void CreateDir(string dirname)
{
char my_dir[247];
WCHAR wcmy_dir[UNLEN+1];sprintf_s(my_dir, dirname.c_str());
MultiByteToWideChar(CP_ACP, 0, my_dir, (int)strlen(my_dir)+1, wcmy_dir,
sizeof(wcmy_dir)/sizeof(wcmy_dir[0]));
CreateDirectory(wcmy_dir, NULL);
}

Your project is not configured to use Unicode, so CreateDirectory() will map to CreateDirectoryA() instead of CreateDirectoryW() like your code is assuming. Passing a WCHAR string to CreateDirectoryA() is indeed an error.
Since you are not actually calling CreateDirectoryW(), you don't need to call MultiByteToWideChar() at all. Just call CreateDirectoryA() explicitly, passing it your input string as-is:
void CreateDir(string dirname)
{
CreateDirectoryA(dirname.c_str(), NULL);
}
Internally, it will convert the char data to WCHAR using CP_ACP and then call CreateDirectoryW() for you.
If you ever decide to update your project to use Unicode but do not change your function to use wstring, this same code will still work without change.
If you ever decide to change your function to use wstring instead, simply call CreateDirectoryW() explicitly to match:
void CreateDir(wstring dirname)
{
CreateDirectoryW(dirname.c_str(), NULL);
}

Related

Using std::filesystem output as LPCWSTR

I'm making a program which recursively lists all files in a certain directory and uploads each file separately to an FTP server using WinINet.
The problem I'm encountering is using filesystem::path::filename in the FtpPutFile() function because a LPCWSTR is needed.
Whats the best and easiest way to convert it (or somehow use it as is)?
std::string path = "C:\\Programs";
for (const auto & entry : std::experimental::filesystem::recursive_directory_iterator(path))
FtpPutFile(hIConnect, entry.path().filename(), entry.path().filename(), FTP_TRANSFER_TYPE_BINARY, 0);
The error I get is:
no suitable conversion function from "const std::experimental::filesystem::v1::path" to "LPCWSTR" exists
EDIT: Here is a solution that worked for me, by following Lightness solution:
std::string path = "C:\\Programs";
for (const auto & entry : std::experimental::filesystem::recursive_directory_iterator(path))
FtpPutFile(hIConnect, entry.path().wstring().c_str(), entry.path().filename().wstring().c_str(), FTP_TRANSFER_TYPE_BINARY, 0);
LPCWSTR is Microsoft's obfuscation of the const wchar_t* type, and filesystem paths conveniently have a wstring() member function. As you may recall, C++ strings give you access to their character buffer, too, via c_str().
So, entry.path().filename().wstring().c_str() is a LPCWSTR you can use (ugh!). Be careful to use that immediately, or store the result of wstring() somewhere for as long as you need the LPCWSTR to survive, because wstring() returns by value and you don't want a dangling pointer.
// Untested, but a logical adaptation of your code
const std::string path = "C:\\Programs";
std::experimental::filesystem::recursive_directory_iterator it(path);
for (const auto& entry : it)
{
const std::wstring filename = entry.path().filename().wstring();
FtpPutFile(
hIConnect,
filename.c_str(),
filename.c_str(),
FTP_TRANSFER_TYPE_BINARY,
0
);
}

Problems transforming QString to _bstr_t

I am trying to transform a QString to _bstr_t type as follows:
QString mFilename="C:/agatebo/amahoro.doc";
QByteArray srcBa1 = mFilename.toLocal8Bit();
const char *srcString1 = srcBa1.data();
CString myStringSrc(srcString1,srcBa1.size());
BSTR bstrUser = myStringSrc.AllocSysString();
_bstr_t user(bstrUser,TRUE);
but when I pass the _bstr_t I get to this function:
pdfObject->cPrintFile(user);
PDFCreator ,a program whose COM interface I am using just crashes .I suspect this has something to do with unicode but can’t figure out what yet.I should mention that when I directly pass a path to the file like this:
pdfObject->cPrintFile(L"c:\\agatebo\\amahoro.doc");
all is ok ,I simply want to be able to use QStrings that come from other modules of my Qt application.I am compiling with Qt 4.8 msvc2010 if this matters. I would appreciate any
You should be able to use QString.utf16()
void ProcedureThatTakesWChar(const wchar_t* s) {
std::wcout<<s<<L'\n';
}
void ProcedureThatTakesBstr(const BSTR& s) {
std::wcout<<s<<L'\n';
}
int main(int argc, char *argv[]) {
QString qs("this is a qstring");
//pass directly
ProcedureThatTakesWChar(qs.utf16());
//if you really want to use a _b_str initialise it with .utf16()
//_b_str will handle SysAllocString and SysFreeString. QString
//does not have to stay in scope.
{
_bstr_t bs(qs.utf16());
ProcedureThatTakesBstr(bs);
}
return 0;
}
Since you're on Windows and the method call works when you pass in a wide string, that means you're compiling in Unicode mode. This means that TCHAR,_bstr_t etc. are typedefed to wchar_t. You can learn more about Unicode support in Windows here.
The good news is that QString and Microsoft's Unicode implementation both use the same character encoding, UTF-16.
To get the raw QString data you simply call QString's utf16() method. This returns a pointer to an array of null-terminated unsigned shorts -- the same type as wchar_t on Windows!
So in all you should have to do here is this:
pdfObject->cPrintFile(mFilename.utf16());

Passing native string type from CLI to native and back again

I am trying to write a CLI wrapper around some low-level COM-related calls. One of the operations that I need to do specifically is to get a specific value from a PROPVARIANT, i.e.:
pwszPropName = varPropNames.calpwstr.pElems[dwPropIndex];
where pwszPropName is documented to be an LPWSTR type and dwPropIndex is a DWORD value passed into the function by the user.
I have a native function defined as follows:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, wchar_t *PropertyName)
I would like to return the value of pwszPropName via *PropertyName.
Is the wchar_t* type the best way to do this, and would I need to pin *PropertyName in my CLI to ensure it does not move in memory? Do I need to define the length of *PropertyName before passing it to native code (buffer)?
If wchar_t* is the right variable type to pass into the native function, what is the proper conversion of LPWSTR to whar_t*, and how then would you convert that value to System::String?
I have tried a number of different techniques over the past few days and can't seem to get anything right.
------------UPDATE------------
Here is my full code. First, the CLI:
String^ MetadataEditor::GetPropertyNameByID(unsigned int ID)
{
LPWSTR mPropertyName = L"String from CLI";
m_pCEditor->GetPropertyNameByID(ID, mPropertyName);
//Convert return back to System::String
String^ CLIString = gcnew String(mPropertyName);
return CLIString;
}
And the native code:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName)
{
HRESULT hr = S_OK;
LPWSTR myPropName;
PROPVARIANT varNames;
PropVariantInit(&varNames);
hr = m_pMetadata->GetAllPropertyNames(&varNames);
if(hr != S_OK)
{
PropVariantClear(&varNames);
return hr;
}
myPropName = varNames.calpwstr.pElems[ID];
PropertyName = myPropName;
PropVariantClear(&varNames);
return hr;
}
It doesn't seem like the value (myPropName) is set properly and/or sustained back into the CLI function because the CLI returns the value I set on mPropertyName before calling the native function.. I'm not sure why or how to fix this.
UPDATE!!!!
I suspected my problem had something to do with variables going out of scope. So I changed the C++ function definition as follows:
LPWSTR GetPropertyNameByID(DWORD ID, HRESULT ErrorCode);
After adjusting the CLI as well, I now get a value returned, but the first character is incorrect, and in fact can be different with every call. I tried using ZeroMemory() in the native class before assigning the output of the PROPVARIANT to the variable (ZeroMemory(&myPropName, sizeof(myPropName +1)); but still no luck.
You can design unmanaged function by the following way:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName, size_t size)
{
....
wcscpy(PropertyName, varNames.calpwstr.pElems[ID]); // or wcsncpy
...
}
PropertyName is the buffer allocated by caller, size is its size. Inside the function wcscpy or wcsncpy the string varNames.calpwstr.pElems[ID] to PropertyName. Client code:
WCHAR mPropertyName[100];
m_pCEditor->GetPropertyNameByID(ID, mPropertyName, sizeof(mPropertyName)/sizeof(mPropertyName[0]));
Think, for example, how GetComputerName API is implemented, and do the same

How can I pass the contents of a tstringstream to a method that takes in an LPTSTR?

I have tried the following:
tstringstream s;
s << _T("test") << std::endl;
LPTSTR message = s.str().c_str();
Log(5, _T("Example", message);
Where Log is defined as such:
void Log(DWORD dwSeverity, LPTSTR szAppID, LPTSTR szMsgString, ...)
{
}
But I get the following error:
Error: A value of type "const char *" cannot be used to initialize an entity of type "LPTSTR"
But I'm not sure exactly how to handle this conversion. In my case, I am compiling a multi-byte character-set application using the MSVC++ compiler. Under these conditions, LPTSTR is defined as an LPSTR, which is defined as a CHAR *.
You're hitting const-incompatibility. For some reason, the function Log takes a pointer to mutable data, which is incompatible with the pointer to const data returned by c_str().
If you have the option, change Log to take its parameter as const (I assume it does not actually modify the string passed in):
void Log(DWORD dwSeverity, LPCTSTR szAppID, LPCTSTR szMsgString, ...)
The same way, declare message as LPCTSTR.
Also note that you cannot actually initialise message the way you're doing it now: the string returned by str() is temporary, so you have to store it:
tstring message = s.str();
Log(5, _T("Example", message.c_str());
If Log is outside your control, but you know that it does not modify its arguments, you can use a const_cast:
LPTSTR message = const_cast<LPTSTR>(message.c_str()); // `message` changed as above
If you cannot vouch for what Log does internally, you'll have to create a mutable buffer:
std::vector<TCHAR> buffer(message.begin(), message.end());
buffer.push_back(0);
Log(5, _T("Example", &buffer[0]);
I can see a couple of problems.
First of all here:
LPTSTR message = s.str().c_str();
The call to s.str() returns a temporary which will be destroyed unless you keep it alive. Therefore the address returned by calling c_str() becomes invalid. You need a temporary local:
string str = s.str();
LPCTSTR message = str.c_str();
And since c_str() returns a const C string, you need to declare message to be a const C string too.
The other problem is that your Log function receives a non-const C string, but c_str() returns a const C string. Presumably the Log function does not need to modify the message, so why are you asking for a modifiable buffer. Change Log to receive a const C string:
void Log(..., LPCTSTR szMsgString, ...)
Finally, since this is C++, why are you using C strings at all? It is better to use C++ strings.

VBA call same C++ dll return different results

I have a test dll function that reads a string and display it:
int _stdcall test(LPSTR myString) {
MessageBoxA(NULL, (LPCSTR)myString, "test", MB_OK);
return 0;}
The excel VBA declaration is
Declare Function test Lib "test.dll" (ByVal text As String) As Long
There is a sub that calls the function. It reads an excel cell with value as "abcde" and is able to display a correct result. The sub code is:
sub testCode()
test (cells(1,1).value)
end sub
However when call the dll function using excel formula =test(A1), the message box only display the first char "a" of the string.
I had spent entire weekend reading BSTR, etc, still not be able to solve this. What is going on here?
Declare your imported function as private:
Private Declare Function test_internal Lib "test.dll" Alias "test" (ByVal text As String) As Long
and create a wrapper function for Excel to use:
Public Function Test (ByVal text As String) As Long
Test = test_internal(text)
End Functin
Because apparently, while VB(A) converts string arguments to ASCII using the current system codepage when calling to Declared APIs, the Excel engine does not.
On a side note, you also might want to remove parentheses.
Excel pass a BSTR to your C++ code. Each character is coded with 2 bytes, the second one being 0 for common characters. That explains why you see only the first one, as MessageBoxA expects char* null terminated strings. Use
MessageBoxW
Try with that code
int _stdcall test( const wchar_t * pString ) {
MessageBoxW( NULL, pString, L"test", MB_OK ); // note the L prefix for literral
return 0;
}
Alternatively, you could translate the BSTR pointer to a char* one, using some ATL macros, or raw Win32 APIs as WideCharToMultiByte (more tricky, mush simpler to use ATL)