LPCTSTR to LPCSTR conversion - c++

I am trying to get information of existing file using GetFileInformationByHandle(). My function that performs the required task receives LPCTSTR Filename as argument. Here is the code:
getfileinfo(LPCTSTR Filename)
{
OFSTRUCT oo;
BY_HANDLE_FILE_INFORMATION lpFileInformation;
HFILE hfile=OpenFile((LPCSTR)Filename,&oo,OF_READ);
int err=GetLastError();
GetFileInfomationByHandle((HANDLE)hfile,&lpFileInformation);
}
Above code works fine if I declare Filename as LPCSTR but as per requirement of my function I receive the filename in LPCTSTR so if I use typecasting then openfile() cannot find the specified file and returns -1.
Can anyone tell me how to get file information if filename is LPCTSTR? Or how to convert LPCTSTR to LPCSTR.
Why is this typecasting not working? I believe this should work.

Just casting the pointer doesn't change the actual data (ie filename) that is being pointed to into eight-bit characters.
Reading the docs at MSDN suggests using CreateFile instead, which handles LPCTSTR filenames.

The solution to your immediate problem is to replace OpenFile() with CreateFile(), just like the OpenFile() documentation says to do:
Note This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
For example:
getfileinfo(LPCTSTR Filename)
{
HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
BOOL ok = GetFileInformationByHandle(hFile, &FileInfo);
int err = GetLastError();
CloseHandle(hFile);
if (!ok)
{
// handle error as needed ...
}
else
{
// use FileInfo as needed...
}
}
}
That being said, a better solution is to not open the file at all. Most of the information that GetFileInformationByHandle() returns can be obtained using FindFirstFile() instead:
getfileinfo(LPCTSTR Filename)
{
WIN32_FIND_DATA FileData = {0};
HANDLE hFile = FindFirstFile(Filename, &FileData);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
FindClose(hFile);
// use FileData as needed ...
}
}

Have a look at Project Properties/Configuration Properties/General/Character Set. This is normally set to UNICODE. It can be changed to MBCS.
If it is set to MBCS, then the code does not need to be modified.
If it is set to Unicode, which I suspect it is otherwise you won't be asking this question, use widechartomultibyte to convert it from LPCTSTR (const wchar_t*) to LPSTR (const char*).

Related

stricmp doesn't work in my code

I'm cycling through a process snapshot of TlHelp32 and then comparing the names with stricmp to get the process handle. The problem is even though both values seem to be the same, they apparently are not since it doesn't return 0 . I don't know why though, I have tried writing the process name into the function as well.
HANDLE GetProcessValues(std::string ProcName)
{
const char* ProcNameChar = ProcName.c_str();
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
if (Process32First(snapshot, &process))
{
do
{
if (_stricmp((char*)process.szExeFile,ProcNameChar)==0)
{
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
return hProc;
}
}while (Process32Next(snapshot,&process));
}
return 0;
}
I debugged it to see if the values fit:
The problem is that you are using the TCHAR versions of Process32First()/Process32Next(), and your debugger screnshot clearly shows that you are compiling your project for Unicode, so TCHAR maps to WCHAR and thus process.szExeFile is a WCHAR[] array. You are incorrectly type-casting that array to a char* pointer. You cannot directly compare a Unicode string to an Ansi string. You need to convert one string to the encoding of the other string before then comparing them.
You are also leaking the HANDLE returned by CreateToolhelp32Snapshot().
Since you are passing an Ansi std::string as input to your GetProcessValues() function, the easiest solution would be to use the Ansi versions of Process32First()/Process32Next() instead, so process.szExeFile is now a CHAR[] array, and thus no conversion is needed:
HANDLE GetProcessValues(std::string ProcName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
return NULL;
PROCESSENTRY32A process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
const char* ProcNameChar = ProcName.c_str();
HANDLE hProc = NULL;
if (Process32FirstA(snapshot, &process))
{
do
{
if (_stricmp(process.szExeFile, ProcNameChar) == 0)
{
hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
break;
}
}
while (Process32NextA(snapshot, &process));
}
CloseHandle(snapshot);
return hProc;
}
However, you really should stay away from using Ansi APIs. Windows is a Unicode-based OS, and has been for a long time. Use Unicode APIs instead:
HANDLE GetProcessValues(std::wstring ProcName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
return NULL;
PROCESSENTRY32W process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
const wchar_t* ProcNameChar = ProcName.c_str();
HANDLE hProc = NULL;
if (Process32FirstW(snapshot, &process))
{
do
{
if (_wcsicmp(process.szExeFile, ProcNameChar) == 0)
{
hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
break;
}
}
while (Process32NextW(snapshot, &process));
}
CloseHandle(snapshot);
return hProc;
}
If your ProcName parameter absolutely must be a std::string, then you can either:
convert ProcName to Unicode using MultiByteToWideChar(), std::wstring_convert, etc, and then compare that result to the strings returned by the Unicode API.
convert strings from the Unicode API to Ansi using WideCharToMultiByte(), std::wstring_convert, etc, and then compare those results to ProcName.
when dealing with wchar* data type, use _wcsicmp for comparison, and - if necessary - convert any involved char* data type into a wchar*-equivalent, e.g. using CStringW class. Confer microsoft _wcsicmp, and be also aware of using a correct locale. A similar problem, yet with wchar* constants, has been described at stack overflow

SHGetKnownFolderPath fails with E_ACCESSDENIED

I have a program that calls SHGetKnownFolderPath with FOLDERID_RoamingAppData.
If I start the program by double clicking it, it works ok.
If the program is started by a windows service (in the current user context), the function fails with error E_ACCESSDENIED (-2147024891).
This is what my code looks like:
Tstring EasyGetFolderPath(REFKNOWNFOLDERID folderid)
{
Tstring sPath = _T("");
PWSTR pszPath = NULL;
HRESULT hr = SHGetKnownFolderPath(folderid, 0, NULL, &pszPath);
if (hr == S_OK && pszPath)
{
sPath = WStringToTCHAR(pszPath);
CoTaskMemFree(pszPath);
return sPath;
}
else
{
throw HResultException(hr, _T("SHGetKnownFolderPath failed"));
}
}
Tstring EasyGetUsrAppDataPath()
{
return EasyGetFolderPath(FOLDERID_RoamingAppData);
}
static TCHAR* WStringToTCHAR(const std::wstring &s)
{
#ifdef UNICODE
TCHAR *sT = new TCHAR[s.length() + 1];
_tcscpy_s(sT, s.length() + 1, s.c_str());
return sT;
#else
std::string str = WStringToString(s);
TCHAR *sT = new TCHAR[str.length()+1];
_tcscpy_s(sT, str.length() + 1, str.c_str());
return sT;
#endif // UNICODE
}
static std::string WStringToString(const std::wstring& s, bool method = true)
{
std::string temp;
temp.assign(s.begin(), s.end());
return temp;
}
This is the code that starts the process in the current user context:
(I've removed the error handling in order to reduce verbosity)
void StartProcessInCurrentUserContext(const Tstring &sExeName, const Tstringarr &lstParams, const Tstring &sWorkingDir)
{
...
EnableDebugPrivilege();
errCode = GetProcessByName(_T("explorer.exe"), hProcess);
if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
{
...
}
if (hProcess)
CloseHandle(hProcess);
Tstring sCmdLine = ...;
...
// Create the child process.
bSuccess = CreateProcessAsUser(hToken, NULL,
(LPTSTR)sCmdLine.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
sWorkingDir.length() > 0 ? (LPCTSTR)sWorkingDir.c_str() : NULL,
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
CloseHandle(hToken);
...
}
Does anyone know what the problem might be?
The documentation for SHGetKnownFolderPath says in the discussion of the hToken parameter:
In addition to passing the user's hToken, the registry hive of that specific user must be mounted.
The documentation for CreateProcessAsUser says
CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key.
These two paragraphs together explain why your code is not working. Fortunately, the next sentence in the documentation for CreateProcessAsUser explains what you need to do:
Therefore, to access the information in the HKEY_CURRENT_USER registry key, you must load the user's profile information into HKEY_USERS with the LoadUserProfile function before calling CreateProcessAsUser. Be sure to call UnloadUserProfile after the new process exits.

Crash when calling ReadFile after LockFileEx

I have several processes that try to read and write the same file. I want each of them to lock the file so that only one of them accesses it at a time.
I tried this (edit: this is a complete test code this time):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
This works fine on my computer, which has Windows 8. But on my colleague's computer, which has Windows 7, it crashes. Specifically, the calls to ReadFile and WriteFile crash, always.
Note that it never enters the code paths with the error printfs. This code triggers no error except for a write at location 0x00000000 in ReadFile (when run on Windows 7).
We tried to also pass the overlapped struct to the ReadFile and WriteFile calls. It prevents the crash but the lock doesn't work anymore, the file is all scrambled (not with this test code, with the real code).
What am I doing wrong?
Looks like your problem is:
lpNumberOfBytesRead [out, optional] argument is null in your call.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Heres your problem :
You are missing a necessary struct-member and:
0 and ~0 and {0} are all bad code, constant expressions like these will always produce unepected results -- WINAPI doesnt work like libc, parameters are not always compared against constants, instead they are tested against/via macros and other preprocessor-definitions themselves so passing constant values or initializing WINAPI structs with constants will often lead to errors like these.
After years of experimenting i have found that there is only one surefire way of avoiding them, i will express it in corrected code :
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
please read this carefully : http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

c++ check if file is empty

I got a project in C++ which I need to edit. This is a declaration of variable:
// Attachment
OFSTRUCT ofstruct;
HFILE hFile = OpenFile( mmsHandle->hTemporalFileName , &ofstruct , OF_READ );
DWORD hFileSize = GetFileSize( (HANDLE) hFile , NULL );
LPSTR hFileBuffer = (LPSTR)GlobalAlloc(GPTR, sizeof(CHAR) * hFileSize );
DWORD hFileSizeReaded = 0;
ReadFile( (HANDLE) hFile , hFileBuffer, hFileSize, &hFileSizeReaded, NULL );
CloseHandle( (HANDLE) hFile );
I need to check if the file is attached (I suppose I need to check if hFile has any value), but don't know how. I tried with hFile == NULL but this doesn't do the job.
Thanks,
Ile
Compare hFile with HFILE_ERROR (not with NULL!). Also, you should change OpenFile to CreateFile and call it properly, OpenFile has long been deprecated. In fact MSDN clearly states:
OpenFile Function
Only use this function with 16-bit
versions of Windows. For newer
applications, use the CreateFile
function.
When you make this change, you will get a HANDLE back, which you should compare with INVALID_HANDLE_VALUE.
Update: Correct way to get a file's size:
LARGE_INTEGER fileSize={0};
// You may want to use a security descriptor, tweak file sharing, etc...
// But this is a boiler plate file open
HANDLE hFile=CreateFile(mmsHandle->hTemporalFileName,GENERIC_READ,0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile!=INVALID_HANDLE_VALUE && GetFileSizeEx(hFile,&fileSize) &&
fileSize.QuadPart!=0)
{
// The file has size
}
else
{
// The file is missing or size==0 (or an error occurred getting its size)
}
// Do whatever else and don't forget to close the file handle when done!
if (hFile!=INVALID_HANDLE_VALUE)
CloseHandle(hFile);
Before you open the file you can try this:
WIN32_FIND_DATA wfd;
HANDLE h = FindFirstFile(filename, &wfd);
if (h != INVALID_FILE_HANDLE)
{
// file exists
if (wfd.nFileSizeHigh != 0 || wfd.nFileSizeLow != 0)
{
// file is not empty
}
FindClose(h)
}