There is a function that copies a value to registry using
RegSetValueEx(hKey, theName, 0, REG_DWORD, (unsigned char *)&value, sizeof(value));
theName passed by the caller is a char *
I get a compile error:
Argument of type char * is incompatible with LPCWSTR
Why do I get this error?
I have copied some code that uses it (and I know it builds succesfully) and built it myself.
Has the function changed or my project settings is messed up? I do not know which version of VS the code was created.
It is because Windows has been a Unicode operating system for the past 18 years. Its default string type is utf-16 encoded, wchar_t* in your code. Or std::wstring. Or LPCWSTR, the typedef used in the Windows headers. Note the prevalence of 'w', it means Wide.
It still supports char* strings, you have to use RegSetValueExA(). Note the added "A". It is also a project setting to make your program use the old multi-byte API. Project + Properties, General, Character Set. Avoid marketing to the other 5 billion customers when you do.
Related
I copied code that's supposed to change desktop wallpaper. I have this constant in my program:
const char * image_name = "button_out.gif";
Later, I write the image on disk using Magick++:
image.write(image_name);
The image appears in program's working directory. If I run the program directly from explorer the working directory equals the program location.
Because the code prints the 0x80070002 - File not found error I added a exist function in the beginning:
#include <sys/stat.h>
bool exists(const char* name) {
struct stat buffer;
return (stat (name, &buffer) == 0);
}
void SetWallpaper(LPCWSTR file){
if(!exists((const char* )file)) {
wcout << "The file "<<file<<" does not exist!" << endl;
return;
... actually try to set a wallpaper ...
}
The error is not printed however and the code proceeds.
Now the question is:
Does my exist function work properly?
Where does windows look for that image?
Full code to set a Magick++ generated image as background in case I have missed something relevant in this question.
Problem 1: String Conversions
Your primary problem is that you are attempting to use LPCWSTR (a const wchar_t *) and const char * interchangeably. I see a number of issues in your source, in particular:
You start with const char * image_name.
You then cast it to a LPCWSTR to pass to SetWallpaper. This basically guarantees that SetWallpaper will fail, as desktop->SetWallpaper is not able to handle non wide-character strings.
You then cast it back to a const char * to pass to stat() via exists(). This should work in your situation (since the original string really is a char *) but isn't correct because your string parameter to SetWallpaper is supposedly a proper LPCWSTR.
You need to pick a string format (wide-character vs. what Windows terms "ANSI") and stick to that format, using consistent APIs throughout.
The easiest option is probably just to leave most of your code untouched, but modify SetWallpaper to take a const char * and convert to a wide-character string when needed (for this you can use mbstowcs). So, for example:
void SetWallpaper(const char * file){ // <- Use a const char* parameter.
...
// Convert to a wide-character string to pass to COM:
wchar_t wcfile[MAX_PATH + 1];
mbstowcs(wcfile, file, sizeof(wcfile) / sizeof(wchar_t));
// Pass the converted wide-character string:
desktop->SetWallpaper(wcfile, 0);
...
}
The other option would be to use wide-character strings throughout, i.e.:
LPCWSTR image_name = L"button_out.gif";
Modify exists() to take a LPCWSTR and use _wstat() instead.
Use wide-character versions of all other API functions.
However, I am unsure how that would interact with the ImageMagick API, which may not have wide-character support. So it's up to you. Choose whatever approach is the easiest to implement but make sure you are consistent. The general rule is do not cast between LPCWSTR and const char *; if you are ever in a situation where you need to change one to the other, you cannot cast, you must convert (via mbstowcs or wcstombs).
Problem 2: SetWallpaper default directory is not current working directory
At this point, your string usage will be consistent. Now that you have that problem ironed out, if SetWallpaper fails while exists() does not, then SetWallpaper is not looking where you think it is. As you discovered in your comment, SetWallpaper looks in the desktop by default. In this case, while I have not tested it, you may be able to work around this by passing an absolute path to SetWallpaper. For this, you can use GetFullPathName to determine the absolute file name given your relative path. Remember to be consistent with your string types, though.
Also, if stat() continues to fail, then that problem is either that your working directory is not what you think it is, or your filename is not what you think it is. To that end you will want to perform the following tests:
Print the current working directory at the point you check for the files existence, verify it is correct.
Print the filename when you check for its existence, verify it is correct.
You should be good to go once you work all the above issues out.
I'm writing a small program with QT creator under windows 7 (32 bit). My goal is to create a windows key.
I'm using
QSettings settings("HKEY_CURRENT_USER\\Software\\Company", QSettings::NativeFormat);
settings.setValue("C:\\path\\prog.exe", "Value");
but in the windows registry the generated key has the value C:/path/prog.exe
I've tryed to convert it with
qDebug() << QDir::toNativeSeparators("C:\\path\\prog.exe");
the output of qDebug() is right c:\path\prog.exe
but doing
settings.setValue(QDir::toNativeSeparators("C:\\path\\prog.exe"), "Value");
results again in a path with a wrong slash.
do there is a way to write correctly the path in the windows registry without using the windows API?
Thanks
Francesco
You can't do it even with WinAPI. Because you are specifying an invalid key. You should understand that QSettings class use platform-specific backend, so it is useful to read documentation, if something does not work as expected. Start here.
QSettings class performs custom transformation to keys and values, so you may store any QVariant values there. Even arrays. Invalid values for each platform will be escaped. You may look at exact transformation rules in Qt sources.
Note: values transformation depends on type of settings storage. For example^ for .ini files.
ok, I managed to achieve my goal by using
RegSetValueEx(hkey, TEXT("C:\\path\\prog.exe"), 0, REG_SZ, (LPBYTE)TEXT("WIN98"), 6 * sizeof(WCHAR));
for a constant string.
in case the program path is strored in a char * (like in my case), it works with
char* exe_name = /*something*/
wchar_t* wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, exe_name, -1, wString, 4096);
RegCreateKeyEx( .......... )
RegSetValueEx(hkey, (LPCWSTR) wString, 0, REG_SZ, (LPBYTE)TEXT("WIN98"), 6 * sizeof(WCHAR));
Francesco
This question already has answers here:
PostgreSQL: Case insensitive string comparison
(6 answers)
Closed last year.
Motivation: I would like to work with strings in PostgreSQL in a case insensitive manner. I am aware of the CITEXT data type and I am also aware of functional indexes where I can use the LOWER function.
Still, the most efficient solution seems to be using a case insensitive collation - something trivial in Sql Server. Anyway, it seems that PostgreSQL is unable to define its own custom collations, instead it derives them from the locales found in the OS, i.e. Windows in my case.
So, the question is this - is it possible to create a custom Windows locale which would treat characters in a case insensitive manner?
The farthest I could get is install a locale builder and export the en-US locale to the respective XML representation (called LDML) to see what is inside. Looking for the sort keyword returns these two lines:
<msLocale:sortName type="en-US" />
<msLocale:sortGuid type="{00000001-57EE-1E5C-00B4-D0000BB1E11E}" />
The guid can be found in the Windows Registry:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\Sorting\Ids]
#="{00000001-57EE-1E5C-00B4-D0000BB1E11E}"
"mn-Mong"="{00000001-57EE-1E5C-00B4-D0000BB1E11E}"
(There are more string values under the key)
And this does not lead anywhere. I am no closer to a case insensitive custom locale than before.
It is possible that LDML can be used to describe a case insensitive locale, but I have no idea how to construct one.
Edit
Food for thought:
SQL Server:
SELECT 'Latin1_General_CS_AS' AS 'Collation',
COLLATIONPROPERTY('Latin1_General_CS_AS', 'CodePage') AS 'CodePage',
COLLATIONPROPERTY('Latin1_General_CS_AS', 'LCID') AS 'LCID',
CONVERT(VARBINARY(8), COLLATIONPROPERTY('Latin1_General_CS_AS', 'ComparisonStyle')) AS 'ComparisonStyle',
COLLATIONPROPERTY('Latin1_General_CS_AS', 'Version') AS 'Version'
UNION ALL
SELECT 'Latin1_General_CI_AS' AS 'Collation',
COLLATIONPROPERTY('Latin1_General_CI_AS', 'CodePage') AS 'CodePage',
COLLATIONPROPERTY('Latin1_General_CI_AS', 'LCID') AS 'LCID',
CONVERT(VARBINARY(8), COLLATIONPROPERTY('Latin1_General_CI_AS', 'ComparisonStyle')) AS 'ComparisonStyle',
COLLATIONPROPERTY('Latin1_General_CI_AS', 'Version') AS 'Version'
yields
Collation CodePage LCID ComparisonStyle Version
Latin1_General_CS_AS 1252 1033 0x00030000 0
Latin1_General_CI_AS 1252 1033 0x00030001 0
Win32 API:
CompareStringEx Win32 function:
int CompareStringEx(
_In_opt_ LPCWSTR lpLocaleName,
_In_ DWORD dwCmpFlags,
_In_ LPCWSTR lpString1,
_In_ int cchCount1,
_In_ LPCWSTR lpString2,
_In_ int cchCount2,
_In_opt_ LPNLSVERSIONINFO lpVersionInformation,
_In_opt_ LPVOID lpReserved,
_In_opt_ LPARAM lParam
);
The flags for the dwCmpFlags parameter can be found in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\WinNls.h:
//
// String Flags.
//
#define NORM_IGNORECASE 0x00000001 // ignore case
#define NORM_IGNORENONSPACE 0x00000002 // ignore nonspacing chars
#define NORM_IGNORESYMBOLS 0x00000004 // ignore symbols
#define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case'
#define LINGUISTIC_IGNOREDIACRITIC 0x00000020 // linguistically appropriate 'ignore nonspace'
#define NORM_IGNOREKANATYPE 0x00010000 // ignore kanatype
#define NORM_IGNOREWIDTH 0x00020000 // ignore width
#define NORM_LINGUISTIC_CASING 0x08000000 // use linguistic rules for casing
From which I conclude that:
using Latin1_General_CS_AS results in CompareStringEx being invoked with the flags NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH
using Latin1_General_CI_AS results in CompareStringEx being invoked with the flags NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|NORM_IGNORECASE
But what is next? How can I create my own Windows locale similar to Latin1_General_CI_AS, but usable outside the SQL Server?
In Windows, there are no case insensitive sort rules. All the rules are able to sort ignoring case but that is handled by means of a flag not by a sort. There is no way to add a custom sort method.
Probably nobody did it. I am thinking so it is possible - but this scenario is not tested and nobody knows if there is some side effect.
This issue is in PostgreSQL ToDo list still and Craig Ringer sent a proposal how to implement it. http://www.postgresql.org/message-id/52C0C31C.4060804#2ndquadrant.com
P.S.
I'm reading a book called "Introduction to 3D Game Programming with DirectX 9.0c: A Shader Approach" and I was following the codes there but the application used Multi-Byte Character Set and I read from somewhere that it's not a good practice to use that and im having error when creating a window. here is the code that im having error.
mhMainWnd = CreateWindow(L"D3DWndClassName", mMainWndCaption.c_str(), WS_OVERLAPPEDWINDOW,
GetSystemMetrics(SM_CXSCREEN)/2 - width/2,
GetSystemMetrics(SM_CYSCREEN)/2 - height/2,
R.right, R.bottom, 0, 0, mhAppInst, 0);
then the eror is:
error C2664: 'CreateWindowExW' : cannot convert parameter 2 from 'const char [16]' to 'LPCWSTR'
hope someone can help me
What you heard about the preferability of Unicode over the ANSI/MBCS is entirely correct. All new Windows code should be written to work with Unicode. In order to make this happen, you have to ensure two things:
Both the UNICODE and _UNICODE symbols need to be defined globally to ensure that the Unicode versions of the API functions are called, even if you forget the W suffix.
You can either do this at the top of your precompiled header
#define UNICODE
#define _UNICODE
or in your project's Properties window within Visual Studio. Simply add both of the values to the list.
All of your strings (both literals and otherwise) need to be Unicode strings.
With literals, you accomplish this by prefixing them with L, just as you've done in the example: L"D3DWndClassName"
With strings that are allocated at runtime, you need to use the wchar_t type. Since you're using C++, you should obviously be using a string class rather than raw character arrays like you would in C. So you need to use a string class that treats the characters in the string as wchar_t. This would either be std::wstring or MFC/ATL/WTL's CStringW class.
It looks like you've got most of this down already. The culprit is mMainWndCaption.c_str(). You are using std::string (which returns a nul-terminated array of chars) instead of std::wstring (which returns a nul-terminated array of wchar_ts).
Either change your project to ANSI or MBCS rather than UNICODE, then change
L"D3DWndClassName"
to
"D3DWndClassName"
or, leave your project properties as UNICODE but use a UNICODE string of your window caption - so
CString szCaption(mMainWndCaption.c_str()); // CString is actually CStringW in UNICODE build
mhMainWnd = CreateWindow(L"D3DWndClassName", szCaption, WS_OVERLAPPEDWINDOW,
GetSystemMetrics(SM_CXSCREEN)/2 - width/2,
GetSystemMetrics(SM_CYSCREEN)/2 - height/2,
R.right, R.bottom, 0, 0, mhAppInst, 0);
Ive got a multi platform project that compiles great on mac, but on windows all my swprintf calls with a %s are looking for a wchar_t instead of the char * im passing it. Turns out M$ thought it would be funny to make %s stand for something other than char * in wide character functions... http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx
Anyways I'm looking for a creative coding trick thats better than putting ifdef else ends around every wide string call
Update: VS 2015 CTP6 reverted the changes and Microsoft are yet again acting different to the standard.
Visual Studio 14 CTP1 and later will always treat %s as a narrow string (char*) unless you define _CRT_STDIO_LEGACY_WIDE_SPECIFIERS. It also added the T length modifier extension which maps to what MS calls the "natural" width. For sprintf %Ts is char* and for swprintf %Ts is wchar_t*.
In Visual Studio 13 and earlier %s/%c is mapped to the natural width of the function/format string and %S/%C is mapped to the opposite of the natural with:
printf("%c %C %s %S\n", 'a', L'B', "cd", L"EF");
wprintf(L"%c %C %s %S\n", L'a', 'B', L"cd", "EF");
You can also force a specific width by using a length modifier: %ls, %lc, %ws and %wc always mean wchar_t and %hs and %hc are always char. (Documented for VS2003 here and VC6 here (Not sure about %ws and when it was really added))
Mapping %s to the natural width of the function was really handy back in the days of Win9x vs. WinNT, by using the tchar.h header you could build narrow and wide releases from the same source. When _UNICODE is defined the functions in tchar.h map to the wide functions and TCHAR is wchar_t, otherwise the narrow functions are used and TCHAR is char:
_tprintf(_T("%c %s\n"), _T('a'), _T("Bcd"));
There is a similar convention used by the Windows SDK header files and the few format functions that exist there (wsprintf, wvsprintf, wnsprintf and wvnsprintf) but they are controlled by UNICODE and TEXT and not _UNICODE and _T/_TEXT.
You probably have 3 choices to make a multi-platform project work on Windows if you want to support older Windows compilers:
1) Compile as a narrow string project on Windows, probably not a good idea and in your case swprintf will still treat %s as wchar_t*.
2) Use custom defines similar to how inttypes.h format strings work:
#ifdef _WIN32
#define PRIs "s"
#define WPRIs L"hs"
#else
#define PRIs "s"
#define WPRIs L"s"
#endif
printf("%" PRIs " World\n", "Hello");
wprintf(L"%" WPRIs L" World\n", "Hello");
3) Create your own custom version of swprintf and use it with Visual Studio 13 and earlier.
Use the %ls format which always means wchar_t*.
You can use "%Ts" format specifier or you can define _CRT_STDIO_LEGACY_WIDE_SPECIFIERS=1.
Read this:
http://blogs.msdn.com/b/vcblog/archive/2014/06/18/crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1.aspx