MFC SetRegistryKey opposite function? What am I missing? - c++

In my app the default Registry key is created called:
SetRegistryKey(_T("Trains"));
It places that "root" key value like so:
Computer\HKEY_CURRENT_USER\SOFTWARE\Trains
My app saves all the window info and other data in subkeys under Trains. I have a "reset" menu item that when the user activates, I would like to delete that "root" key and all the subkeys under it.
If I'm in registry editor, it is simply a right click and delete....and blamo, all gone.
I've read other threads here and on Google and there seems to be multiple ways to do this.... I've tried DelRegTree with little success and I'm unclear why this process is so cumbersome to do with multiple functions and recursion to find all the keys, delete them, then remove the root key.
https://learn.microsoft.com/en-us/cpp/mfc/reference/cwinapp-class?view=msvc-160#delregtree
I've tried DelRegTree(\\HKEY_CURRENT_USER\\SOFTWARE, _T("Trains")); but that doesn't work. How should I approach this seemingly easy task?

You can use the SHDeleteKey() function. You can use HKEY_CURRENT_USER for the first argument and specify the key path (from that) in the second:
#include <shlwapi.h>
LSTATUS status = SHDeleteKey(HKEY_CURRENT_USER, _T("SOFTWARE\\Trains"));
You will need to include "Shwlapi.lib" in your link.
(Note: Calling the DelRegTree member of CWinApp may also work, if you use the same arguments; but you can't add the \\SOFTWARE part to the first argument – that will have to be included in the key path/name.)

Related

How does "send to" manages input arguments? (Windows)

Background: I want to add my application to the windows context menu, I have done this by adding a new key to the windows registry:
HKEY_CLASSES_ROOT\*\shell\myapp
HKEY_CLASSES_ROOT\*\shell\myapp\command
And assigning the default value of the "command" key to the location of my exe, plus an extra argument:
value = "c:\users\john\myapp\myappexe.exe" "%1" arg1
It works, i can 'right click' any file and run my application with that file. The problem comes when I try to select multiple files, it opens as many windows of my app as files selected, I want to be able to handle all the inputs with one instance of my program.
I'm aware that this may be solved by creating shell extensions as posted here, here, here or here. Creating a full functional shell extension is out of the scope of my (small) project, and I haven't found tutorials which I can understand.
Problem: I'm looking a way around it, and I found that a program called from the "send to" folder in windows is able to handle multiple files, for example, if i put the execulable of this code (c++) in the C:\Users\john\AppData\Roaming\Microsoft\Windows\SendTo folder,
#include <iostream>
using namespace std;
int main(int argc, char* argv[]){
for(int i=0;i<=argc;i++){
cout << argv[i] << endl;
}
return 0;
}
...select a bunch of flies, and drag them into the executable, I'll get in one window the path of all the selected files (send to tutorial). How does this work? Can I use this behavior and apply it to my app?
One approach is to design your application so that any newly launched instance checks for a pre-existing instance (you could use a mutex to do this) and then forwards the command-line parameters to that one, encapsulated in a message of some kind. The original instance can then take the appropriate action.

C++ How do we make our application start on computer startup (and of course, after a user signed in)?

How do we make our application start on computer startup (and of course, after the user had signed in)?
And no, I am not making a virus.
Does registry editing sound like a good idea?
My OS is Windows 8.
However, I will try to make my application available for all possible Window OS.
The correct way to do this is simply to add a shortcut to your application's executable to the user's Startup folder. You do not need to (and should not) modify the registry.
Advanced users know how to do this manually already, but it may also be an option you want to provide as part of your installer and/or a configuration dialog in your application.
To do this from C++ code, you will need to do two things:
Retrieve the location of the current user's Startup folder.
This is accomplished by calling the SHGetKnownFolderPath function and specifying the KNOWNFOLDERID of the folder you're interested in. In this case, that would be FOLDERID_Startup.
Sample code:
std::wstring GetStartupFolderPath()
{
PWSTR pszPath;
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Startup,
0, // no special options required
NULL, // no access token required
&pszPath);
if (SUCCEEDED(hr))
{
// The function succeeded, so copy the returned path to a
// C++ string, free the memory allocated by the function,
// and return the path string.
std::wstring path(pszPath);
CoTaskMemFree(static_cast<LPVOID>(pszPath));
return path;
}
else
{
// The function failed, so handle the error.
// ...
// You might want to throw an exception, or just return an
// empty string here.
throw std::runtime_error("The SHGetKnownFolderPath function failed");
}
}
Note, however, that while SHGetKnownFolderPath is the recommended function to use, it is supported only by Windows Vista and later. If you need to support older versions of the operating system, you'll need to call it dynamically on newer versions where it is available, and otherwise fall back to calling the SHGetFolderPath function. This one takes a different type of identifier, a CSIDL value. The one you want is CSIDL_STARTUP.
Create a shortcut to your application's executable.
This is accomplished using a different set of Shell API functions. I won't bother writing up sample code here because it's all quite well explained on MSDN already: Shell Links
Now you just connect the dots: when you create the shortcut to your application's executable, specify the user's Startup folder as its destination path.
The only other thing to be aware of is that there are actually multiple Startup folders. Each user has one, which is the one we retrieved above using FOLDERID_Startup. About 99% of the time, that's the one you want. Putting a shortcut to your app there will cause it to be launched automatically when that user logs on.
However, there is also a global Startup folder that is shared by all users. This one is identified by FOLDERID_CommonStartup (or CSIDL_COMMON_STARTUP) and requires administrative privileges to add items to. That makes sense, of course, because whatever you put in there is going to launch automatically when any user logs on to the computer. Only administrators can affect global behavior like this. And chances are, your app doesn't need this anyway.
Start menu
Simplest solution is to place .lnk of .bat file into the Start Menu\On startup folder. This is easiest and not too sneaky against the user.
Registry:
Another solution is creating the key in the registry keys:
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run] //All users
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce] //All users once
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run] //Currend user
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce] //Current user once
This is not that transparent - so a bit more agressive against the user.
On windows you can put a shortcut to your application in the Startup folder, or you can implement it as a service.
And that "I am not making a virus" does make you sound guilty... Maybe it is a keylogger? ;)
There are a lot of ways, but they all depend on your OS. For windows take a look at the "Task Schedualer" under "Administrative tools" in the control panel.
Maybe something like this? Note, this code snippet is not written by me.
#include <windows.h>
void Reg() {
::HKEY Handle_Key = 0;
::DWORD Dispoition = 0;
::RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
0,
KEY_ALL_ACCESS,
&Handle_Key );
const unsigned char Path[ MAX_PATH ] = "C:\\Windows\\YourProgramName.exe";
::RegSetValueEx( Handle_Key, "My Directory", 0, 1, Path, sizeof( unsigned char ) );
};
What do you guys think?

XPCOM CPP code fail to find an existing key in the registry

Here is a simplified example of a code I use in my XPCOM CPP DLL to check if a key exists in the registry.
It checks for the existance of 2 keys: HKLM\SOFTWARE\Microsoft and HKLM\SOFTWARE\Microso both exist with the same permissions, but the first one is found by this code and the second one is not... any idea why?
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("#mozilla.org/windows-registry-key;1");
if (!regKey) {
log("can't create #mozilla.org/windows-registry-key;1");
return -1;
}
NS_NAMED_LITERAL_STRING(key2,
"SOFTWARE\\Microsoft");
if (NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
key2, nsIWindowsRegKey::ACCESS_QUERY_VALUE))) {
// FAILED
LOG("regKey:: no such key");
}
NS_NAMED_LITERAL_STRING(key1,
"SOFTWARE\\Microso");
if (NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
key1, nsIWindowsRegKey::ACCESS_QUERY_VALUE))) {
// FAILED
LOG("regKey:: no such key");
}
EDIT: To make it clear, I've created a registry key myself, called HKLM\SOFTWARE\Microso and I can access it through regedit.
nsIWindowsRegKey.Open is implemented via RegOpenKeyEx WinAPI function. This function requires existing relative path passed as argument and does not support templates. If there is no exactly same path in the registry, it falls. SOFTWARE\Microsoft is exists in the HKLM root space, HKLM\SOFTWARE\Microso is not.
The issue is most likely that you are viewing the registry with the x64 regedit and then expecting Firefox to have the same view. However, regedit is an x64 application whereas the usual Firefox builds are x86 and run inside the 32-bit subsystem (via WoW64). When an x86 application accesses the HKLM\Software key it gets redirected to HKLM\Software\Wow6432Node. You can run c:\Windows\SysWOW64\regedit.exe instead of c:\Windows\regedit.exe to see the view of the registry that an x86 application gets.
So your XPCOM component is actually trying to access HKLM\Software\Wow6432Node\Microsoft and HKLM\Software\Wow6432Node\Microso - and the former exists while the latter doesn't. If you want to access the "real" registry key instead, you have to pass the WOW64_64 flag in the third parameter of nsIWindowsRegKey.open() (it corresponds to the KEY_WOW64_64KEY flag that can be passed to the RegOpenKeyEx WinAPI function):
NS_NAMED_LITERAL_STRING(key1,
"SOFTWARE\\Microso");
if (NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, key1,
nsIWindowsRegKey::ACCESS_QUERY_VALUE | nsIWindowsRegKey::WOW64_64))) {
// FAILED
LOG("regKey:: no such key");
}

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.

Changing the Total Number of Recent Files

I'd like the user to be able to edit the number of recent files shown in the File menu of my MFC application. I've used two very good references:
http://www.codeproject.com/KB/menus/changemru.aspx
http://www.microsoft.com/msj/0899/c/c0899.aspx
It involves deleting and recreating the CRecentFileList object stored in CWinApp::m_pRecentFileList. Unfortunately, I find that the menu is not updated properly after replacing the CRecentFileList. See code snippet below:
void CMyWinApp::SetMRUListSize( int size )
{
// size guaranteed to be between 1 and 16
delete m_pRecentFileList ;
LoadStdProfileSettings( size ) ;
}
What can I do to ensure that what is drawn into the File menu is synchronized with m_pRecentFileList after I recreate the object?
My CApp derives from CWinApp. In initInstance, you have this line:
LoadStdProfileSettings(10);
At the end of InitInstance, add this code:
m_pmf->m_pRecentFileList = m_pRecentFileList;
Here m_pmf is my MainFrame class and I created a member CMainFrame::m_pRecentFileList of type CRecentFileList which is in the MFC source file filelist.cpp. m_pRecentFileList on the right is protected and CMainFrame doesn't have access to it from outside InitInstance, but you can make a functional copy here.
At the end of CMainFrame::OnClose, force a registry update by:
m_pRecentFileList->WriteList();
// Force registry update on exit. This doesn't work without forcing.
I don't even have to rebuild m_pRecentFileList, the MRU mechanism updates it correctly. Example: 5 MRU items, the first is moved to another directory and can no longer be found. Stepping through the code in the debugger shows that the bad entry is removed from the list. For some reason, the updated list isn't saved correctly unless I force it as explained above. I originally thought the problem might have something to do with privileges (64-bit Win7), but running the app as admin didn't help.
Some of Microsoft's documentation suggest you should call CWinApp::LoadStdProfileSettings from within InitInstance. This suggests to me that it's something done once during initialisation rather than at run time.
Have you tried fully implementing the second of the two links you provided? My guess is you need to add the second part instead of the call to CWinApp::LoadStdProfileSettings:
m_pRecentFileList = new CRecentFileList(0, strSection, strEntryFormat, nCount);
if(m_pRecentFileList)
{
bReturn = TRUE;
// Reload list of MRU files from registry
m_pRecentFileList->ReadList();
}
[Edit] Apparently m_pRecentFileList points to an CRecentFileList Class . Have you tried calling CRecentFileList::UpdateMenu?
There's another CodeProject example which might help too.