Parameters of GetPrivateProfileInt method - c++

Question: How to use string/char* variable as the path parameter to GetPrivateProfileInt method.
I m trying to use GetPrivateProfileInt given for windows. The following code runs perfeclty without any issue:
int x = GetPrivateProfileInt(L"x",L"y",1,L"This\\is\\the\\path");
But in my case, the path is being passed to the function. Something like this:
void fun(std::string path)
{
//error const char* is incampatible with LPCWSTR.
int x = GetPrivateProfileInt(L"x",L"y",1,path.c_str());
}
In some attempts given below, x is recieving the default value. i.e. the path is not being passed to the GetPrivateProfileInt method correctly.
Following are several other attempts made by me:
Attempt1:
// No error, default value is being read.
int x = GetPrivateProfileInt(L"x",L"y",1,(LPCTSTR)path.c_str());
Attempt2:
// No error, default value is being read.
int x = GetPrivateProfileInt(L"x",L"y",1,(wchar_t*)path.c_str());
Attempt3:
//_T() macro giving error.
// 'Ls' : undeclared identifier.identifier "Ls" is undefined.
LPCTSTR path_s = _T(path.c_str());
int x = GetPrivateProfileInt(L"x",L"y",1,path_s);
I went through the answers here but not able find out the solution.

There are two versions of the function, one takes UCS-2 characters (GetPrivateProfileIntW) and one takes char characters (GetPrivateProfileIntA). There are no versions which allow you to mix the parameters. Your options are to either change the appname and keyname parameters to single-byte to match your data
GetPrivateProfileIntA("x", "y", 1, path.c_str());
or to convert the last parameter to UCS-2 using MultibyteToWideChar, then call GetPrivateProfileIntW.
Pointer-casting is NOT a conversion of the character encoding, and will not work. The compiler type system is there to help you, and making it shut up with a cast is nearly always the wrong thing to do (exception: the return value of GetProcAddress does need a cast).

Related

FindFirstFile cout problems

I need to find files with certain extentions, for example *.doc, *.docx
First, i'm looking for all files
lstrcat(szPath, L"*");
hFind = FindFirstFile(szPath, &fdFindData);
Then, i compare founded file with extention i need
PCWSTR str1 = L".doc";
if(NULL != StrStr(fdFindData.cFileName,str1)) {
FoundFileFunction(fdFindData.cFileName);
}
And then I got problem with cout
VOID FoundFileFunction(HANDLE hFile)
{
std::cout<<hFile;
}
This is output:
009AE50000
009AEB0000
009AEBBB00
and so on. What's the problem?
WIN32_FIND_DATA::cFileName is a TCHAR[MAX_PATH], not a HANDLE.
I don't know why you wrote HANDLE, as that's not uttered on the documentation page even once.
Your function is trying to print out the C-string filename as if it were a HANDLE, which is a different kind of pointer to a TCHAR*. It doesn't know to take the pointer as a TCHAR* so it doesn't know you want it to format the output as a string. It can only know to print the address represented by the pointer.
Your function FoundFileFunction should take a TCHAR*.
The problem would have been automatically detected had you used STRICT mode. If (for example) NO_STRICT is defined then HANDLE is an alias for void* which, per the rules of the language, can be initialised implicitly from a TCHAR*. You should always compile with STRICT defined: that would have changed the types not to be implicitly convertible to one another, and you would have received a compilation error for your mistake.
Furthermore, if your program is using Unicode, then TCHAR is not char but wchar_t, so you need to use not std::cout but std::wcout.

Cannot resolve type for template function

I'm trying to code up something very simple in D, but I'm having a few problems with one of the standard library template functions (specifically, nextPermutation from std.algorithm).
The crux of what I'm trying to do is to create all permutations of pandigital numbers (that is, numbers including all the values 1 to 9 exactly once).
To do this, I've done the following:
import std.algorithm;
import std.conv;
int[] pandigitals()
{
char[] initial = "123456789".dup;
auto pan = [to!int(initial)];
while(nextPermutation!(initial)) {
pan ~= to!int(initial);
}
return pan;
}
This gives me the error:
Error: cannot resolve type for nextPermutation!(initial)
I've also tried to explicitly set the types:
while(nextPermutation!("a<b", char[])(initial))
However, this gives an error saying it cannot match the template:
Error: template instance std.algorithm.nextPermutation!("a < b", char[]) does not match template declaration nextPermutation(alias less = "a < b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
What is the correct form of the call meant to be?
Well, your first problem is that you're passing initial as a template argument instead of a function argument. The !() is for template arguments. so, instead of
while(nextPermutation!(initial))
you need to do
while(nextPermutation(initial)) {
Now, that will still give you an error.
q.d(10): Error: template std.algorithm.nextPermutation cannot deduce function from argument types !()(char[]), candidates are:
/usr/include/D/phobos/std/algorithm.d(12351): std.algorithm.nextPermutation(alias less = "a<b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
And that's because hasSwappableElements!(char[]) is false, and per nextPermutations' template constraint it needs to be true for a type to work with nextPermutations.
It's false because all strings are treated as ranges of dchar rather than their actual element type. This is because in UTF-8 (char) and UTF-16 (wchar), there are multiple code units per code point, so operating on individual code units could break up a code point, whereas in UTF-32 (dchar), there's always one code unit per code point. Essentially, if arrays of char or wchar were treated as ranges of char or wchar, you'd run a high risk of breaking up characters so that you'd end up with pieces of characters rather than whole characters. So, in general in D, if you want to operate on an individual character, you should use dchar, not char or wchar. If you're not very familiar with Unicode, I'd suggest reading this article by Joel Spoelsky on the subject.
However, regardless of why hasSwappableElements!(char[]) is false, it is false, so you're going to need to use a different type. The simplest thing would probably be to just swap your algorithm over to using dchar[] instead.
int[] pandigitals()
{
dchar[] initial = "123456789"d.dup;
auto pan = [to!int(initial)];
while(nextPermutation(initial)) {
pan ~= to!int(initial);
}
return pan;
}

QSettings does not differentiate between string and int values

I am writing and reading string and int values using a file-backed QSettings object.
When I later try to read the values from a different process, the values are read as strings instead of int.
This is the code I am using to write values:
QSettings settings("TestQSettings.ini", QSettings::IniFormat);
settings.setValue("AAA",QString("111"));
settings.setValue("BBB",222);
This is the file created:
[General]
AAA=111
BBB=222
This is the code I am using to read values:
QVariant qvar = settings.value("AAA");
std::cout << "AAA type " << qvar.type() << std::endl;
qvar = settings.value("BBB");
std::cout << "BBB type " << qvar.type() << std::endl;
If I run this code from the same process:
AAA type 10
BBB type 2
If I run this code from a different process:
AAA type 10
BBB type 10
I know it's possible to convert the types after they have been read.
Unfortunately, this solution will require modifying Windows legacy cross-platform code which I prefer not to modify, for example multiple calls to RegQueryValueEx().
Is it possible to store and read the type information for strings and integers?
For example, Strings will have quotes "" and integers will not:
[General]
AAA="111"
BBB=222
This problem is present on both Qt 4 and Qt 5, on Linux.
Whoa whoa, are you using .ini files or the registry?
With .ini files it's obviously impossible to know what the type was, since it's all a string. You can attempt conversion of the variant to an integer (don't use canConvert!), and assume it's an integer if it converts into one.
With the registry, QSettings will work as you expect it to.
I really don't see what the problem is. Don't use .ini files if you wish to retain type information. You'd face exactly the same problems if you wrote the code by hand in a platform-dependent manner.
You can explicitly write quoted strings into the .ini files, and check for presence of quotes when reading them back. If the quotes are not present, you can try conversion to an integer.
I solved this problem for a component which needs to save and restore variants of arbitrary type, without knowing what its clients expect. The solution was to store the variant's typeName() alongside each value:
void store(QSettings& settings, const QString& key, const QVariant& value)
{
settings.setValue(key+"value", value);
settings.setValue(key+"type", value.typeName());
}
When reading back, we also read the type name, and convert() the variant if it's not already the correct type, before returning it.
QVariant retrieve(const QSettings& settings, const QString& key)
{
auto value = settings.value(key+"value");
const auto typeName = settings.value(key+"type").toString();
const bool wasNull = value.isNull(); // NOTE 1
const auto t = QMetaType::type(typeName.toUtf8()); // NOTE 2
if (value.userType() != t && !value.convert(t) && !wasNull) {
// restore value that was cleared by the failed convert()
value = settings.value(key+"value");
qWarning() << "Failed to convert value" << value << "to" << typeName;
}
return value;
}
Notes
The wasNull variable is in there because of this niggle of convert():
Warning: For historical reasons, converting a null QVariant results in a null value of the desired type (e.g., an empty string for QString) and a result of false.
In this case, we need to ignore the misleading return value, and keep the successfully-converted null variant of the correct type.
It's not clear that UTF-8 is the correct encoding for QMetaType names (perhaps local 8-bit is assumed?); my types are all ASCII, so I just use toLatin1() instead, which might be faster. If it were an issue, I'd use QString::fromLatin1 in the store() method (instead of implicit char* to QString conversion), to ensure a clean round-trip.
If the type name is not found, t will be QMetaType::UnknownType; that's okay, because convert() will then fail, and we'll return the unconverted variant (or a null). It's not great, but it's a corner case that won't happen in normal usage, and my system will recover reasonably quickly.
Turns out the solution was very simple.
When values are written to the INI file, the type is known.
I am appending to the value "\"STRING right before SetValue
When values are read back from the INI file.
I verify that string types have the above postfix.
If they do, I chop the postfix off.
If they don't I assume they are integers instead of strings.
Works like a charm!
Thanks to you all and especially #Kuba Ober for practically handing out the solution.

How to invoke an exported function from DLL written in C/C++ which return type is char* or string?

We designed C/C++ DLL just like this:
WIN32_DLL_EXPORT int FnRetInt(int i)
{
....
return 32 ;
}
WIN32_DLL_EXPORT char* FnRetString()
{
return "THIS IS A TEST STRING" ;
}
when we invoke these two functions in Go by using syscall:
hd:=syscall.NewLazyDLL(dll_path)
proc:=hd.NewProc(dll_func_name)
ret:=proc.Call()
we found:
FnRetInt worked ok, but FnRetString didn't. proc.Call return type is uintptr, how can we change it to the type we wanted (for exsample: char* or string)?
A uintptr is a Go type that represents a pointer. You can use the unsafe package and convert it to unsafe.Pointer, and then you can convert an unsafe.Pointer into any Go pointer type. So you could do something like
str := (*uint8)(unsafe.Pointer(ret))
to get a *uint8 back.
Look at syscall.Getwd windows implementation http://code.google.com/p/go/source/browse/src/pkg/syscall/syscall_windows.go#323. It is different from your problem:
it passes buffer to the dll, instead of receiving it from dll;
the data is uint16s (Microsoft WCHARs), instead of uint8s;
GetCurrentDirectory tells us how long resulting string is going to be, while your example, probably, expects you to search for 0 at the end;
But should give you enough clues.
Alex

CString error, 'CString': is not a member of 'ATL::CStringT<BaseType, StringTraits>'

I am trying to do this:
#include <atlstr.h>
CHAR Filename; // [sp+26Ch] [bp-110h]#1
char v31; // [sp+36Ch] [bp-10h]#1
int v32; // [sp+378h] [bp-4h]#1
GetModuleFileNameA(0, &Filename, 0x100u);
CString::CString(&v31, &Filename);
But I am getting the compiler error C2039:'CString': is not a member of 'ATL::CStringT'
This is a non MFC based dll, but according to the docs you should be able to use CString functionality with the include #include atlstr.h how do I make it work?
Thanks
That's not how constructors are invoked in C++.
CString s = CString(&v21,&File);
Note that GetModuleFilename expects a pointer to an array of characters (which it fills), not a pointer to a single character. Your code is therefore doomed to crash at runtime.
You have several problems in this code snippet:
1) CHAR Filename; declares a variable that is only a single character. However, GetModuleFileNameA expects to be given a pointer to an array of characters. When you pass the parameters &Filename and 0x100u you would make it think that &Filename points to an array of memory with room for up to 256 characters. However, as written in your snipped, it's only a single character. Thus you would have a bad buffer overflow.
Filename should most likely be declared as CHAR Filename[0x100]; in this case. That would also mean you don't need to take the address of Filename when passing it to that function. So the call would then be written as GetModuleFileNameA(0, Filename, 0x100u);
2) When writing code for a constructor, you define is by writing something similar to CString::CString (using whatever your class's name is) and then filling out the function. However, when using a constructor you don't use that syntax at all. You don't call CString::CString() to create a CString object.
You would have to choose an name for the CString object, such as "FilenameStr". So the in the context of you code you would write something like CString FilenameStr(Filename);
3) As implied at the end of the last point, the parameters you are trying to pass to the constructor are wrong. &v31 and &Filename would each by pointers to characters in your original code. However, as far as I know, CString does not have any constructor that takes two character pointers.
I can't even tell how v31 is supposed to be involved there, but it doesn't seem necessary at all. If you want to fill a CString with the contents of a character array, then you can just pass that array to the constructor and it will take care of everything. So, something like CString FilenameStr(Filename);