I have an application that doesn't appear to be responding to SikuliX's (v 1.1.2) .focus(). It is one of three custom WinForms applications I have running. I found this link pertaining to my exact situation, but the suggestions did not help.
I have been able to get the code to work for Chrome, SQL Server, and other random applications I have running at the time. The problem seems to come in when I have more than one type of application running. If my applications are named "Version Launcher", "Device 1", and "Alternative", I am able to switch to "Version Launcher", but "Device 1" and "Alternative" aren't found.
class myDevice:
def startApp(self):
#my_app = App("Chrome") # works
#my_app = App("Visual Studio") # works
#my_app = App("Version Selector") # works
#my_app = App("Device 1") # does NOT work
my_app = App("Alternative") # does NOT work
my_app.focus(); wait(1)
my_device = myDevice()
my_device.startApp()
In order to rule out a bad name (perhaps, on some level, the application is not really named "Device 1"), I'd like to build a list of every application that Sikulix can detect at runtime. Has anyone ever tried such a thing? I've searched all over the documentation and cannot find any features that allows for this sort of querying.
Raimund Hocke, the maintainer of the SikuliX project, answered my question over on launchpad.
https://answers.launchpad.net/sikuli/+question/664004
In short, SikuliX uses the 'tasklist' command in Windows to grab the list of available applications.
Related
I'm trying to encapsulate a number of repetitive installation tasks into a private setup program. The program is for in-house use setting up custom, single purpose systems for industrial users. I need Administrator privileges to tweak a number of Windows settings for our environment and then I need to set some current user settings for the application software packages to use.
Is it possible for a Windows program (in plain C, created with Visual Studio 2017) that uses requireAdministrator in its manifest to revert to the user that started the program when the admin privilege is no longer needed? I've seen this done in linux, but have been unable to find any examples (or even mentions) of this being done in Windows. Help? Please?
You don't.
A way given awhile back is to track down the running instance of explorer, and spawn a remote thread in it (with CreateRemoteThread) that does what you want. However CreateRemoteTherad is touchy and what if explorer isn't running?
If you know the username you can use CreateService() to create a service that runs as that user and ServiceStart() to start it but that's its own pain and now the code has to deal with no access to the desktop. Getting code running as the user on the desktop involves digging into the undocumented.
The correct design is to use two executables, the first with asInvoker that starts the second with requireAdministrator using the API call ShellExecuteEx, waits for it to finish, checks the exit code, and on success does the individual user steps.
There is no way to de-elevate a running process. You might be able to lower your rights a little bit but not all the way. Even if it was possible, you would have to hardcode the list of groups and privileges to remove/disable in your token because I don't believe there is a API to restrict a token just like UAC does.
There are many half-assed solutions out there to start a un-elevated child process:
Using the Task Scheduler
IShellDispatch2::ShellExecute in the "main" Explorer.exe instance
CreateProcessAsUser with the token from the "main" Explorer.exe instance
Bootstrapper instance elevates another instance and communicates back to parent when it needs to perform un-elevated actions
Take advantage of Explorer bug and simply execute "%windir\Explorer.exe" "c:\path\to\myapp.exe"
All of those solutions have issues related to:
Explorer might not be running (custom shell or Explorer crash)
Explorer is running elevated
Non-admin users elevate with a different administrator account with a different SID
RunAs.exe has been used and your parent process is not the same as the "main" logon session nor Explorer.exe
Final Answer
When I was finally able to install a clean Windows 10 on a spare system for testing and create a pure non-admin account to test with, the new, improved answer did not work. I added a GetUserName() call after the impersonate and wrote it to the debug log to learn that the user name was the same before and after the impersonate, even though all of the functions returned success. I can only assume that the GetShellWindow() [I also tried GetDesktopWindow(), just in case] returned a handle to an explorer/shell under the Admin context. So, now I'm using a cleaned up (to make it plain C) version of the GetConsoleUserToken() function I found here: https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/17db92be-0ebd-4b54-9e88-a122c7bc351d/strange-problem-with-wtsqueryusertoken-and-impersonateloggedonuser?forum=windowsgeneraldevelopmentissues This is working on both my development system AND on the clean Windows 10 non-admin user. The function actually searches all running processes for the explorer.exe that belongs (is attached?) to the console session and while debugging it, I did see that it find more than one explorer.exe process, but only ONE is the right one.
Thanks for all of the suggestions and comments! They gave me good ideas and put me on a path that allowed me to use better search terms to find what I needed.
To Microsoft: This seems quite unnecessarily complex to do something that should not be difficult for an administrator-level process to do.
New, Improved Answer:
Following the suggestion made by eryksun, I created the following example function that shows all of the steps my program needed to get the current user key opened. My program has requireAdministrator in the manifest, if yours does not, you might need to make changes or additions to my sample. Here is what is working perfectly for me (but apparently not on a clean machine under a non-admin account):
BOOL ChangeHkcuSettings( void )
{
BOOL bResult = FALSE; // HKCU was not accessed
HWND hwndShell;
DWORD dwThreadId;
DWORD dwProcessId;
HKEY hKeyUserHive;
HANDLE hToken;
HANDLE hProcess;
hwndShell = GetShellWindow();
dwThreadId = GetWindowThreadProcessId( hwndShell, &dwProcessId );
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
if( NULL != hProcess )
{
if( OpenProcessToken( hProcess,
TOKEN_QUERY
| TOKEN_DUPLICATE
| TOKEN_IMPERSONATE,
&hToken ) )
{
if( ImpersonateLoggedOnUser( hToken ) )
{
if( ERROR_SUCCESS == RegOpenCurrentUser( KEY_ALL_ACCESS, &hKeyUserHive ) )
{
// ... use the user hive key to access necessary HKCU items ...
RegCloseKey( hKeyUserHive );
bResult = TRUE; // HKCU was accessed
}
RevertToSelf();
}
CloseHandle( hToken );
}
CloseHandle( hProcess );
}
return bResult;
}
Thanks again to eryksun for the suggestion!
ORIGINAL ANSWER: I think I found another way that will work for me... Instead of using HKEY_CURRENT_USER (which will be the Administrator) the admin account can open the specific user's registry key(s) under HKEY_USERS instead. I will need to find the appropriate user's SID, but my setup knows the user's name (and password, for setting auto logon), so I think this is do-able. For me, this is much easier, since all of the code already exists in a single program that formerly write EVERYTHING to HKEY_LOCAL_MACHINE, which was easy and worked great. Trying to be "correct" is much more work, perhaps more than it should be! :-(
I have gone to License your app and there is only code for C#. I am wondering where to place the license information in my F# WPF application.
Does it go in the app.fs file or a different one.
Thanks
I'm not familiar with this SDK but it should go into the assembly (so exe or dll) file that uses it. It would've been helpful to show the C# code, and not just the link:
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId = "mYcLieNTid";
try
{
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.Initialize();
}
catch (Exception ex)
{
Console.WriteLine("Unable to initialize the ArcGIS Runtime with the client ID provided: " + ex.Message);
}
From the recently much improved F# docs Try/With is the equivalent exception handling mechanism in F#:
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId <- "mYcLieNTid";
try
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.Initialize()
with
| ex -> printfn "Unable to initialize the ArcGIS Runtime with the client ID provided: %A" ex.Message
Additional Info: If you have time please take a look at F# for fun and also Modules and Classes, you can also search these topics on SO. Here are some comments:
F# is sensitive to the file order in the project, please make sure that you put your module above the file that is open-ing it
you generally #load *.fsx scripts, you can but you don't need to do this for *.fs files, as those assumed to be built into an assembly. You can just say open File1 assuming you have a File1.fs and inside it a module File1, then if inside the File1 module you have let let x = 5, you can say File1.x to access it
You don't need to put a module into a separate file. You can just place it ino the namespace you have your SDK in (maybe App.fs).
Easiest would be to actually put this code inside your main function, in the [<EntryPoint>]
In my Yesod web app I found my code - which had worked perfectly before - impossible to launch properly.
The error message was this:
Database migration: manual intervention required.The following actions are >considered unsafe: DROP TABLE "config_d_b";
The database consists of this code:
share [mkPersist sqlSettings, mkMigrate "migrateAll"]
[persistLowerCase|
ConfigDB
numberOfParticipants Int
setEndOfRegDate Bool Maybe
endOfRegistration Day Maybe
stopRegistration Bool
groupName Text
deriving Show
|]
I'm working on fpcomplete and now, after logging out and leaving it alone for ten minutes, it works fine.
I still don't want to run the risk of this happening again (presentation due in 4 days).
So, what is going on?
From this related question:
Haskell Persistent out of sync
I got the impression that it had something to do with
endOfRegistration Day Maybe
but deleting all the related code yielded no different result.
Thanks in advance, Sophia
I have multiple python scripts which I have converted to executables using py2exe. When I run them I get a UAC dialog box saying
'Do you want the following program from an unknown publisher to be able to make changes to your computer.'
I'm running windows 7, 64bit, python 3.3.
In order to be sure it wasn't due to my code, I copied the following simple script from the web and created an exe. Still the same problem.
import ctypes
from ctypes import wintypes
def get_appdata_directory():
CSIDL_APPDATA = 0x001a
dll = ctypes.windll.shell32
app_data_directory = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
found = dll.SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, app_data_directory)
return app_data_directory.value
appdata = get_appdata_directory()
The script merely finds the path to the appdata directory.
What needs to be done in order to avoid the UAC dialog box?
You need to create an "Assembly Manifest" for your application. It has to declare requestedExecutionLevel=asInvoker, and then either
embed it as a resource (RT_MANIFEST)
or have it in the same folder as your exe, and named MyApp.exe.manifest
I've a WPF Application that actually uses a Web server for downloading the app and execute it on the client... I've also created a staging enviorment for that application when I put the release as soon as new features are added / bug fixed.
I've not found a reasonable way of promoting from staging to production since the app.config is hashed... so I can't change my pointments (DB/Services) editing it...
My actual way is publishing for staging, increasing of 1 the publish version and publishing for production...but this is quite frustrating.... since I've to do twice the work...any sugeestion?
Thanks
Our team encountered the same situation a year ago. We've solved the situation by following this steps:
Determine the latest ClickOnce application version;
Removing the *.deploy extensions;
Making the necessary *.config file changes;
Updating the manifest file (*.manifest) by using 'Mage.exe' and your certificate (see also: MSDN);
Update the deployment manifest (*.application) in the application version directory and in the root directory, again by using 'Mage.exe';
Adding back the *.deploy extensions.
Hereby a short code sample for calling Mage, really not that complicated though.
// Compose the arguments to start the Mage tool.
string arguments = string.Format(
#"-update ""{0}"" -appmanifest ""{1}"" -certfile ""{2}""",
deploymentManifestFile.FullName,
applicationManifestFile.FullName,
_certificateFile);
// Add password to the list of arguments if necessary.
arguments += !string.IsNullOrEmpty(_certificateFilePassword) ? string.Format(" -pwd {0}", _certificateFilePassword) : null;
// Start the Mage process and wait it out.
ProcessStartInfo startInfo = new ProcessStartInfo(_mageToolPath, arguments);
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
Process mageProcess = Process.Start(startInfo);
mageProcess.WaitForExit();
// Show all output of the Mage tool to the current console.
string output = mageProcess.StandardOutput.ReadToEnd();
// Determine the update of the manifest was a success.
bool isSuccesfullyConfigured = output.ToLower().Contains("successfully signed");