I want to restart my application on restart of the system - c++

I use GetModuleFileName to get the absolute path to my application, open the RunOnce registry key using RegOpenKeyEx and set a value using RegSetValueEx.
if (RegOpenKeyEx (HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",0, KEY_SET_VALUE, &hk1) == ERROR_SUCCESS)
{
RegSetValueEx(hk1, // subkey handle
"", // value name
0, // must be zero
REG_SZ, // value type
(LPBYTE) &path, sizeof(DWORD)); // length of value data
RegCloseKey(hk1);
}
However my application does not start after a system restart.

There are a few methods:
Place your application in your start-up folder. This is a very easy method. When your system (PC) will be restarted, the application will get started (You need to login for this);
Use windows task planner;
Make the application an service.
I prefer the last option if it always needs to run. But you will need to add service handling.

You can create a task using Task Scheduler to run your application when the computer starts.
Open Task Scheduler by clicking the Start button , clicking Control Panel, clicking System and Security, clicking Administrative Tools, and then double-clicking Task Scheduler.‌ If you're prompted for an administrator password or confirmation, type the password or provide confirmation.
Click the Action menu, and then click Create Basic Task.
Type a name for the task and an optional description, and then click Next.
Click When the computer starts, and then click Next.
To schedule a program to start automatically, click Start a program, and then click Next.
Click Browse to find the program you want to start, and then click Next.
Select the Open the Properties dialog for this task when I click Finish check box and click Finish.
In the Properties dialog box, select Run whether user is logged on or not, and then click OK
Source:
Windows 7 - Schedule a task
PS: You must be logged on as an administrator to perform these steps

There are a number of things to keep in mind when using the solution you opted for:
The application does not start when the system starts but rather when the current user logs on.
If you write to the RunOnce key the operation will be performed only once. If you want your application to always start when the user logs on you should instead use the Run key.
In addition to the above, if you want to create a value you will have to give it a name. From the documentation of the lpValueName parameter for RegSetValueEx:
If lpValueName is NULL or an empty string, "", the function sets the type and data for the key's unnamed or default value.
The default (unnamed) value is the one that shows up as (Default) when using regedit. To get this to work you will have to provide a name for the value. This should be unique so that it does not conflict with other values under that key.
On a less technical note, implementing an auto-start feature for an application should only be done after thorough consideration.

You are passing the wrong parameter values to RegSetValueEx(). You need to use it like this instead:
TCHAR path[MAX_PATH+1] = {0}
GetModuleFileName(NULL, path, MAX_PATH);
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"), 0, KEY_SET_VALUE, &hk1) == ERROR_SUCCESS)
{
RegSetValueEx(hk1, // subkey handle
TEXT("MyApp"), // value name
0, // must be zero
REG_SZ, // value type
(LPBYTE) path,
(lstrlen(path)+1) * sizeof(TCHAR)); // length of value data, in bytes
RegCloseKey(hk1);
}

Related

Setting global environment variables programmatically

I need to set an environment variable programmatically.
Microsoft provides documentation for that here. You just need to create a new value in the registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment. This part works fine.
The problem is that these changes only come into effect after logging out and logging in again.
To circument this they propose to execute this little piece of code:
if (!SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM) "Environment", SMTO_ABORTIFHUNG,
5000, &dwReturnValue))
{
... take action in case of failure
}
I did exactly this, SendMessageTimeout returns TRUE, but at least under Windows 10 it has no effect. A newly opened command prompt window still won't show the newly created variable.
I also tried to run this piece of code in an elevated process, but the result is still the same.
But when I use system applet for changing environment variables, my newly created variable shows up and when I click OK on the applet and when I open another command prompt, then the variable is there.
Any thoughts?
The problem was solved by calling explicitly the wide version of SendMessageTimeout and sending the "Environment" as wide string:
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
As Michael found out, the string width needs to match the A/W function type. WM_SETTINGCHANGE is in the < WM_USER range and will be marshaled by the window manager.
You can use the TEXT macro to create code that works for everyone everywhere if you don't want to hardcode the function name suffix:
SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) TEXT("Environment"),
SMTO_ABORTIFHUNG,
5000,
&dwReturnValue
);

Issues with CFileDialog for multiple file selection

I'm using the following code to retrieve multiple file selection via UI:
CFileDialog fd(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
NULL, hParentWnd ? CWnd::FromHandle(hParentWnd) : NULL);
fd.m_pOFN->Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_NODEREFERENCELINKS;
int nLnBuff = 32767;
TCHAR* pBuffFileSelect = new TCHAR[nLnBuff];
memset(pBuffFileSelect, 0, nLnBuff * sizeof(TCHAR));
fd.m_ofn.lpstrFile = pBuffFileSelect;
fd.m_ofn.nMaxFile = nLnBuff;
if(fd.DoModal() == IDOK)
{
POSITION fileNamesPosition = fd.GetStartPosition();
while(fileNamesPosition != NULL)
{
CString strSelPath = fd.GetNextPathName(fileNamesPosition);
TRACE("path: %s\n", CStringA(strSelPath));
}
}
delete[] pBuffFileSelect;
So when I try it on my PC, I run the method above and when the "Open File" dialog open up, just as a test, I navigated to my desktop and selected all files using Ctrl+A shortcut and then clicked Open. As a result I started getting the following paths:
The first path is a link, which is correct (it exists on my Public desktop):
"C:\Users\Public\Desktop\avp.lnk"
But then the second path is wrong. It gives me:
"C:\Users\Public\Desktop\1.txt"
when it's supposed to be (for the desktop that I picked):
"C:\Users\UserName\Desktop\1.txt"
and then every consecutive path has "Public" instead of "UserName".
I should point out that I have several user accounts set up on this PC and the one that I'm testing this method from is a Standard user account. The app that I'm running this method from is not running elevated (or with regular user privileges) so it should not have access to other user accounts anyway.
So what am I doing wrong here?
Checked the sources, and GetOpenFileName assumes that all the items are in fact in the same file path. This isn't true for the Desktop (there are items in different paths merged into one shell view), and so you'll see the bad behavior.
The solution is to use the Common Item dialogs, which use the shell namespace rather than file system paths. All the desktop items are in a common shell path, and then you can use IShellItem::GetDisplayName to convert to a file system path.
Unfortunately, MFC doesn't have a wrapper for the common item dialog, so you'll have to manage that yourself.

Open URL with ShellExecute - SW_SHOWMAXIMIZED dont active window in C++

I used this function to open new tab in Chrome and active it:
ShellExecuteA(0,0,"chrome.exe","http://google.com --incognito",0,SW_SHOWMAXIMIZED);
but Chrome only open new tab but it doesnt active window.
(I call this function from global keyboard-hook of an application with no user interface, if user press specified key).
How I can fix it?
Looks like a bug in chrome.exe. I could repro with your ShellExecute call from a simple console app, if a regular (non-incognito) chrome.exe session was running and no incognito session was running. In other words, if a new incognito chrome session needed to be spawned, the regular session did not appear to correctly propagate the ShowWindow flags to the spawned incognito process. Another factor was that the activation failure also required the regular chrome session to be active before the test app ran. If any other app was active (say notepad.exe), then activation of the incognito session succeeded. The same behavior occurs with ShellExecuteEx and CreateProcess. Observing in Process Explorer (from sysinternals), it's clear that chrome.exe is forking the child process as necessary and then terminating itself. This makes it difficult to intercept an hProcess or processId in order to ultimately call SetActiveWindow.
Its not possible. You have to make Google Chrome as default browser and than try this:
(only tested on WinXP using
IE6)
first a function, that finds the default app for any File extension:**
enter code here
#include<Registry.hpp>
AnsiString GetDefaultApp(AnsiString ext)
{
TRegistry* reg = new(TRegistry);
reg->RootKey = HKEY_CURRENT_USER;
if(!reg->OpenKeyReadOnly("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\."+ext+"\\OpenWithList"))
return(NULL);
try
{
AnsiString MRUList = reg->ReadString("MRUList");
AnsiString ret = reg->ReadString(AnsiString(char(MRUList[1])));
return(ret);
}
catch(...)
{
return(NULL);
}
}
now the code to launch the default app for html files and giving
the URL as parameter:**
#include<shellapi>
void OpenURL(AnsiString URL)
{
AnsiString app = GetDefaultApp("html");
if(app == NULL)
return;
ShellExecute(NULL,"open",app.c_str(),URL.c_str(),NULL,SW_SHOWDEFAULT);
}
Now you can open a URL in a new Browser using this command:
OpenURL("http://www.AlgorithMan.de/");

GetWindowThreadProcessId can not find my window handle, even though its process ID exists on Window

I have a setup application that if user clicks the same setup twice, they would get the pop up message "Another setup instance already running". Upon clicking OK on that message I want to put focus back on the existing installation window which has been running. I currently have the following codes:
if("setup.exe" == CString(buffer))
EnumWindows(EnumWindowsProc,(LPARAM)processID);
BOOL CALLBACK EnumWindowsProc(HWND windowHandle,LPARAM lParam)
{
DWORD searchedProcessId = (DWORD)lParam;
DWORD windowProcessId = 0;
GetWindowThreadProcessId(windowHandle,&windowProcessId);
if(searchedProcessId == windowProcessId)
{
//Set focus when detects the right window.
SetForegroundWindow(windowHandle);
return FALSE;
}
return TRUE;
}
The above code works if I stay on the first screen/step on the installation wizard (install shield).
When I move to the next screen on the installation wizard, this focus logic no longer works. Upon debugging I found that the function GetWindowThreadProcessId could not find any windowProcessID that match searchedProcessId. I also confirmed the following:
the searchProcessId value remains the same whether I am on the 1st or 2nd installation screen.
I confirmed I see the searchProcessID value exists when I view in in the window task manager.
I read up on GetWindowThreadProcessId and see the following note: "The return value is the identifier of the thread that created the window." In my own interpretation, was this because the 2nd step/screen on the wizard is generated by its own thread?
I tried to play around with EnumChildWindow() function but that did not help. I'd be very appricated if anyone able to point me in the right direction of trying to get this to work?
I would use Spy++ which comes with Visual Studio or a similar system monitoring tool to show you all the windows/threads so you can try to confirm exactly what the install wizard is doing. Chances are EnumWindows() is working just fine and it is a problem with your code or your assumptions of how things work.

How might I obtain the IContextMenu that is displayed in an IShellView context menu?

Building a file open dialog replacement. Much of it works now, but I would like to generate the view-mode drop-down for the toolbar directly from the shell view object.
Looking at IShellView2, I can see IShellView2::GetView() will give me the FOLDERVIEWMODE's supported. However, that doesn't give me the names of these modes, nor format that popup menu for me, nor immediately give me a way to actually set one of those modes (it would appear it is necessary to destroy the shell view window and create a replacement one for the current folder and specify the new FOLDERVIEWMODE desired... yeesh).
At any rate, if one right clicks on an IShellView window, one gets a context menu, the first submenu of which is exactly what I want to place in my drop-down toolbar button (ie. the "view" fly-out menu (e.g. Small Icons, Medium Icons, etc.)).
It seems like there ought to be a way to grab that submenu directly from the IShellView, rather than having to hardcode my values (and that way, if a given instance of IShellView supports extra view modes, they'd be there. Similarly, those which should be disabled would be, since it would all be under the IShellView's control).
I have read Raymond Chen's excellent How to host an IContextMenu. Unfortunately, that just gives me a very simplistic context menu - the one for the folder itself, or for a file in a given folder, but NOT the context menu for the IShellView's shell view window (from which I might obtain the view fly-out).
I have tried the following, based on Chen's article:
CComQIPtr<IContextMenu> pcm(m_shell_view); // <<-- FAIL resulting pointer is NULL <<<
// create a blank menu
CMenu menu;
if (!menu.CreatePopupMenu())
throw CContextException("Unable to create an empty menu in which to store the context menu: ");
// obtain the full popup menu we need
if (FAILED(m_hresult = pcm->QueryContextMenu(menu, 0, SCRATCH_QCM_FIRST, SCRATCH_QCM_LAST, CMF_NORMAL)))
throw CLabeledException("Unable to query the context menu for the current folder");
// display the menu to the user
// menu.getsubmenu
::TrackPopupMenu(menu, ::GetSystemMetrics(SM_MENUDROPALIGNMENT)|TPM_TOPALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, m_shell_view_hwnd, NULL);
Unfortunately, the attempt to query the m_shell_view (which is an IShellView*) for its IContextMenu interface fails. This "works":
// retrieve our current folder's PIDL
PidlUtils::Pidl pidl(m_folder);
// get the context menu for the current folder
CComPtr<IContextMenu> pcm;
if (FAILED(m_hresult = GetUIObjectOf(m_owner->m_hWnd, pidl, IID_PPV_ARGS(&pcm))))
throw CLabeledException("Unable to obtain the PIDL for the current folder");
But here I get only a very few options in the context menu (Open, Explore, ...). Not the detailed context menu that I get if I simply right click on the shell view itself.
I'm out of ideas as to how to proceed. Help?! ;)
Try IShellView::GetItemObject with SVGIO_BACKGROUND as uItem to get a IContextMenu on the view object : http://msdn.microsoft.com/en-us/library/bb774832%28VS.85%29.aspx
There is the SHCreateDefaultContextMenu (Vista an up) that may be of help. Bjarke Viksoe website contains great info as well.
SVGIO_BACKGROUND will get you the background context menu of the shell view. You may need to call repeatedly pShellView->SelectItem for each PIDL you may have, then do the GetUIObjectOf call (then QI for IContextMenu, create a menu, call IContextMenu(3)::QueryContextMenu and finally display it with TrackPopupMenu).