Controlling Message Boxes In Citrix - c#

I have an instance of an application running on a Citrix server. I was recently tasked with writing a plugin for that piece of software, and for reasons to do with how software is deployed where I work, the plugin actually just executes another piece of software sitting on a remote server that actually does the work and waits for that process to end (this is hidden from the user).
Occasionally this external software has to display a message with a message box. In order to make sure that it came up on top of the application, I used the user32 messagebox method with that application's handle.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern MessageBoxResult MessageBox(IntPtr hWnd, String text, String caption, int options);
public static MessageBoxResult ShowMessageBox(IntPtr windowHandle, string text, string caption, MessageBoxOptions options)
{
return MessageBox(windowHandle, text, caption, (int)options);
}
That works great when the application is being run on a local machine, but when it is being run through Citrix, the message box no longer shows up on top. Does anyone have any ideas how to make the Citrix version behave like the local version?

I worked around the issue by setting the topmost flag on the messagebox. This isn't exactly what I wanted, but it was better than having the messagebox not show up on top initially.

Related

Send username and password to another application

I would like to send a user name and a password to another application, and process the input.
so I have Application A which has a window that requires a username and a password.
and we have Aplication B that is running. Application B needs to search for application A, login window, and send the user name to a textbox in it and the password, and then process those unputs through the Ok button.
Are there any libraries that can handle those sorts of requirements?
Any help weather it be website or dll references or examples would be great
NOTE:-
APPLICATION A is not something I built, or have access to its code or anything, I can start it, thats about it.
here is the process just to make things clear since some are confused:-
Application B is an EXE application, when clicked, it does some logic, then it starts Application A.
As soon as Application A starts, the user will prompted with a dialog box to enter user name, and password This is not something I made, it is what the application does. My question is can I access this dialog window, and send inputs to it.
FORM CODE
public partial class Form1 : Form {
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
public Form1() {
InitializeComponent();
var process = new ProcessStartInfo(#"arcmap.exe");
var pr=Process.Start(process);
SetForegroundWindow(pr.Handle);
SendKeys.Send("ne{TAB}ne{ENTER}");
}
}
}
This doesn't sound like a proper design strategy to me. Why not merging the two applications to one and passing the requested values between different application forms?
If for some reason you need to use two different applications, simply open application B AFTER the user has entered his login credentials in application A, and pass those values as parameters to your second app.
You can also consider using a TCP class in order to virtually connect the two of your apps using sockets.
You'll need to start Arcmap (this is a fairly easy task using Process.Start(string path);, then give it some time to boot using Thread.Sleep(int miliseconds), and then it gets tricky.
You'd have to get the Arcmap process (probably by name) and set it as foreground window by importing this method:
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
And then calling it this way:
Process process = Process.GetProcessesByName("arcmapProcessName").FirstOrDefault();
SetForegroundWindow(process);
And later you just send keys using
SendKeys.Send("login{TAB}password{ENTER}");
Then you would have to reference the SendInput function to programatically inject keyboard keypresses into the input stream. Perhaps, since it's a lot of hassle to reinvent the wheel and you're asking for an external library anyway, you could use C# Input Simulator.

Programatically paste text into text box in another application

I want to be able to paste the results from my application to another application. Been Googling and all I can find is the ApplicationCommands.Paste. That will paste it into my application not another application.
Background: My application needs to interact with a very old application. This application is not being developed and DOES NOT have any API calls. Meaning any answers like "Link your application via DLLs" will only be excepted if it also includes a time machine :P So the solution is to simple paste results from my app to the old application.
For workflow reasons the client wants my Application to disappear and automatically paste the results into an open text box in (if it fails then manually pasting the results in).
Hiding the window is simple, but how do I find current active application and then paste it in? Is this even possible? Also note this application is NOT .NET (VB 6 if I am correct).
You can bring up the other app and send a key combination... something like:
[DllImport ("User32.dll")]
static extern int SetForegroundWindow(IntPtr hwnd);
public static void PasteToApplication(string appName)
{
var proc = Process.GetProcessesByName(appName).FirstOrDefault();
if(proc != null)
{
var handle = proc.MainWindowHandle;
SetForegroundWindow(handle);
SendKeys.SendWait("^v");
}
}
This should bring up the other app's window and send a ctrl-v command. With a bit of experimentation, you could find out the exact handle of the control you want to send the paste to, and set focus on it aswell

ShowWindow Function Doesn't Work When Target Application Is Run As Administrator

I am writing a program that shows/hides the window of some target application. I was testing it out earlier and noticed something strange. If I run the target application as Administrator (right-click->Properties, "Compatability" tab, "Run this program as administrator") it doesn't work.
To demonstrate I wrote a simple GUI app called "TargetApplication" and then I wrote the following code to test showing/hiding this application:
class Program
{
static void Main(string[] args)
{
IntPtr windowPtr = FindWindow(null, "TargetApplication");
ShowWindow(windowPtr, 0); // 0 = Hide
Console.WriteLine("The window is now hidden. Press Enter to restore");
Console.ReadLine();
ShowWindow(windowPtr, 9); // 9 = Restore
Console.WriteLine("The window is now restored. Press Enter to exit.");
Console.ReadLine();
}
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
If I start the windowed application without Administrator rights it doesn't work.
Would anyone mind testing this for me? I have uploaded the .exe's for both applications here:
TestShowWindow Download
All you have to do is download them and run TestApplication.exe then run TestShowWindow.exe. You will find that by changing TestApplication.exe to run as Administrator causes ShowWindow to no longer work.
Of course if you don't trust downloading my stuff you can always compile my code and test it on any target application in Windows that you are able to change compatability mode of.
P.S. I am not sure if it makes a difference but I am running Windows 8 Pro. 64-bit.
This is by design. It is the lesser known twin of UAC, called UIPI or User Interface Privilege Isolation. An un-elevated program cannot commandeer an elevated one. Given the capabilities of UI Automation, this is an obvious counter-measure to stop programs from hijacking the capabilities of an elevated process. A security violation called a shatter attack.
Workarounds are to provide a manifest with uiAccess = true for a program stored in c:\windows or c:\program files and provided with a certificate. And for the target program to call ChangeWindowMessageFilter to allow certain messages to be sent. In your case that ought to be WM_SHOWWINDOW.
If you don't mind the window acting like you minimized it to the taskbar; You can, generally, show and hide windows from elevated processes by posting WM_SYSCOMMAND with a wParam of SC_RESTORE or SC_MINIMIZE.

Changing the user agent using urlmon.dll

While looking for a way to change the user agent string for the webBrowser control, I found this nifty method:
[DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);
const int URLMON_OPTION_USERAGENT = 0x10000001;
public static void ChangeUserAgent(string Agent)
{
UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, Agent, Agent.Length, 0);
}
Basically, I needed a way to change the user agent until I want to change it again.
The usual:
webBrowser1.Navigate ("http://www.whatsmyuseragent.com", "_self" , null, "User-Agent: Luke's Web Browser");
Only works for one request.
However, I keep reading everywhere that the first method only works once per session. In my case, it works as many times as I want it to. So my guess is that this is related to the instance of Internet Explorer on the computer?
So my questions are:
What version does the end user need to have installed on their computer for this method to work as intended? IE. change as much as I want.
Since this is related to the Internet Explorer installed on the computer, does changing the user agent in my application effect the browser?
If the user has Internet Explorer open, will this method still work?
Thanks!
We use the "UrlMkSetSessionOption" function quite a bit. We have a "custom web browser shell" which is really just an IE user control embedded into a full screen WinForms program. We change the user agent to identify to our web server that this is our "custom" browser shell. But to answer your specific questions:
We've used this with both IE8 on XP and IE9 on Win7. I think it is version independent, but we always use the latest version.
As far as we can tell, changing this setting only affects IE running in the process that invoked the method. So if a user launches IE from the desktop, the user agent is unchanged. If you restart the program, the user agent is unchanged.
It works with and without standalone IE instances running. The user agent for those standalone instances remain unchanged.

Finding the Child Window inside a Microsoft RemoteApp Programmatically

Background
I'm using SendKeys() to send keyboard commands to the active window, but I'm not having any luck finding the child window when the application is running through RemoteApp. It all works as expected when I run the application locally.
Microsoft RemoteApp allows users to connect to applications through the RDP protocol, but instead of showing the entire remote Virtual machine, it just shows the application window. To the end user, there is no difference between an application running under RemoteApp and it running on their desktop.
I've been using ManagedSpy to determine the class name of the .NET application window so that I can use the Win32 API function FindWindowEx to make one of the child windows active, and it works well. However, I'm having a problem when the application is running over RemoteApp.
I can still use the .NET Process.GetProcessesByName() to find the application, I just have to have it invoke mstsc.exe:
IntPtr hwndChild = IntPtr.Zero;
Process[] processess = Process.GetProcessesByName("mstsc");
IntPtr appHandle = IntPtr.Zero;
foreach (Process p in processess)
{
if ((p.MainWindowHandle != IntPtr.Zero))
{
appHandle = p.MainWindowHandle;
}
}
if (appHandle == IntPtr.Zero)
{
MessageBox.Show("Application is not Running.");
return;
}
However, I can't use FindWindowEx in the same way. This question revolves around that.
For the unmanaged code to tell me what windows mstsc.exe has active, I used Spy++, but for mstsc.exe it comes back with a different class name, called RAIL_WINDOW:
Here is the code I'm using to find the Child Window:
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
hwndChild = FindWindowEx(appHandle, IntPtr.Zero, "RAIL_WINDOW", "MyApplication (Remote)");
SetForegroundWindow(hwndChild);
Questions
I can use Spy++ to highlight the active child window in the RemoteApp version of the application, and I get RAIL_WINDOW, but I cannot seem to access this window programmatically. Given the code above, what am I missing to be able to do so?
Are there other ways of sending keyboard strokes to an application running over Remote App?
Knowing how Microsoft does things, I'll bet the "rail window" is nothing more than a dumb, local proxy that doesn't bother responding to what SendKeys is sending. I haven't looked, but I'll bet that ends up sending WM_CHAR messages, to which a dumb proxy probably wouldn't bother responding. Instead, try sending it WM_KEYUP and WM_KEYDOWN messages manually and see if that works, given that I expect it would transmit those and mouse clicks (and what not) rather than the translated versions.
What commands are you sending using SendKeys()?
It may be better to look for an alternative solution instead of using `SendKeys()'.
And you can probably take advantage of handling IMsTscAxEvents::OnRemoteWindowDisplayed event that gives you the proper window handle at the right time without calling FindWindowEx, etc.

Categories

Resources