Jako PH
asked on
C++/CLR GetSystemMetrics Doesn't work
Hi i was having some problems in finding the screen width and height how ever i am working on an project and i finally found
Isn't it supported in Clr ? if yes what i can use instead.
GetSystemMetric(SM_CXSCREEN)
but every time i use this function in CLR i am getting this problem :1>Width.obj : error LNK2028: unresolved token (0A00002E) "extern "C" int __stdcall GetSystemMetrics(int)" (?GetSystemMetrics@@$$J14YGHH@Z) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
1>Width.obj : error LNK2019: unresolved external symbol "extern "C" int __stdcall GetSystemMetrics(int)" (?GetSystemMetrics@@$$J14YGHH@Z) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z)
Isn't it supported in Clr ? if yes what i can use instead.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks a lot Sara you always help me <3
anyway i have another question ...
I have a list view and i am getting the selected text with :
String ^Selected = listView1->SelectedItems[0 ]->SubItem s[0]->Text ;
But i wanted to write the result to an ini file :
WritePrivateProfileSection (Selected, L"Key",L". //Test.txt ");
But the writeprivateprofilesection needs a parameter of type LPCWSTR so this string cannot be used in it
any ideas ?
anyway i have another question ...
I have a list view and i am getting the selected text with :
String ^Selected = listView1->SelectedItems[0
But i wanted to write the result to an ini file :
WritePrivateProfileSection
But the writeprivateprofilesection
any ideas ?
L".//Test.txt" is already a Long Pointer to Constant Wide String (LPCWSTR). if Test.txt wasn't found you may Change to L".\\test.txt" or L"test.txt" what is all the same (if your current folder is the right one).
a System::String is a gc object. you can get a pointer from it by code like
(code from https://msdn.microsoft.com/de-de/library/ms235631.aspx)
if you have atl or mfc with your native code (or include atlbase.h and atlconv.h) you simply could do
the CString automatically handles wide strings if character set is not set to multi-byte but to UNICODE (what is default) and has a constructor that takes a String. it also has a operator const wchar_t * which casts a CString to LPCWSTR.
so
you can do
note, the above would only write one entry Key=Value to the new section.
if you want to write more entries you have to add binary zero wide characters (=16 bit integer 0) or L'\0'. to the string and then append the next key=value pair after the zero. the string ends with a double-zero what is also required for your single pair (see code sample where i used a CString constructor that takes a LPCWSTR and a length in characters) . it probably is more easy to use CString or std::wstring for this kind of concatenation.
Sara
a System::String is a gc object. you can get a pointer from it by code like
(code from https://msdn.microsoft.com/de-de/library/ms235631.aspx)
// Set up a System::String and display the result.
String ^orig = gcnew String("Hello, World!");
Console::WriteLine("{0} (System::String)", orig);
// Obtain a pointer to the System::String in order to
// first lock memory into place, so that the
// Garbage Collector (GC) cannot move that object
// while we call native functions.
pin_ptr<const wchar_t> wch = PtrToStringChars(orig);
if you have atl or mfc with your native code (or include atlbase.h and atlconv.h) you simply could do
CString wstr(selected.Text());
the CString automatically handles wide strings if character set is not set to multi-byte but to UNICODE (what is default) and has a constructor that takes a String. it also has a operator const wchar_t * which casts a CString to LPCWSTR.
so
you can do
String ^Selected = listView1->SelectedItems[0]->SubItems[0]->Text;
WritePrivateProfileSection(CString(Selected), CString(L"Key=Value\0\0", 11), L"Test.txt");
note, the above would only write one entry Key=Value to the new section.
if you want to write more entries you have to add binary zero wide characters (=16 bit integer 0) or L'\0'. to the string and then append the next key=value pair after the zero. the string ends with a double-zero what is also required for your single pair (see code sample where i used a CString constructor that takes a LPCWSTR and a length in characters) . it probably is more easy to use CString or std::wstring for this kind of concatenation.
Sara
ASKER
So CString converts from String ^Selected to std::string ?
no, CString has a constructor that takes a System::String.
CString also has an operator LPCTSTR (a so-called cast operator) which returns a const pointer to TCHAR. TCHAR is wchar_t if the characterset in the project properties is UNICODE (more precisely it is not UNICODE but UTF16 wide characters). TCHAR is char if the characterset is 'multi-byte' what actually means ANSI characterset.
with the cast operator of CString you always can use a CString variable where a const wchar_t * (LPCWSTR) was required (UNICODE) or const char * (LPCSTR) in case of ANSI character set. in mixed managed and unmanaged project you better use wide characters for CString to avoid errors. System::String is always wide characters.
std::string now is std::basic_string<char> and would take a const char * in one of ist constructors. so if you have a CString with wide characters you firstly have to convert the const wchar_t * to const char * (what could be done by wcstombs function). then you could feed the std::string with that const char * pointer. much simpler is to use std::wstring what is std::basic_string<wchar_t> . with that you can do:
if the project uses wide strings.
sara
CString also has an operator LPCTSTR (a so-called cast operator) which returns a const pointer to TCHAR. TCHAR is wchar_t if the characterset in the project properties is UNICODE (more precisely it is not UNICODE but UTF16 wide characters). TCHAR is char if the characterset is 'multi-byte' what actually means ANSI characterset.
with the cast operator of CString you always can use a CString variable where a const wchar_t * (LPCWSTR) was required (UNICODE) or const char * (LPCSTR) in case of ANSI character set. in mixed managed and unmanaged project you better use wide characters for CString to avoid errors. System::String is always wide characters.
std::string now is std::basic_string<char> and would take a const char * in one of ist constructors. so if you have a CString with wide characters you firstly have to convert the const wchar_t * to const char * (what could be done by wcstombs function). then you could feed the std::string with that const char * pointer. much simpler is to use std::wstring what is std::basic_string<wchar_t>
System::String^ sysstr = L"Hello World";
std::wstring wstr = CString(sysstr);
if the project uses wide strings.
sara
ASKER
Thanks sara my problem now is the file is always created as ANSI which means i can't write unicode (Arabic) to the file and if i wrote the result would be ???????
So i need a way to create the file in unicode settings is that possible while using the ini file ?
So i need a way to create the file in unicode settings is that possible while using the ini file ?
String ^Shi = listView1->SelectedItems[0]->SubItems[0]->Text;
WritePrivateProfileSection(CString(Shi),L"Name = "+CString(Shi), L".//"+CString(Shi)+".txt");
ASKER
I mean that when i write unicode to a file the must be in unicode settings but i want to make this settings from the code automatic since my project will create a lot of file so i can't change the settings of every file
ASKER
Didn't find any solution for that on google !
ASKER
I guess i have to use xml instead ?
do you need arabic characters in the ini file? or only in the files where the file names are normal ASCII and the filename is in the ini file?
to write UNICODE into a text file i would suggest to use UTF-8 rather than UTF-16 (what is the MS UNICODE). in UTF-8 all ASCII characters are 1 byte. so if the text is mostly ASCII you can it read without problems. the disadvantage is that you have to care for multibyte utf-8 characters and reconvert them to utf-16 if needed. in c++ you would use the function MultiByteToWideChar function which takes a char array (or pointer to char) as Input and CP_UTF8 as 'codepage' argument, and then produces a wide char buffer in UTF-16. the other way is WideCharToMultiByte which takes the wide string (wchar_t* as explained above) and has an UTF-8 coded char array as output (which you could write in the value part of an inifile entry)
Sara
to write UNICODE into a text file i would suggest to use UTF-8 rather than UTF-16 (what is the MS UNICODE). in UTF-8 all ASCII characters are 1 byte. so if the text is mostly ASCII you can it read without problems. the disadvantage is that you have to care for multibyte utf-8 characters and reconvert them to utf-16 if needed. in c++ you would use the function MultiByteToWideChar function which takes a char array (or pointer to char) as Input and CP_UTF8 as 'codepage' argument, and then produces a wide char buffer in UTF-16. the other way is WideCharToMultiByte which takes the wide string (wchar_t* as explained above) and has an UTF-8 coded char array as output (which you could write in the value part of an inifile entry)
Sara
ASKER
You didn't answer me about XML ...
i don't see where XML should help. of course you can write different encodings to XML which are defined in the XML Header. nevertheless you need conversion if you write or read the XML and have or need a different encoding to that which is defined in the XML. inifiles more easily could be read or written than XML and have much less overhead.
can you answer my question whether you want to write UTF-16 to the inifile or to other files which are only referenced in the inifile?
Sara
can you answer my question whether you want to write UTF-16 to the inifile or to other files which are only referenced in the inifile?
Sara
ASKER
that's what i mean
[محمد]
name = محمد
[محمد]
name = محمد
ASKER
could you give me an example of how to make the file settings utf-8 like u said ?
String ^Selected = listView1->SelectedItems[0]->SubItems[0]->Text;
char szName[256] = { '\0' }; // create a char buffer which is big enough for section name
char szBuf[1024] = { '\0' }; // create a char buffer which is big enough for entries
CString strW = Selected;
WideStringToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, strW, strW.GetLength(), szName, sizeof(szName), NULL, NULL);
//the szBuf has all zero characters. we easily can add key=value pairs:
wchar_t wpair[256] = { 0 };
wcscpy(wpair, L"key1=value1"); // here you can use Unicode characters
strW = wpair;
char pair[512] = { '\0' };
int nlen = WideStringToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, strW, strW.GetLength(), pair, sizeof(pair), NULL, NULL);
int noff = 0;
strcpy(&szBuf[noff], pair);
noff += nlen + 1; // add the length + 1 for zero separator
wcscpy(wpair, L"key1=value1"); // here you can use Unicode characters
strW = wpair;
nlen = WideStringToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, strW, strW.GetLength(), pair, sizeof(pair), NULL, NULL);
strcpy(&szBuf[noff], pair);
noff += nlen + 1;
// ... and so on
// you also could add entries in a loop
// finally increment noff to have two zeros at end of buffer
// we now use the single char version of writeprivateprofilesection
WritePrivateProfileSectionA(szName, szBuf, noff, "Test.txt");
to get the utf-8 data back you do the reverse
// convert section name to utf-8 (if necessary)
String ^Selected = listView1->SelectedItems[0]->SubItems[0]->Text;
char szName[256] = { '\0' }; // create a char buffer which is big enough for section name
CString strW = Selected;
WideStringToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, strW, strW.GetLength(), szName, sizeof(szName), NULL, NULL);
// convert key to get to utf-8 (if necessary)
wchar_t wkey[256] = { 0 };
wcscpy(wkey, L"key"); // here you can use Unicode characters
strW = wkey;
char szKey[512] = { '\0' };
int nlen = WideStringToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, strW, strW.GetLength(), szKey, sizeof(szKey), NULL, NULL);
char szValue[512] = { '\0' };
int len = GetPrivateProfileStringA(szName, szKey, "", szValue, sizeof(szValue), "Test.txt");
if (len > 0)
{
MultiByteToWideChars(CP_UTF8, WC_ERR_INVALID_CHARS, szValue, len, strW.GetBuffer(256), 256, NULL, NULL);
strW.ReleaseBuffer(-1);
SystemString^ value = (LPCWSTR)strW; // hope that works. i am not experienced in managed c++
}
Sara
name = محمد
note, don't use space character left or right of the = between key and value.
if section names and key names would be ASCII you much easier could handle utf-8 values.
if there is any problem converting chars between UTF-16 and UTF-8, the flag WC_ERR_INVALID_CHARS makes that the conversion function fails.
if you don't want that, replace WC_ERR_INVALID_CHARS by 0.
Sara
ASKER
Sorry but what's the header file of WideStringToMultiByte ?
ASKER
Is there a definition for widestringtomultibyte or what I cannot even find it on msdn or specially on google.
it was my fault. the function was named WideCharsToMultiByte.
Sara
Sara
The question was solved.
Sara
Sara
ASKER