Problems formatting arrays and strings in C++ - c++

I'm having a simple problem that's been driving me nuts all day. I am trying to open a file on the current user's Desktop without knowing the current user's name.
The idea is that I would use the GetCurrentUser call to the API to get the user name. Then format a string to give the full path directory, and pass that variable into fopen to open the file. Here is the code I'm working on, I get no compiler errors and it compiles fine but nothing writes to the file.
int main() {
char pathName[200]; // declaring arrays
char userName[100];
DWORD userNameSize = sizeof(userName); // storage for user name
if (!GetUserName(userName, &userNameSize)) { cout << "user not found"; }
else { cout "hello" << userName;} // error checking
// format for Windows 7 desktop
sprintf(pathName, "\"C:\\Users\\%s\\Desktop\\text.txt\"", userName);
cout << pathName << "\n"; // confirms correct location
const char* fileLocation = pathName; // pointer to full path to pass into fputs
const char* test = "test"; // test information to write to file to confirm
FILE *f = fopen(fileLocation,"a+"); // open file in append mode
fputs(test, f); // write to file
fclose(f); // flush and exit
return 0;
}
Maybe I need to use a different call to format the string? Or declare fileLocation as a different variable type?
I'm fairly new to C++ and would appreciate any tips that would help me to be able to open a file on the current user's Desktop. Thanks.
EDIT IN RESPONSE TO JERRY'S ADVICE:
This is what my latest comment was referring to:
#include <iostream>
#include <cstring>
#include <string>
#include <conio.h>
using namespace std;
string location ("C:\\Users\\testuser\\Desktop\\log.dat");
char cstr = char* [location.size()]; //This is a problematic line
strcpy (cstr, location.c_str());
void write(const char* c)
{
const char* fileLocation = cstr;
//const char* fileLocation = g_pathName;
FILE *f = fopen(fileLocation,"a+"); // This is the problematic line right here.
if(f!=NULL)
{
fputs(c,f); // append to end of file
fclose(f); // save so no entries are lost without being flushed
}
}
int main ()
{
write("test");
cout << "done";
_getch();
return 0;
}

You have a missing semicolon at line 9 where it says:
...{ cout << "user not found" }...
Semicolons are not optional in C++, you need them for a working program. Also, as stated in the comments, you do not need quotes around the name of the file.

I'd use SHGetSpecialFolderPath from shlobj.h:
const char *szFileName = "text.txt";
const char *szContent = "test string";
char szPath[_MAX_PATH];
SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
strcat(szPath, "\\");
strcat(szPath, szFileName);
FILE *pFile = fopen(szPath, "a+");
if(pFile != NULL)
{
fputs(szContent, pFile);
fclose(pFile);
}

I would use SHGetKnownFolderPath with FOLDERID_Desktop to get the path to the desktop, then add a file name to the end. You also almost certainly want to do the manipulation on std::strings, then when you've created the full name, use the .c_str member function to retrieve the name as a C-style string. Unless you have a really specific reason to do otherwise, you're probably better off using a std::ofstream instead of a C-style FILE * as well (and in that case if your compiler is current, you can probably pass the std::string object directly as the name).
Edit: some quick demo code creating and writing to a file on the user's desktop:
#include <windows.h>
#include <Shlobj.h>
#include <objbase.h>
#include <string>
#include <fstream>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
std::string GetKnownFolderPath(REFKNOWNFOLDERID f) {
PWSTR sys_path;
SHGetKnownFolderPath(f, 0, NULL, &sys_path);
DWORD size = WideCharToMultiByte(CP_ACP, 0, sys_path, -1, 0, 0, NULL, NULL);
std::string path(size, ' ');
WideCharToMultiByte(CP_ACP, 0, sys_path, -1, &path[0], size, NULL, NULL);
// We're finished with the string the system allocated:
CoTaskMemFree(sys_path);
// WideCharToMultiByte leaves space for a NUL terminator we don't need
path.resize(path.size()-1);
return path;
}
int main() {
std::string path(GetKnownFolderPath(FOLDERID_Desktop));
path += "\\test.txt";
std::ofstream test(path.c_str());
test << "This is a test";
return 0;
}

Related

Issue reading file with ifstream using absolute path

Hello stack overflow community. I came here as a last resort because i probably made a stupid mistake i cannot see myself.
The question im asking is for some reason when i try to read a file with an absolute path(or relative, you can see i tried that in my code) it cannot read the file for some unknown reason(atleast to me). This is a small thing for a big project im working on. Thank you guys!
main.cpp
#include <iostream>
#include <fstream>
#include <filesystem>
#include <unistd.h>
#include <string>
std::string openf() {
FILE* pipe = popen("zenity --file-selection", "r"); // open a pipe with zenity
if (!pipe) return "ERROR"; // if failed then return "ERROR"
char buffer[912]; // buffer to hold data
std::string result = ""; // result that you add too
while(!feof(pipe)) { // while not EOF read
if(fgets(buffer, 912, pipe) != NULL) // get path and store it into buffer
result += buffer; // add buffer to result
}
//I thought i needed to convert the absolute path to relative but i did not after all
// char cwd[10000];
// getcwd(cwd, 10000); // get cwd(current working directory)
// result = std::filesystem::relative(result, cwd); // convert the absolute path to relative with cwd
pclose(pipe); // cleanup
return result;
}
std::string readf(std::string filename){
std::string res;
std::ifstream file;
file.open(filename.c_str());
if(file.is_open()) {
while(file){
res += file.get();
}
}else {
std::cout << "failed to open file " + filename;
}
return res;
}
int main( void ){
std::string file = openf();
std::cout << file << std::endl;
std::string str = readf(file);
std::cout << str << std::endl;
return 0;
}
output
/home/meepmorp/Code/Odin/test/test.odin
failed to open file /home/meepmorp/Code/Odin/test/test.odin
It seems zenity, which you use as file chooser, outputs an extra newline after the file name, which you include in the name. In Linux, files can actually contain embedded newline characters in their name, and you actually try to open "test.odin\n" instead of "test.odin".

How to create files corresponding to program location?

Is there a way to create files on a computer using C++ and the location of the C++ program? I want to be able to use this program on multiple computers yet each computer has its own different directory. For example if I want to create test.txt file located on the user directory is there a way to put the path of the file corresponding to the program file's location because "user" differs on the name of the user.
as long as you are on windows you can use the API GetUserName then use SetCurrentDirectory API to change working directory then create your file there using CreateFile or fstream:
#include <iostream>
#include <windows.h>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ULONG len = 50;
LPSTR lpBuffer = (LPSTR)GlobalAlloc(GPTR, len);
GetUserName(lpBuffer, &len);
cout << lpBuffer << endl;
// don't forget to clean when you're done:
string str = "C:\\Users\\";
str += lpBuffer;
str += "\\test.txt";
cout << str << endl;
ofstream out(str.c_str());
if(out.fail())
perror("Opening failed");
out << "Hello " << lpBuffer;
out.close();
GlobalFree(lpBuffer);
GlobalFree(lpBuffer);
return 0;
}
this program gets the current username and creates file inside its folder and writes in it "Hello" 'yourusername'

How to get the absolute path of the desktop for the calling user on Windows

How can I get the absolute path to the desktop for the user that is starting my program?
int main () {
ofstream myfile;
myfile.open ("C:\\Users\\username\\Desktop\\example.txt");
myfile << "Writing this to a file" << endl;
myfile.close();
}
Edited : as Remy Lebeau suggested
I want to get absolute path to desktop for every computer starting program?
If you are in windows you need to use the API SHGetFolderPath function, click here for more informations.
When you get the path of the desktop you will need to combine (append) it with your file name, the generated path will represents the full path of the file wich is situated in the desktop, there is the full code:
#include <iostream>
#include <Windows.h>
#include <fstream>
#include <shlobj.h> // Needed to use the SHGetFolderPath function.
using namespace std;
bool GetDesktopfilePath(PTCHAR filePath, PTCHAR fileName)
{
// Get the full path of the desktop :
if (FAILED(SHGetFolderPath(NULL,
CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE,
NULL,
SHGFP_TYPE_CURRENT,
filePath))) // Store the path of the desktop in filePath.
return false;
SIZE_T dsktPathSize = lstrlen(filePath); // Get the size of the desktope path.
SIZE_T fileNameSize = lstrlen(fileName); // Get the size of the file name.
// Appending the fileName to the filePath :
memcpy((filePath + dsktPathSize), fileName, (++fileNameSize * sizeof(WCHAR)));
return true;
}
int main()
{
ofstream myFile;
TCHAR filePath[MAX_PATH]; // To store the path of the file.
TCHAR fileName[] = L"\\Textfile.txt"; // The file name must begin with "\\".
GetDesktopfilePath(filePath, fileName); // Get the full path of the file situated in the desktop.
myFile.open(filePath); // Opening the file from the generated path.
myFile << "Writing this to a file" << endl;
myFile.close();
return 0;
}

How to pass variable to windows.h function text()?

First off, I googled the hell out of this then searched the forums. In my ignorance of how the TEXT() function operates I cannot find an efficient way to search for an answer.
I writing a piece of code to search for a file that relies on inputting the directory you want to search. However, when I pass anything but a literal value to the function, like displayContent(_TEXT("c:\")), the software does not execute properly. It does not search for anything. Inserting breakpoints doesn't tell much, as the software closes anyways.
I would like to pass a variable to the the displayContent function by placing TEXT(variable) inside its argument like displayContent(_TEXT(*ptrDir)) but that is not compiling. Furthermore, when I simply place ptrDir inside of the argument of displayContent the software compiles but does not execute properly, as it asks for the directory to search but does not actually search it.
What's happening here? There has to be a way to pass a variable to displayContent that includes a string that's recieved from the user.
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "Strsafe.h"
#include <string>
using namespace std;
typedef wchar_t WCHAR;
#define CONST const
typedef CONST WCHAR* LPCWSTR;
int displayContent(LPCWSTR lpszPath, int level = 0) {
wcout << lpszPath << endl;
getchar();
getchar();
WIN32_FIND_DATA ptrFileData;
HANDLE hFile = NULL;
BOOL bGetNext = TRUE;
wchar_t lpszNewPath[MAX_PATH];
if (lstrlen(lpszPath) > MAX_PATH)
return -1;
StringCchCopy(lpszNewPath, MAX_PATH, lpszPath);
StringCchCat(lpszNewPath, MAX_PATH, _TEXT("*.*"));
hFile = FindFirstFile(lpszNewPath, &ptrFileData);
while (bGetNext)
{
for (int i = 0; i < level; i++)
wcout << "-";
if (ptrFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY
&& lstrlen(ptrFileData.cFileName) > 2)
{
wchar_t lpszFirstTimePath[MAX_PATH];
StringCchCopy(lpszFirstTimePath, MAX_PATH, lpszPath);
StringCchCat(lpszFirstTimePath, MAX_PATH, ptrFileData.cFileName);
StringCchCat(lpszFirstTimePath, MAX_PATH, _TEXT("\\"));
wcout << ">" << ptrFileData.cFileName << endl;
displayContent(lpszFirstTimePath, level + 2);
}
else
{
wcout << ">" << ptrFileData.cFileName << endl;
}
bGetNext = FindNextFile(hFile, &ptrFileData);
}
FindClose(hFile);
return 0;
}
int main(int argc, char* argv[])
{
WCHAR directory;
LPCWSTR ptrDir;
ptrDir = &directory;
cout << "Enter directory you wish to search: " << endl;
//cin >> directory;
directory = 'c:\\' ;
ptrDir = &directory;
displayContent(_TEXT(*ptrDir));
getchar();
getchar();
return 0;
}
The _TEXT (and equivalently, _T) macro is strictly for literals (string literals or character literals). It expands to L for a Unicode build, and to nothing for a narrow-character build. So, for a string like (say) "hello", you'll get L"hello" for a Unicode build and "hello" for a narrow-character build. This gives you a wide literal in a Unicode build and a narrow literal otherwise.
If you have a string in a variable, you can convert between wide and narrow characters with the MultiByteToWideChar and WideCharToMultibyte functions.
In this case, doing a conversion on the contents of a variable isn't really needed though. After eliminating some unnecessary complexity, and using a few standard library types where they make sense, I end up with code something like this:
#include <iostream>
#include <tchar.h>
#include <string>
#define UNICODE
#include <windows.h>
int displayContent(std::wstring const &path, int level = 0) {
WIN32_FIND_DATA FileData;
if (path.length() > MAX_PATH)
return -1;
std::wstring new_path = path + L"\\*.*";
HANDLE hFile = FindFirstFile(new_path.c_str(), &FileData);
do {
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (FileData.cFileName[0] == L'.'))
continue;
std::wcout << std::wstring(level, L'-') << L">" << FileData.cFileName << L"\n";
if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
displayContent(path + L"\\" + FileData.cFileName, level + 2);
} while (FindNextFile(hFile, &FileData));
FindClose(hFile);
return 0;
}
int main(int argc, char* argv[]) {
wchar_t current_dir[MAX_PATH];
GetCurrentDirectory(sizeof(current_dir), current_dir);
displayContent(current_dir);
return 0;
}
[Note: I've also changed it to start from the current directory instead of always starting at the root of the C drive, but if you want to change it back, that's pretty trivial--in fact, it simplifies the code a bit more).

Full path of executable file in Windows, c++ [duplicate]

This question already has answers here:
Wide character output result [closed]
(2 answers)
Closed 8 years ago.
I just want to get full path of my executable file written on console, but the variable path just stores numbers how can i convert it to string (I know this code only outputs memory location of path)?
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
int main() {
WCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, 500);
cout << "File path is: " << path << endl;
}
There are a couple of problems with your code:
You're passing the wrong size parameter to GetModuleFilename - the buffer size is supposed to be the size in TCHARs, which would be MAX_PATH in your case, not 500. That's a buffer overflow waiting to happen as 500 > MAX_PATH
You're using the narrow stream for your output, that can't print a wide string so you're seeing the address instead. To print wide characters, you need to use std::wcout instead.
As already noted in the comments, you may want to use wcout to print a WCHAR string.
You may want to consider a function like this to wrap the GetModuleFileName() call in a convenient C++ way:
#include <stdexcept> // For std::runtime_error
#include <string> // For std::wstring
#include <Windows.h> // For Win32 API
// Represents an error in a call to a Win32 API.
class win32_error : public std::runtime_error
{
public:
win32_error(const char * msg, DWORD error)
: std::runtime_error(msg)
, _error(error)
{ }
DWORD error() const
{
return _error;
}
private:
DWORD _error;
};
// Returns the full path of current EXE
std::wstring GetPathOfExe()
{
// Get filename with full path for current process EXE
wchar_t filename[MAX_PATH];
DWORD result = ::GetModuleFileName(
nullptr, // retrieve path of current process .EXE
filename,
_countof(filename)
);
if (result == 0)
{
// Error
const DWORD error = ::GetLastError();
throw win32_error("Error in getting module filename.",
error);
}
return filename;
}
Note that if you want the size in WCHARs of a raw string buffer, you may want to use _countof().
wchar are 16bit and you are using cout and that output stream expect 8bit char that's why you get weird number on the output
when you have to use wchar use wcout and take care of the kind of string you use!
#include <iostream>
#include <string>
#include <windows.h>
std::wstring app_path() {
std::wstring path;
path.resize(MAX_PATH, 0);
auto path_size(GetModuleFileName(nullptr, &path.front(), MAX_PATH));
path.resize(path_size);
return path;
}
int main() {
auto path(app_path());
std::wcout << L"File path is: " << path << std::endl;
}
Try this one!