C++ GetModuleFileName Access Violation - c++

I am trying to get the current executable path into a string by using this code (I have tried several other versions of it too, but none of them really works, I always get a access violation at some point)
char *filename = new char[MAX_PATH + 1];
GetModuleFileName(NULL, filename, MAX_PATH);
string exe = filename;
This fails with an access violation at the first line for some reason. What am I missing?

This version does the error check, and also respects that GetModuleFileName works with TCHAR's (the second parameter is an LPTSTR, which is a pointer to a TCHAR).
#include <windows.h>
#include <string>
typedef std::basic_string<TCHAR> TCharString;
int main()
{
TCHAR filename[MAX_PATH + 1];
if ( GetModuleFileName(NULL, filename, MAX_PATH) != 0 )
{
TCharString strExe = filename;
}
}
Note that since GetModuleFileName works with TCHAR, it is not correct to blindly use std::string as the string type. Instead, create a string type based on TCHAR.
Second, the error check is done to ensure that we do not assign an invalid string to the string object.

try not using a char pointer . use a char array instead.

Related

C++ Combine 2 Tchar

I'm trying to combine 2 tchar.
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
But I get error error at appdatapath line. How can I combine 2 tchar? Thanks
Have a look at strcat and wcscat. You can't add char pointer with char array.
If you are on a windows machine, you can use _tcscat which will redirect to the right function to use depending on _UNICODE and _MBCS defines.
Might want to use the safe versions as well by appending _s to the function name.
As pointed in the comments, you can also use snprintf like so:
const size_t concatenated_size = 256;
char concatenated[concatenated_size];
snprintf(concatenated, concatenated_size, "C:\\Users\\%s\\AppData", username);
Since you have string literals before and after the runtime string, it is probably a better approach.
To answer the question in the title: you concatenate two TCHAR strings using the _tcscat function.
However, there are other issues in your code related to this: GetUserName expects a LPTSTR, i.e. a pointer to a buffer TCHAR characters. Furthermore, there's another TCHAR usage in
TCHAR* appdatapath ="C:\\Users\\"+username+"\\AppData";
The issue with this is that the type to which TCHAR expands changes depending on whether _UNICODE is defined. In particular, if you set it, TCHAR (eventually) expands to wchar and hence GetUserName expects a wchar_t* but you pass a char*. Another issue is that you cannot concatenate C arrays using the + operator.
I suggest to stop worrying about TCHAR in the first place and always just compile with _UNICODE defined - and use wchar throughout your code. Also, since you're using C++, just use std::wstring:
wchar username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserNameW(username, &username_len);
std::wstring appdatapath = L"C:\\Users\\";
appdatapath += username;
appdatapath += L"\\AppData";
Last but not least: your entire code can probably be replaced with a call to the SHGetSpecialFolderPath function - pass CSIDL_APPDATA to it to get the "AppData" path.
#include <tchar.h>
const size_t stringSize= 20;
TCHAR value[stringSize] = { 0 };
_tcscat_s(value, stringSize, TEXT("appendMe"));
MSDN: _tcscat_s

Concatenate two WCHAR_T arrays in C++

Dealing with these insane strings and arrays is giving me a headache...
Here's my code so far
wchar_t mypath[MAX_PATH];
wchar_t temppath[MAX_PATH];
GetModuleFileName(0, mypath, MAX_PATH);
GetTempPath(MAX_PATH, temppath);
CreateDirectory(???, NULL);
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference? After I get the path for the TEMP directory, I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable. Can someone give me some tips on how to use these arrays. This is what makes C++ a pain. Why couldn't everyone just settle on one data type for strings. How is wchar_t even useful? It's so hard to use and manipulate.
Thanks guys!
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference?
LPCWSTR is a const version of LPWSTR:
From LPCWSTR:
typedef const wchar_t* LPCWSTR;
From LPWSTR:
typedef wchar_t* LPWSTR, *PWSTR;
I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable.
Use a std::wostringstream:
std::wostringstream wos;
wos << temppath << L"\\test";
std::wstring fullpath(wos.str());
or just a std::wstring (as suggested by chris in the comments):
std::wstring fullpath(std::wstring(temppath) + L"\\test");
to produce a concatenated version. Then use c_str() as the argument to CreateDirectory():
if (CreateDirectory(fullpath.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// Directory created or already existed.
}
else
{
// Failed to create directory.
}
Use PathCombine(), eg:
wchar_t temppath[MAX_PATH+1] = {0};
GetTempPath(MAX_PATH, temppath);
wchar_t mypath[MAX_PATH+8] = {0};
PathCombineW(mypath, temppath, L"test");
CreateDirectoryW(mypath, NULL);

conversion of Cstring to BYTE

I am using Visual Studio c++ and want to convert the Cstring to Byte. I have written this code but it gave me error in the second line that "data" is undefined.
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
Further more I need to convert LPBYTE to const char for strcmp function. I have written the code but I can't find the issue with it.
const LPBYTE lpBuffer;
LPBYTE lpData = lpBuffer;
CString rcvValue(LPCSTR(lpBuffer));
const CHAR* cstr = (LPCSTR)rcvValue;
if (strcmp (cstr,("ABC")) == 0)
{
////
}
The CString type is a template specialization of CStringT, depending on the character set it uses (CStringA for ANSI, CStringW for Unicode). While you ensure to use a matching encoding when constructing from a string literal by using the _T macro, you fail to account for the different size requirements when copying the controlled sequence to the buffer.
The following code fixes the first part:
CString data = _T("OK");
size_t size_in_bytes = (data.GetLength() + 1) * sizeof(data::XCHAR);
std::vector<BYTE> buffer(size_in_bytes);
unsigned char const* first = static_cast<unsigned char*>(data.GetString());
unsigned char const* last = first + size_in_bytes;
std::copy(first, last, buffer.begin());
The second question is really asking to solve a solved problem. The CStringT type already provides a CStringT::Compare member, that can be used:
const LPBYTE lpBuffer;
CString rcvValue(static_cast<char const*>(lpBuffer));
if (rcvValue.Compare(_T("ABC")) == 0)
{
////
}
General advice: Always prefer using the concrete CStringT specialization matching your character encoding, i.e. CStringA or CStringW. The code will be much easier to read and reason about, and when you run into problems you need help with, you can post a question at Stack Overflow, without having to explain, what compiler settings you are using.
Make sure you include atlstr.h to provide the definition of CString, as below:
#include "stdafx.h"
#include <Windows.h>
#include <atlstr.h>
int _tmain(int argc, _TCHAR* argv[])
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
I'm fairly certain Jay is correct for your first question. You need to include the right header.
For your second question, why would you expect that code to work? Let's walk through what the code you've written actually does.
Create a char pointer (char *) without initializing it. This leaves lpData/lpBuffer pointing to a random location in memory.
Create a CString and initialize it with this random pointer.
Extract the buffer from the CString and compare it to a string literal.
Keeping in mind that the CString contains random garbage, what exactly do you expect this code to do? (Other than crash horribly? =) )
I also want to point out that you need to be more consistent in your approach to strings. Do you plan to support both char and wchar_t based strings as your use of TCHAR in the first sections suggests? Do you want to work with C-Style strings or do you want to use objects like CString? If you want to work with CString's, just use the Compare function that CString provides. Don't bother with strcmp.
Probably you didn't include the cruicial header
#include <afx.h>
int main()
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
This code works fine.
You should rather use
CString ss = "123ABC";
BYTE* bp = (BYTE*)ss.GetBuffer(ss.GetLength());
BYTE expected[16] ;
CopyMemory(expected,bp,sizeof(expected));
Just using '=' won't work.

C++ - Convert LPSTR to const char* in MinGW under Windows

I'm having trouble converting from LPSTR to const char* in MinGW under Windows.
#include <dirent.h>
#include <cstdio>
#include <fstream>
#include <windows.h>
int main() {
DIR *dir;
struct dirent *ent;
LPSTR buffer;
GetCurrentDirectory(100, buffer);
const char *str = *buffer;
dir = opendir(*str);
return 0;
}
What I'm trying to do is grab a list of all the current files in a directory and write it to a file; I can do the latter, but the former is giving me some trouble. I can figure out how to read the directory once I can convert the different variable types.
I know what LPSTR is, but I don't know how to apply it to this code.
Do not suggest using atlbase.h because MinGW does not support it, and I'm not willing to go back to Visual unless absolutely necessary.
You seem to be a bit confused about indirection. LPSTR is a char*. It is a pointer to a char (or, as is the case here, a pointer to the initial element of an array of char).
When you call GetCurrentDirectory, you need to pass it a pointer to the initial element of an array of char and the size of that array. So, what you need to do is declare an array and pass that into the function. For example,
char buffer[MAX_PATH];
GetCurrentDirectory(MAX_PATH, buffer);
With your current implementation, your program will assuredly crash because buffer is uninitialized, so GetCurrentDirectory will attempt to write to some random location in memory.
You should also check the return value of GetCurrentDirectory to ensure that it completed successfully and that the buffer contains the complete path. Its documentation explains the values that it may return.
Once you have the path, you can pass it directly to opendir: the array buffer is implicitly convertible to a pointer to its initial element--that is, the char[MAX_PATH] can be converted to a char*--and that char* can be implicitly converted to the char const* required by opendir:
DIR* dir = opendir(buffer);
Do note that the signature of GetCurrentDirectory depends on whether the UNICODE macro is defined or not: if you are compiling your program for Unicode, it actually takes a pointer to an array of wchar_t. If you build a Unicode program, you will need to account for this (you should use Unicode if you can).

AccessViolation error while using _tcstok in C++

I am trying to run the following code
TCHAR* str1 = TEXT("C:\\Program Files\\Internet Explorer;");
const TCHAR* del = TEXT(";");
TCHAR* token = _tcstok(str1, del);
When I run this in VS 2010 I get the following Exception :
Unhandled exception at 0x10275af4 (msvcr100d.dll) in String_Tchars.exe: 0xC0000005: Access violation writing location 0x0041839c.
My Objecttive to to be able to get the part before the semi-colon ";" and then do an append to that token to get the final string as c:\Program Files\Internet Explorer\iexplore.exe
Could someone shed some light what is causing this exception?
You can only use strtok() (and its Windows relatives) with modifiable strings. So make your strings local character arrays:
TCHAR str1[] = TEXT("C:\\Program Files\\Internet Explorer;");
TCHAR* token = _tcstok(str1, ";");
// etc.
The the tokenizer function actually modifies the string by replacing the delimiter by null bytes, so there's no way you can use this on a read-only string.
If your string comes to you through a pointer-to-const, copy it to a local array first (e.g. to a std::vector<TCHAR>):
void foo(const TCHAR * str)
{
std::vector<TCHAR> s(str, _tcslen(str) + 1); // local copy, includes null terminator
TCHAR * str1 = s.data(); // or &s[0]
TCHAR* token = _tcstok(str1, ";");
// ...
}
_tcstok tries to modify the constant string(string Literal) causing an Undefined Behavior, which presents itself in the form of an access violation.
The string Literal I refer to here is:
TCHAR* str1 = TEXT("C:\\Program Files\\Internet Explorer;");
^^^^
The program should not modify it, and _tcstok tries to do that hence the Undefined Behavior.
Instead use modifyable non const string array:
TCHAR str1[] = TEXT("C:\\Program Files\\Internet Explorer;");