I have a program I am making in C++ WinAPI & I need to determine the version of Windows the user is running & the path to Program Files.
I know I can determine this by looking at the Windows Environment Variables or the Registry Keys(can I get the path to program files from the Registry?) BUT which is better practice?
I know Environment Variables can be changed easily so its not good to trust them, but can the registry keys be changed as easily - which is better to trust?
Is it better practice to go to the Registry for this information or the Environment Variables? Which would you do?
You should use the GetVersionEx Function API instead. It's better than the environment variable and the registry.
For the path to program files, there is also an API: SHGetFolderPath Function
Related
I need to set a local environment variable for current user and it shoukd be visible to other processes like a new command prompt. I need it for windows. I have tried options like putenv and editing the registry from C++ code but the new cmd prompt see the old values. Primarily i need to edit PATH variable along with few custom env variables. Will appreciate if i can get a working sample code.
Please note that the environment variable need to persist past program execution.
My requirement is for windows. I even tried running setx from C++ code and it works fine but for PATH variable it trims it down to 1024 character and i lose the update. Is there a workaround to this?
IF my wording looks confusing about the requirement. I need exactly same behavior as if i am using setx.
Thanks in advance.
If you start Cmd.exe from your process you can control its environment. The environment variables are inherited from the parent process. They can also be overridden when you call CreateProcess.
If you change the users/system environment configuration in the registry(HKCU\Environment/HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) and log off/reboot then the first process will use these new defaults.
If you update the registry you can tell other applications to refresh their environments without logging off by broadcasting a message:
BroadcastSystemMessage(0, 0, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("Environment"));
In reality it is only Explorer.exe that reacts to this message but that is enough to affect new applications started from the taskbar/start menu.
The setx command is actually an executable that sets values in the registry. If you are looking to simulate the behavior where you can set an environment variable that will last longer than the current process you will need to write it to the HKCU\Environment key. The HKCU is for the the current user and can be written to without elevated permissions.
Use RegEdit.exe or reg.exe query HKCU\Environment to view the current settings. From C/C++ you can use the Registry functions. If you can, I recommend using the ATL CRegKey class as it follows RAII and ensures handles are properly cleaned up.
What is the difference between a Registry Key & an Environment Variable?
I think Environment Variables are only something found in windows OS? And I hear thats its very easy to change these so its not good to trust them? Are Registry Keys just as easy to change?
Are Registry keys stored in the kernal?
My most important question is: I know that the environment variables let me know the path to %APPDATA, the current users name, the path to program files, the version of Windows OS running, etc. BUT do the Registry keys also contain this kind of data - can I also find out this information by looking at the registry keys?
Both are used to configure programs. The biggest difference is that environment variables are stored in memory, registry keys are stored in a file. Which explains many of their properties:
Environment variable values are lost as soon as the process that writes them terminates.
A process cannot update the environment variable values of another process. With one important exception: the environment for a process is created by the process that starts it. The lpEnvironment argument of CreateProcess(). This is how a parent process configures the child processes it starts.
The space for storing environment variables is severely limited, 64KB max.
Environment variables do not have user scope like registry keys do, they'll have the same value for any user, unless the parent process takes care of it explicitly.
Environment variable values cannot be secured.
Accessing environment variables is fast. With the caveat that searching for a variable is an O(n) operation since they don't have a hierarchical organization nor an index. The limited environment size makes that unnecessary. Windows heavily optimizes registry key access however.
Another important difference:
Environment variables are loaded to the process when it starts. So if you change them after the process is running, the process won't see that.
And about your other question:
User Variables: HKEY_CURRENT_USER\Environment
System Variables: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
An article about the default system variables:
http://vlaurie.com/computers2/Articles/environment.htm
What is the difference between a Registry Key & an Environment
Variable?
Registry Keys are stored permanently in special file. Environment Variables are stored in memory of the process, but some of them (System Environment Variables) are loaded from registry on process start.
I known such tools
http://portableapps.com/development/projects/registry_rapper
RegRap.exe can get through param other .exe file and catch requests to registry and save it into .ini
That is good, but I need snippt code to set such hundler inside my C++ program and for given Reg KEY return my value...
RegRap.exe written with NSIS scripts that is why is not helpful for me :(
But may be somebody known other project only with c++?
Thx, and sorry for my bad english.
If you want to track registry access within YOUR program, you can #define away the registry API functions, provide your hooks instead, and track it in your hooks.
//in your stdafx.h, or some other universally included file
#define RegCreateKeyEx MyRegCreateKeyEx
//somewhere else
#undef RegCreateKeyEx
LONG WINAPI MyRegCreateKeyEx(stuff...)
{
//Track
//Call the real RegCreateKeyEx
}
That's probably the easiest way of hooking an API. Will not work if you want to track registry usage by your program but outside of your code (i. e. in libraries or DLLs). Then more advanced techniques are in order.
Also, consider Process Monitor by Mark Russinovich: http://technet.microsoft.com/en-us/sysinternals/bb896645
It's not a programmatic hook, but an awesome tool all around, and therefore worth plugging. It monitors registry access by your process(es) and then some.
This post seems to say that there are no hooks for the registry and you can only long poll. Simple way to hook registry access for specific process
If you want to use pure C++, check out the libraries EasyHook and Detours. Both are intended for this sort of function-level hooking. EasyHook works in C++ and C#, 32 and 64-bit, while Detours is somewhat outdated and only for 32-bit C++ (even running it on a 64-bit OS can crash your program).
You need to install the hook within the target process, either by loading your code as a DLL or creating the process (suspended), installing the hooks and then running it.
In EasyHook that goes something like:
LhInstallHook(&RegCreateKeyEx, &MyRegCreateKeyEx, &hookstruct);
You can also hook functions your library is not linked to using the Windows API to get the address.
I have a C++ library, which is used in both Linux and Windows.
I want to enable the user to control the debug level (0 - no debug, 1 - only critical errors ... 5 - informative debug information).
The debug log is printed to a text file.
In Windows, I can do it using a registry value (DWORD DebugLevel).
What can be a good replacement which works also for Linux?
(Without 3rd party tools, for example Linux "registry").
Thanks in advance!
Does your library have some sort of initialisation function? Make the level a parameter to that function. Ideally store the passed-in value in a context structure or class if it makes sense for your API (i.e. if you require clients to always operate via a "context") - but if not, a global might be reasonable.
If it's largely for development purposes (ie the "user" you refer to is a developer using your library, not the end user of that code), the quickest/easiest way is to use an environment variable.
If it's to be controlled by the end-user, you probably need to extend your API so that the app developer can set the debug level in code, after reading his configuration files -- you wouldn't normally have a separate config file for just one library used by a program.
You can use the log4cxx framework. This is configurable through a file. I haven't tried it yet, but it should work with Windows too.
You could use a configuration file in /etc/YOURAPP or ~/.YOURAPP or ~/.config/YOURAPP
Is there a way to set the global windows path environment variable programmatically (C++)?
As far as I can see, putenv sets it only for the current application.
Changing directly in the registry (HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) is also an option though I would prefer API methods if there are?
MSDN Says:
Calling SetEnvironmentVariable has no
effect on the system environment
variables. To programmatically add or
modify system environment variables,
add them to the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
Manager\Environment registry key, then
broadcast a WM_SETTINGCHANGE message
with lParam set to the string
"Environment". This allows
applications, such as the shell, to
pick up your updates. Note that the
values of the environment variables
listed in this key are limited to 1024
characters.
As was pointed out earlier, to change the PATH at the machine level just change this registry entry:
HLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
But you can also set the PATH at the user level by changing this registry entry:
HKEY_CURRENT_USER\Environment\Path
And you can also set the PATH at the application level by adding the application\Path details to this registry entry:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
There is no API - changing the registry is the way to do it. The changed value will be used for processes starting after the change was made.
Also: Notice that running applications must actively process the settings changed message and many (most?) do not do so.
If you want to do it through the registry, you might want to look at the source code of this program.
Microsoft also provides a small command line utility called setx with its resource toolkits, which will let you do this. By the way, the regular set command just lets you define local environment variables I think.
Yes You are correct.
You also need to effect these settings without logging off
Send Message of borad casting to all windows SETTINGCHANGE for the parameter (LPARAM) "Environment" with SMTO_ABORTIFHUNG for some milliseconds(5000) using SendMessageTimeout API.
This is what setX.exe provided with resource Kit does.