How to get localized names for Windows default folders in Qt - c++

Using Qt, I can get some default path where I can create files via e. g. QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) which works fine on both Linux and Windows. I also saw that one can get a localized name for the respective location via QStandardPaths::displayName.
The "problem" is that, on Windows, the names of some default folders are displayed localized. For the above command, I get – according to the documentation – C:/Users/some_user/Documents. This is probably the actual path on the disk. But what the user (with a German locale) sees is a translated version: C:/Benutzer/some_user/Eigene Dokumente in this case.
So, not only the last folder is translated (the string I could get via the QStandardPaths::displayName call), but also the base directory.
Is there a reliable standard Qt way to be able to display the directory names the user knows from his other Windows programs?

It's not exactly what you are looking for but I think that can give an idea. You can get a default path by accessing to the Windows Environment Variables:
In C++ is really, we have a native function for that purpose:
inline auto get_environement_variable(const char* key ) {
char * val = getenv(key);
return (val == NULL) ? "" : std::string(val);
}
Some of the default environment variables:
auto programFiles = get_environement_variable("%ProgramW6432%");
auto programFilesX86 = get_environement_variable("%ProgramFiles(x86)%");
auto userProfile = get_environement_variable("%USERPROFILE%");
Maybe I'm wrong but I think that this is the one for the documents folder:
auto userProfile = get_environement_variable("%USERPROFILE%\Documents");
My OS is in English so I cannot confirm that the returned string is the translated one.

Related

How to use Windows environment variables in Qt5

I'm working on a project, where I wanted to access a sound file from C:/Windows/media, but to keep it more general, I want to use some environment variable from the user's system.
This code works At the moment
soundURL = QUrl::fromUserInput(soundFilename,
QStringLiteral("C:/Windows/media"),
QUrl::AssumeLocalFile);
I have tried the below code, doesn't work
soundURL = QUrl::fromUserInput(soundFilename,
QStringLiteral((%%WINDIR%%)+"/media"),
QUrl::AssumeLocalFile);
How can I make use of %WINDIR% to make the path simpler and more general?
Qt5 exposes several functions to retrieve the value stored in an environment variable, namely qgetenv and qEnvironmentVariable.
As you seem to target Windows, the safer is to use QString qEnvironmentVariable(const char *varName)
QString winDirPath = qEnvironmentVariable("WINDIR");
if (!winDirPath.isNull()) {
// the environment variable WINDIR exists and has been retrieved
} else {
// the environment variable does not exists in this system
}
string path(getenv("WINDIR"));
will put %WINDIR% in a std::string. I would expect you can do the same with Qt types.
You're probably better off using Qt Standard Paths http://doc.qt.io/qt-5/qstandardpaths.html. Messing with %WINDIR% is a bit dangerous.

VSIX how to get current snapshot document name?

I have been trying to to create an extension that highlights specific line numbers for me in Visual Studio in the margins.
I manged to get my marking in the margins using predefined line number but for it to work properly I need to know what the current document FullName is (Path and filename)
After much googling I figured out how to do it with the sample code (which is not ideal)
DTE2 dte = (DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.15.0");
var activeDocument = dte.ActiveDocument;
var docName = activeDocument.Name;
var docFullName = activeDocument.FullName;
Now I know the problems here
is that is for specific version bases on the text
there is no way to select which instance (when running more than one VS)
It seems to be very slow
I have a feeling I should be doing this with MEF Attributes but the MS docs examples are so simple that they do not work for me. I scanned a few SO questions too and I just cannot get them to work. They mostly talk about Services.. which I do not have and have no idea how to get.
The rest of my code uses SnapshotSpans as in the example Extension of Todo_Classification examples which is great if you do NOT need to know the file name.
I have never done any extensions development. Please can somebody help me do this correctly.
You can use following code to get a file from a snapshot without any dependencies.
public string GetDocumentPath(Microsoft.VisualStudio.Text.ITextSnapshot ts)
{
Microsoft.VisualStudio.Text.ITextDocument textDoc;
bool rc = ts.TextBuffer.Properties.TryGetProperty(
typeof(Microsoft.VisualStudio.Text.ITextDocument), out textDoc);
if (rc && textDoc != null)
return textDoc.FilePath;
return null;
}
If you don't mind adding Microsoft.CodeAnalysis.EditorFeatures.Text to your project it will provide you with an extension method Document GetOpenDocumentInCurrentContextWithChanges() on the Microsoft.VisualStudio.Text.Snapshot class. (Plus many other Rosyln based helpers)
using Microsoft.CodeAnalysis.Text;
Document doc = span.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

How to Remove Hex Digits Prepended to a Windows Process Name

I have created a 64-bit executable using Visual Studio 2015, intended to be run on Windows 7. The executable is a C++ wrapper that calls the main method in a Java application via JNI. The application runs as expected, but in Windows Task Manager, on the "Process" tab, my application name has been prepended with 16 hex digits. So even though my application compiles to "someapp.exe", it is listed as "80005b29594d4a91someapp.exe" in the process list when I run it. Does anyone know why this is happening, and how to make it show up as just "someapp.exe" in the Task Manager?
EDIT 1:
I should note that the hex string is always the same when it appears in the name. However, there is a small percentage of the time I run my application when it actually has the expected name of "someapp.exe". I have not been able to figure out the pattern of when the hex string is prepended and when it is not, but I estimate the hex string appears 98% of the time it is executed.
EDIT 2:
This appears to be related somehow to the use of JNI. When I remove the JNI calls, this stops occuring altogether. The following represents the entirety of the C++ code making up the "someapp" application:
#include <jni.h>
#include <Windows.h>
#define STRING_CLASS "java/lang/String"
int main(size_t const argc, char const *const argv[]) {
// Modify the DLL search path
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32 |
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
SetDllDirectoryA(R"(C:\Program Files\Java\jdk1.8.0_112\jre\bin\server)");
// Create and populate the JVM input arguments
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_8;
vm_args.ignoreUnrecognized = JNI_FALSE;
vm_args.nOptions = 2;
vm_args.options = new JavaVMOption[vm_args.nOptions];
// Set command-line options
vm_args.options[0].optionString = "-Dfile.encoding=UTF-8";
vm_args.options[1].optionString = "-Djava.class.path=someapp.jar";
// Create the JVM instance
JavaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &vm_args);
// Get the main entry point of the Java application
jclass mainClass = env->FindClass("myNamespace/MainClass");
jmethodID mainMethod = env->GetStaticMethodID(
mainClass, "main", "([L" STRING_CLASS ";)V");
// Create the arguments passed to the JVM
jclass stringClass = env->FindClass(STRING_CLASS);
jobjectArray mainArgs = env->NewObjectArray(
static_cast<jsize>(argc - 1), stringClass, NULL);
for (size_t i(1); i < argc; ++i) {
env->SetObjectArrayElement(mainArgs,
static_cast<jsize>(i - 1), env->NewStringUTF(argv[i]));
}
env->CallStaticVoidMethod(mainClass, mainMethod, mainArgs);
// Free the JVM, and return
jvm->DestroyJavaVM();
delete[] vm_args.options;
return 0;
}
I have tried to remove the arguments passed to the Java main method, but that had no affect on the outcome.
EDIT 3:
Thanks to the suggestion from 1201ProgramAlarm, I realized that this was actually related to running from a dynamic ClearCase view. The "Image Path Name" column in the Task Manager was one of the following values, which directly correlates with the incorrect "Image Name" symptom that I was observing:
\view\view-name\someapp-path\someapp.exe
\view-server\views\domain\username\view-name.vws.s\00035\8‌​0005b29594d4a91somea‌​pp.exe
I would still like to know why this is happening, but since this only affects our development environment, fixing it has become low priority. For anyone else experiencing this problem, the following represents the relevant software installed in my environment:
Windows 7 Enterprise x64 SP1
Rational ClearCase Explorer 7.1.2.8
Visual Studio 2015 Update 3
Java x64 JDK 8u112
Run your application from a drive that isn't a ClearCase dynamic view.
The Image Name of the running process reference a file in a ClearCase view Storage (\\view\view-name\someapp-path\someapp.exe =>
\\view-server\views\domain\username\view-name.vws\.s\00035\8‌​0005b29594d4a91somea‌​pp.exe), the .vws meaning view storage.
See "About dynamic view storage directories":
Every view has a view storage directory. For dynamic views, this directory is used to keep track of which versions are checked out to your view and to store view-private objects
So a view storage exists both for snapshot and dynamic view.
But for dynamic view, that storage is also used to keep a local copy of the file you want to read/execute (all the other visible files are accessed through the network with MVFS: MultiVersion File System)
That is why you see \\view-server\views\domain\username\view-name.vws\.s\00035\8‌​0005b29594d4a91somea‌​pp.exe when you execute that file: you see the local copy done through MVFS by ClearCase.
Would you have used a snapshot view, you would not have seen such a complex path, since a snapshot view by its very nature does copy all files locally.
It appears as though the path is "correct" when I have not accessed the MVFS mount recently using Windows Explorer
That means the executable executed by Windows is still the correct one, while MVFS will be busy downloading that same executable from the Vob onto the inner folder of the view storage.
But once you re-execute it, that executable is already there (in the view storage), so MVFS will communicate its full path (again, in the view storage) to Windows (as seen in the Process Explorer)

Loading Image from Content to StorageFile^ in Metro C++

I am trying Share an Image in Windows 8 Metro C++ Application using Share Charm. To do so, I need to load image to StorageFile^ first. I assume it should looks like:
create_task(imageFile->GetFileFromPathAsync("Textures/title.png")).then([this](StorageFile^ storageFile)
{
imageFile = storageFile;
});
where imageFile is defined in header file
Windows::Storage::StorageFile^ imageFile;
This actual code would throw this exeption
An invalid parameter was passed to a function that considers invalid parameters fatal.
This seems to be very trivial, but there is a very little documentation about Sharing in Metro, and the only Microsoft example shows how to do sharing using FilePicker.
Would be very grateful if someone knows how to do it properly.
If "Textures" is coming from your application package, you should use StorageFile::GetFileFromApplicationUriAsync instead:
Uri^ uri = ref new Uri("ms-appx:///Assets/Logo.png");
create_task(StorageFile::GetFileFromApplicationUriAsync(uri)).then([](task<StorageFile^> t)
{
auto storageFile = t.get();
auto f = storageFile->FileType;
});
You can also use a task-based continuation (as I show above) in order to inspect the exception information more closely. In your case, the inner exception is: The specified path (Assets/Logo.png) contains one or more invalid characters.
This is due to the forward-slash, if you change it to a backslash you'll see: The specified path (Assets\Logo.png) is not an absolute path, and relative paths are not permitted.
If you want to use GetFileFromPathAsync I would recommend using
Windows::ApplicationModel::Package::Current->InstalledLocation
To figure out where your application is installed and building up your path from there.

Create registry entry to associate file extension with application in C++

I would like to know the cleanest way of registering a file extension with my C++ application so that when a data file associated with my program is double clicked, the application is opened and the filename is passed as a parameter to the application.
Currently, I do this through my wix installer, but there are some instances where the application will not be installed on ths user's computer, so I also need the option of creating the registry key through the application.
Additionally, will this also mean that if the application is removed, unused entries in the registry will be left lying around?
Your basic overview of the process is found in this MSDN article. The key parts are at the bottom of the list:
Register the ProgID
A ProgID (essentially, the file type registry key) is what contains your important file type properties, such as icon, description, and context menu items including applications used when the file is double clicked. Many extensions may have the same file type. That mapping is done in the next step:
Register the file name extension for the file type
Here, you set a registry value for your extension, setting that extension's file type to the ProgID you created in the previous step.
The minimum amount of work required to get a file to open with your application is setting/creating two registry keys. In this example .reg file, I create a file type (blergcorp.blergapp.v1) and associate a file extension (.blerg) with it.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command]
#="c:\path\to\app.exe \"%1\""
[HKEY_CURRENT_USER\Software\Classes\.blerg]
#="blergcorp.blergapp.v1"
Now, you probably want to accomplish this programmatically. To be absolutely kosher, you could check for the existence of these keys, and change your program behavior accordingly, especially if you're assuming control of some common file extension. However, the goal can be accomplished by setting those two keys using the SetValue function.
I'm not positive of the exact C++ syntax, but in C# the syntax looks something like this:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command", null, #"c:\path\to\app.exe \"%1\"");
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\.blerg", null, "blergcorp.blergapp.v1");
Of course you could manually open each sub key, manually create the ProgID and extension subkey, and then set the key value, but a nice thing about the SetValue function is that if the keys or values don't exist, they will automatically be created. Very handy.
Now, a quick word about which hive to use. Many file association examples online, including ones on MSDN, show these keys being set in HKEY_CLASSES_ROOT. I don't recommend doing this. That hive is a merged, virtual view of HKEY_LOCAL_MACHINE\Software\Classes (the system defaults) and HKEY_CURRENT_USER\Software\Classes (the per-user settings), and writes to any subkey in the hive are redirected to the same key in HKEY_LOCAL_MACHINE\Software\Classes. Now, there's no direct problem doing this, but you may run into this issue: If you write to HKCR (redirected to HKLM), and the user has specified the same keys with different values in HKCU, the HKCU values will take precedence. Therefore, your writes will succeed but you won't see any change, because HKEY_CURRENT_USER settings take precedence over HKEY_LOCAL_MACHINE settings.
Therefore, you should take this into consideration when designing your application. Now, on the flip side, you can write to only HKEY_CURRENT_USER, as my examples here show. However, that file association setting will only be loaded for the current user, and if your application has been installed for all users, your application won't launch when that other user opens the file in Windows.
That should be a decent primer for what you want to do. For further reading I suggest
Best Practices for File Association
File Types and File Association, especially
How File Associations Work
And see also my similar answer to a similar question:
Associating file extensions with a program
This is a two step process:
1. Define a program that would take care of extension: (unless you want to use existing one)
1.1 create a key in "HKCU\\Software\\Classes\\" for example
"Software\\Classes\\YourProgramName.file.ext"
1.2 create subkey "Software\\Classes\\YourProgramName.file.ext\\DefaultIcon"
1.2.1 set default value ("") to your application full path to get
icon from resources
1.3 create a subkey "Software\\Classes\\YourProgramName.file.ext\\Shell\\OperationName\\Command"
OperationName = for example Open, Print or Other
1.3.1 set default value ("") to your application full path +optional runtime params (filename)
2.Associate file extension with program.
2.1 create a key HKCU\\Software\\Classes\\.ext - here goes your extension
2.2 set default value to the program definition key
("YourProgramName.file.ext")
Below is part of the program written in c# which associate file extension. It is not c++ but i think it is simple enought to explain itself and AFAIK it is verv simmilar if not identical to the code in c++
1.
RegistryKey keyPFCTExt0 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc", true);
if (keyPFCTExt0 == null)
{
keyPFCTExt0 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc");
keyPFCTExt0.CreateSubKey("DefaultIcon");
RegistryKey keyPFCTExt0ext = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\DefaultIcon", true);
keyPFCTExt0ext.SetValue("", Application.ExecutablePath +",0");
keyPFCTExt0ext.Close();
keyPFCTExt0.CreateSubKey("Shell\\PFCT_Decrypt\\Command");
}
keyPFCTExt0.SetValue("", "PFCT.file.enc");
keyPFCTExt0.Close();
2.
RegistryKey keyPFCTExt1 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command", true);
if (keyPFCTExt1 == null)
keyPFCTExt1 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command");
keyPFCTExt1.SetValue("", Application.ExecutablePath + " !d %1"); //!d %1 are optional params, here !d string and full file path
keyPFCTExt1.Close();
I don't know why people keep saying that HKEY_CURRENT_USER\Software\Classes\<.ext>'s Default value (which will redirect you into another (software-created) class.
It does work, but it will be overridden by
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\<.ext>\UserChoice
And I believe Microsoft recommends the second practice- because it's what the built-in "open with" is doing. The value of Progid" key is equal to default value of HKEY_CURRENT_USER\Software\Classes\<.ext> in this case.
I found the following while trying to manipulate associations using C#:
hkcu\software\microsoft\windows\currentVersion\explorer\fileexts.reg\userchoice -> for user specific settings. The values in the openWithProgIds
key point to the keys in the hkcr.
hkcr\xfile\shell\open\muiVerb value or hkcr\xfile\shell\open\command\default value -> affects open handler. This is the value that contains the path to a program.
hkcr\ .x -> affects context menu (new x) among other things related to the menus.
I don't know the C++ code, but given these info you must be able to manipulate the registry using the registry API.