WritePrivateProfileString works in main but not in function - c++

I am trying to use WritePrivateProfileString and GetPrivateProfileInt for a .ini parser.
When I put the code below into main(), or into a class constructor, it works for writing and reading.
But, when I make functions for writing and reading, and call the functions in main(), nothing happens, although the functions are run as they will cout something if I ask them to.
Here is the test program I wrote to demonstrate this:
#include <iostream>
#include <Windows.h>
#include <fstream>
#include <string>
#define CStringify(x) std::to_string(x).c_str()
int testvar = 12;
int returntestvar = 0;
std::fstream config;
std::string configstring = ".//config.ini";
int main()
{
WriteINI();
ReadINI();
std::cout << returntestvar << std::endl;
getchar();
}
void WriteINI()
{
config.open("config.ini", std::ios::app);
WritePrivateProfileString("Test", "Test1", CStringify(testvar), configstring.c_str());
}
void ReadINI()
{
config.open("config.ini", std::ios::app);
returntestvar = GetPrivateProfileInt("Test", "Test1", 0, configstring.c_str());
}
The above code creates and then edits an .ini file, as it is expected to.
However, if I move the code into a class, it will no longer work.
main.cpp
#include <iostream>
#include <Windows.h>
#include <fstream>
#include <string>
#include "INIClassTest.h"
extern INIParser* Parse;
int main()
{
Parse->WriteINI();
Parse->ReadINI();
std::cout << Parse->returntestvar << std::endl;
getchar();
}
INIClassTest.h
#pragma once
#include <fstream>
#include <string>
#include <Windows.h>
#define CStringify(x) std::to_string(x).c_str()
class INIParser
{
public:
INIParser();
void WriteINI();
void ReadINI();
int testvar;
int returntestvar;
std::fstream config;
std::string configstring;
};
extern INIParser* Parse;
INIClassTest.cpp
#include "INIClassTest.h"
#include <iostream>
INIParser* Parse = new INIParser();
INIParser::INIParser()
{
returntestvar = 0;
testvar = 18;
std::string configstring = ".//config.ini";
}
void INIParser::WriteINI()
{
config.open("config.ini", std::ios::app);
WritePrivateProfileString("Test", "Test1", CStringify(testvar), configstring.c_str());
}
void INIParser::ReadINI()
{
config.open("config.ini", std::ios::app);
returntestvar = GetPrivateProfileInt("Test", "Test1", 0, configstring.c_str());
}
The above code creates an .ini file, but it doesn't edit it or return anything.

You should NOT be using an fstream at all to create/open the INI file manually. WritePrivateProfileString() and GetPrivateProfileInt() handle that for you.
Also, if you read their documentation, you would see that you SHOULD NOT use a relative path for the INI file, or else the file will be relative to the Windows installation folder, not your app folder. So, you probably ARE reading/writing the INI file, just not where you are expecting from/to. If you want your INI file to be relative to your app's folder, you need to retrieve the path of your app's folder 1 and append the INI filename to it.
1: that is really not a good idea in general, though. Depending on where you install your app, the user might not have write access to that folder. You should instead use SHGetFolderPath() or SHGetKnownFolderPath() to get the user's local %AppData% folder, then create your own subfolder inside of it, and then create your INI file inside of that subfolder.
Try this instead:
#include <Windows.h>
#include <iostream>
#include <string>
#define CStringify(x) std::to_string(x).c_str()
std::string GetAppFolder();
std::string GetINIPath();
void WriteINI();
void ReadINI();
int testvar = 12;
int returntestvar = 0;
std::string configstring = GetINIPath();
int main()
{
WriteINI();
ReadINI();
std::cout << returntestvar << std::endl;
std::cin.get();
return 0;
}
std::string GetAppFolder()
{
char szFileName[MAX_PATH];
DWORD len = GetModuleFileName(NULL, szFileName, MAX_PATH);
std::string result(szFileName, len);
std::string::size_type pos = result.find_last_of("\\/");
result.resize(pos+1);
return result;
}
std::string GetINIPath()
{
return GetAppFolder() + "config.ini";
}
void WriteINI()
{
WritePrivateProfileString("Test", "Test1", CStringify(testvar), configstring.c_str());
}
void ReadINI()
{
returntestvar = GetPrivateProfileInt("Test", "Test1", 0, configstring.c_str());
}
The main reason your INIParser class fails is because your constructor is storing the INI file path in a local variable named configstring, instead of in the class's member also named configstring. Thus, the class member is blank when WriteINI() and ReadINI() are called.
Try this instead:
main.cpp
#include <iostream>
#include "INIClassTest.h"
int main()
{
Parse.WriteINI();
Parse.ReadINI();
std::cout << Parse.returntestvar << std::endl;
std::cin.get();
return 0;
}
INIClassTest.h
#pragma once
#include <string>
class INIParser
{
public:
INIParser();
void WriteINI();
void ReadINI();
int testvar;
int returntestvar;
std::string configstring;
};
extern INIParser Parse;
INIClassTest.cpp
#include <Windows.h>
#include "INIClassTest.h"
#include <string>
#define CStringify(x) std::to_string(x).c_str()
INIParser Parse;
static std::string GetAppFolder()
{
char szFileName[MAX_PATH];
DWORD len = GetModuleFileName(NULL, szFileName, MAX_PATH);
std::string result(szFileName, len);
std::string::size_type pos = result.find_last_of("\\/");
result.resize(pos+1);
return result;
}
static std::string GetINIPath()
{
return GetAppFolder() + "config.ini";
}
INIParser::INIParser()
{
returntestvar = 0;
testvar = 18;
configstring = GetINIPath();
}
void INIParser::WriteINI()
{
WritePrivateProfileString("Test", "Test1", CStringify(testvar), configstring.c_str());
}
void INIParser::ReadINI()
{
returntestvar = GetPrivateProfileInt("Test", "Test1", 0, configstring.c_str());
}

Related

Trying to print a map in CPP with LIBCACA

I'm trying to display a simple map using the caca_put_str() / caca_printf() function except that it doesn't interpret the '\n' correctly. Any tips to share to fix this? The documentation is quite empty btw...
Thanks in advance !
Here is the code :
#include <string>
#include <caca.h>
#include <iostream>
#include <fstream>
caca_canvas_t *cv;
static std::string readFile(const std::string &file)
{
std::ifstream buffer(file);
std::string str;
if (buffer.is_open())
{
std::getline(buffer, str, '\0');
buffer.close();
return (str);
}
return (NULL);
}
int main(void)
{
std::string map = readFile("arcade.txt");
caca_display_t *dp;
caca_event_t event;
int width = 1080;
int height = 980;
cv = caca_create_canvas(width, height);
dp = caca_create_display(cv);
if (!dp)
std::exit(1);
caca_set_display_title(dp, "Windows");
while (true)
{
caca_refresh_display(dp);
caca_put_str(cv, 0, 0, map.c_str();
}
caca_free_canvas(cv);
caca_free_display(dp);
}
I'm trying to print this :
############################
#............##............#
#.####.#####.##.#####.####.#
#.####.#####.##.#####.####.#
#..........................#
#.####.##.########.##.####.#
#......##....##....##......#
######.#####.##.#####.######
#....#.##..........##.#....#
#....#.##.###--###.##.#....#
######.##.#......#.##.######
..........#......#..........
######.##.#......#.##.######
#....#.##.########.##.#....#
#....#.##..........##.#....#
######.##.########M##.######
#............##............#
#.####.#####.##.#####.####.#
#...##................##...#
###.##.##.########.##.##.###
#......##....##....##......#
#.##########.##.##########.#
But it is displayed on a single line.

Tried to split wchar or another function to get the file name of running application

I searched here a lot and did try several examples but still can't solve my little problem.
I need to extract the file name 'test.exe' out of the path. Has someone an idea which might work? Other option is to get the file name by another function?
Thanks in advance!
WCHAR fileName[255];
GetModuleFileName(NULL, fileName, 255); // fileName = \TestFolder\test.exe
Look at PathFindFileName():
#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
WCHAR fullPath[MAX_PATH];
GetModuleFileName(NULL, fullPath, MAX_PATH);
LPWSTR fileName = PathFindFileName(fullPath);
Using WinApi
#include <iostream>
#include <string>
#include <windows.h>
std::string GetExecutableName()
{
std::string path = std::string(MAX_PATH, 0);
if( !GetModuleFileNameA(nullptr, &path[0], MAX_PATH ) )
{
throw std::runtime_error(u8"Error at get executable name.");
}
size_t pos=path.find_last_of('/');
if(pos == std::string::npos)
{
pos = path.find_last_of('\\');
}
return path.substr(pos+1);
}
int main()
{
std::cout<< GetExecutableName() << std::endl;
return 0;
}
Using main args
First - arg[0] contains full filename of executable.
#include <iostream>
#include <string>
std::string GetExecutableName(const std::string& exe)
{
size_t pos=exe.find_last_of('/');
if(pos == std::string::npos)
{
pos =exe.find_last_of('\\');
}
return exe.substr(pos+1);
}
int main(int argc,char ** args) {
std::cout << GetExecutableName(args[0])<< std::endl;
}

"extern vector<string> startParsing(FILE*);"

I'm learning C++, and I have the following problem. I can't understand how this sentence interacts
extern vector<string> startParsing(FILE*);
I tried to find information about (FILE*) but I can't find anything.
main.cpp
#include <iostream>
#include <fstream>
#include "Parser/parser.h"
using namespace std;
int main(int argc, char** argv)
{
cout<<"Welcome to Group 01 final project."<<endl;
std::string rule_file = "urbanmodel.zoo";
// parsing
Parser parser(rule_file);
std::vector<std::string> tokens = parser.parse();
parser.printTokens();
return 1;
}
parser.cpp
#include "parser.h"
extern vector<string> startParsing(FILE*); //<---------------------???
Parser::Parser(string filePath){
// open a file handle to a particular file:
this->myfile = fopen(filePath.c_str(), "r");
// make sure it's valid:
if (!this->myfile) {
cout << "I can't open the urbanmodel.zoo file!" << endl;
}
};
vector<string> Parser::parse(){
if(this->myfile)
this->tokens = startParsing(myfile);
return this->tokens;
};
void Parser::printTokens(){
int size = this->tokens.size();
for(int i=0;i<size;i++)
cout<<this->tokens[i];
cout<<std::endl;
};
parser.h
#include <iostream>
#include <vector>
#include <cstdio>
#include "scanner.h"
using namespace std;
class Parser{
private:
FILE* myfile; //<----------------------------------------???
vector<string> tokens;
public:
Parser(string filePath);
vector<string> parse();
void printTokens();
};

Passing a global string variable between .cpp files?

I have created a globals.h header file which has the extern string which is declared as "new_name". In image_output.cpp (main), I have declared string(new_name) as a global variable at the top of my function. Then I passed that variable into the erode_image.cpp(function file) and update it. I have included the globals.h with the main and the function files. The problem is that the "new_name" variable does not get updated in the function file(erode_image.cpp). Does anyone know where I am doing mistake?
globals.h:
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
extern string new_name;
erode_image.cpp (function):
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "functions.h"
#include "globals.h"
using namespace cv;
using namespace std;
Mat erode_image(Mat image, int erosion_size, string new_name) {
new_name += "_eroded";
Mat element = getStructuringElement(MORPH_RECT, Size(erosion_size, erosion_size));
erode(image, image, element);
return image;
}
image_output.cpp (main):
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "functions.h"
#include "globals.h"
using namespace cv;
using namespace std;
Mat imgCrop;
string new_name;
int erosion_size = 25;
int dilate_size = 50;
int brightness = 50;
int threshold_to_zero = 3;
int sectionCount = 5;
int main()
{
String folderpath = "*.png";
vector<String> filenames;
cv::glob(folderpath, filenames);
//removes ./ from beginning of filepath
for (int i = 0; i < size(filenames); i++) {
filenames[i] = filenames[i].erase(0, 2);
}
for (int i = 0; i < size(filenames); i++) {
if (filenames[i].find("_cropped") == string::npos) {
string image_path = filenames[i];
string new_name = image_path.substr(0, image_path.find_last_of('.')) + "_cropped";
string extension = image_path.substr(image_path.find_last_of("."));
Mat img = imread(image_path);
cvtColor(img, img, cv::COLOR_BGR2GRAY);
img = crop_image(img);
img = rotate_image(img);
img = erode_image(img, erosion_size, new_name);
//img = average_section_threshold(img, sectionCount, new_name);
//img = dilate_image(img, dilate_size, new_name);
string new_file_name = new_name + extension;
imwrite(new_file_name, img);
cout << "Image Succesfully Saved!";
}
}
}
You already solved your problem in the comments, so I'm just typing it up to make it a proper answer.
Your original code was like this:
globals.h
extern std::string new_name;
other_file.cpp
#include "globals.h"
void func(std::string new_name) // <- shadows the global new_name
{
new_name += "_stuff";
}
main.cpp
#include "globals.h"
std::string new_name;
int main()
{
new_name = "bla";
func(new_name);
std::cout << new_name << std::endl;
return 0;
}
Here new_name in main is not updated, and the output is bla. This happens because the argument in func shadows the global/extern variable.
The correct way to use extern (if you really want to keep the global) is to remove the argument to func:
globals.h
extern std::string new_name;
other_file.cpp
#include "globals.h"
void func()
{
new_name += "_stuff";
}
main.cpp
#include "globals.h"
std::string new_name;
int main()
{
new_name = "bla";
func();
std::cout << new_name << std::endl;
return 0;
}
Now the shadowing is gone, and the output is bla_stuff. However, this uses a global which is something to avoid, since being global makes it hard to reason about where, when, and how the variable is updated (as it can be accessed literally anywhere in the program).
A better solution is to get rid of the global, and instead pass the variable like originally except by reference.
other_file.cpp
void func(std::string& new_name)
{
new_name += "_stuff";
}
main.cpp
int main()
{
std::string new_name = "bla";
func(new_name);
std::cout << new_name << std::endl;
return 0;
}
Now the global is gone (as is the globals.h file), and the output is still bla_stuff as intended.

vector<wstring> as Return value and Parameter

I want to create some modules for my program. I want to call a function and pass a vector as a parameter. The return value should also be a vector.
My code looks like this
main.cpp
//BlueSmart.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
#include "stdafx.h"
#define WIN32_LEAN_AND_MEAN
using namespace std;
#pragma comment(lib, "Irprops.lib")
BLUETOOTH_FIND_RADIO_PARAMS m_bt_find_radio = {
sizeof(BLUETOOTH_FIND_RADIO_PARAMS)
};
BLUETOOTH_RADIO_INFO m_bt_info = {
sizeof(BLUETOOTH_RADIO_INFO),
0,
};
BLUETOOTH_DEVICE_SEARCH_PARAMS m_search_params = {
sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),
1,
0,
1,
1,
1,
15,
NULL
};
BLUETOOTH_DEVICE_INFO m_device_info = {
sizeof(BLUETOOTH_DEVICE_INFO),
0,
};
HANDLE m_radio = NULL;
HBLUETOOTH_RADIO_FIND m_bt = NULL;
HBLUETOOTH_DEVICE_FIND m_bt_dev = NULL;
int wmain(int argc, wchar_t **args) {
while(true) {
m_bt = BluetoothFindFirstRadio(&m_bt_find_radio, &m_radio);
do {
localBluetoothDevices ();
m_search_params.hRadio = m_radio;
::ZeroMemory(&m_device_info, sizeof(BLUETOOTH_DEVICE_INFO));
m_device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
m_bt_dev = BluetoothFindFirstDevice(&m_search_params, &m_device_info);
vector<wstring> vec;
int m_device_id = 0;
do {
wostringstream tmp;
++m_device_id;
//Something like this <----------------------------------------
externBluetoothDevices (vec);
//Something like this <----------------------------------------
wprintf(L"********************************************************************** \n");
wprintf(L"\tDevice %d:\r\n", m_device_id);
wprintf(L"\t\tName: %s\r\n", m_device_info.szName);
wprintf(L"\t\tAddress: %02x:%02x:%02x:%02x:%02x:%02x\r\n", m_device_info.Address.rgBytes[0], m_device_info.Address.rgBytes[1], m_device_info.Address.rgBytes[2], m_device_info.Address.rgBytes[3], m_device_info.Address.rgBytes[4], m_device_info.Address.rgBytes[5]);
wprintf(L"====================================================================== \n");
for (int i = 0; i < 6; i++) {
tmp << hex << m_device_info.Address.rgBytes [i];
if (i < 5)
tmp << L':';
}
vec.push_back(tmp.str());
} while(BluetoothFindNextDevice(m_bt_dev, &m_device_info));
BluetoothFindDeviceClose(m_bt_dev);
//Sleep(10*1000*60);
Sleep(10000);
} while(BluetoothFindNextRadio(&m_bt_find_radio, &m_radio));
BluetoothFindRadioClose(m_bt);
}
return 0;
}
//Lokal verfügbare bzw. angeschlossene Bluetooth-Devices
void localBluetoothDevices (){
int m_radio_id = 0;
m_radio_id++;
BluetoothGetRadioInfo(m_radio, &m_bt_info);
//Lokaler Bluetoothadapter
wprintf(L"====================================================================== \n");
wprintf(L"Local Device Nr. %d\n", m_radio_id);
wprintf(L"\tName: %s\r\n", m_bt_info.szName);
wprintf(L"\tAddress: %02x:%02x:%02x:%02x:%02x:%02x\r\n", m_bt_info.address.rgBytes[0], m_bt_info.address.rgBytes[1], m_bt_info.address.rgBytes[2], m_bt_info.address.rgBytes[3], m_bt_info.address.rgBytes[4], m_bt_info.address.rgBytes[5]);
}
//Extern verfügbare bzw. Bluetooth-Devices
vector<wstring> externBluetoothDevices (vector<wstring> &vec){
return vec;
}
stdafx.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <windows.h>
#include <stdlib.h>
#include <bthdef.h>
#include <BluetoothAPIs.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <iomanip>
#include <conio.h>
void localBluetoothDevices ();
vector<wstring> externBluetoothDevices (vector<wstring>);
It says that vector is not a known type. What am I doing wrong?
In stdafx.h replace
vector<wstring> externBluetoothDevices (vector<wstring>);
with
std::vector<std::wstring> externBluetoothDevices (std::vector<std::wstring>);
Basically the issue was although you put using namespace std; in your cpp file that doesn't count in your header file which is before the using declaration is seen.
Also note that your defintion in the cpp file is different. In the cpp file you have a reference
vector<wstring> externBluetoothDevices (vector<wstring>&);
Decide which you really want.
You should pass a pointer of a vector.