Prevent Citrix session to timeout - c#

I need some applications running overnight on Citrix. I don't wish to stay awake all night for that. The Session will timeout and application will be closed. I would not convince the administrator to change the Citrix configuration for this application.
I am trying to create application which will periodically send mouse or keyboard events to the Citrix window. I already have a simple solution which is clicking the mouse.
I wish to have a better solution where everything will be done on background and events would be send just to the Citrix window. Any ideas how to achieve that?
I am using Windows and C# with .NET.
Thank you for any help.
Update #1
I am trying to use Citrix Live Monitoring API as it appears to be a best option. I end up with this:
WFICALib.ICAClient ico = new WFICALib.ICAClient();
int enumHandle = ico.EnumerateCCMSessions();
Console.WriteLine(ico.GetErrorMessage(ico.GetLastError()));
Unfortunately this returns an error message saying:
Live monitoring is disabled
According to documentation it requires following registry keys to be set to 1:
"HKLM\Software\Citrix\ICA Client\CCM\AllowLiveMonitoring(REG_DWORD)"
Problem is that I was unable to find Citrix key in "HKLM\Software\" and it also don't work if I created this keys and values. How do I enable Live Monitoring API?

I have played around with sending input to other windows in the past. I used something like the following:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetCursorPos(int x, int y);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private static void LeftMouseClick(Point point)
{
int xpos = (int)point.X;
int ypos = (int)point.Y;
if (SetCursorPos(xpos, ypos))
{
mouse_event(MOUSEEVENTF_LEFTDOWN, xpos, ypos, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, xpos, ypos, 0, 0);
}
}
So to make this work you need to inject coordinates that fall within the Citrix Receiver window. I can't recall whether you get any focus/activation issues - I believe the click injection should bring the window into focus. I never did anything particularly serious with this code so no guarantees.

Related

WinForm ZIndex to Desktop

As a fun office project we are building a cool transitional background Winform's app to replace the standard windows desktop background.
One of the challenges is that we need our WinForm window to sit on top of the desktop background and icons but not the taskbar.
Is there some way to precisely adjust the Z-Index of a winform window so that it sits on top of the windows desktop but still allows the taskbar and other windows to sit on top of it?
Thank you for the assistance in getting this working. The following worked for us.
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
const short SWP_NOMOVE = 0X2;
const short SWP_NOSIZE = 1;
const short SWP_NOZORDER = 0X4;
const int SWP_SHOWWINDOW = 0x0040;
Usage as follows.
// Our desktop is the top most window.
IntPtr desktop = new IntPtr(0);
// The running form we are testing this code with.
IntPtr form1 = System.Windows.Forms.Application.OpenForms[0].Handle;
// So we're setting our window Z-index to that of the desktop,
// but we setting flags for showing the window and then not not moving and resizing it.
SetWindowPos(form1, desktop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
The Spy++ is really a great tool to learn about the structure of windows and child windows. We found out that setting the IntPtr to Zero will automatically make it select the Desktop (most top) window.
Download spy++ http://mdb-blog.blogspot.com/2010/11/microsoft-spy-or-spyxx-for-download.html then check what's the desktop handle and the start menu handle respectively. This is just to make the proof of concept later you have to find out a better way of taking the handles. Using P\Invoke calls you can get those windows z-order
int GetZOrder(IntPtr hWnd)
{
var z = 0;
for (IntPtr h = hWnd; h != IntPtr.Zero; h = GetWindow(h, 3)) z++;
return z;
}
That code was copied from this question How to get the z-order in windows?
Then you can use SetWindowPos https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx to position your own windows exactly where you want it to be. If you are using windows 8 have in mind that a lot of folks have ClassicShell installed on their machines. Good luck.

Sending shortcuts (sendkeys) to another application while control key is down

I have an application in which I can select options in a list which, when selected, give focus to another window and send a shortcut (e.g. focus Chrome, and send Ctrl + 3 to go to the third tab).
This works well, but I can also use a shortcut to quickly select an option in the list within my own app (e.g. Ctrl + 3).
The issue is that if the user uses a shortcut within my app, then Ctrl key is down globally, and sending shortcuts to other application will also have the Ctrl key down. (Note that I also send shortcuts to other applications using Alt and Win keys, so using the same control key in both my app and the target app is not an option)
Is there a way to tell Windows that Ctrl is not down when using SendKeys, so that the shortcut works in another application? Is there otherwise an alternative for achieving this?
Here is a simplified example of the code I'm using (C#):
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public void SendCtrl3()
{
keybd_event(0xA2, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(0x33, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(0x33, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
keybd_event(0xA2, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
It seems that if the key is physically down, there is no way to make it so other apps won't see that key as down.
The best alternative I found was to use UI Automation.
http://msdn.microsoft.com/en-us/library/ms747327(v=vs.110).aspx

c# receive plug and play events

I was wondering if there are any examples and/or documentation on how to handle Plug and Play event messages used in Windows. Ideally what I am trying to accomplish is to be able to have my application detect a device that has been connected to a machine without having to have a timer, that on tick, will poll ALL COM ports. I find that doing this is extremely inefficient and ramps up my application's CPU usage ten fold. My application is in C# and is currently leveraging .NET 4.0 we are looking to upgrade to .NET 4.5 within the next month. So I am reaching out to find some kind of literature on how to do this. As this is my fist look into supporting a plug and play devices please be gentle with the criticism.
EDIT: Also this application will be running on Windows 7 and Windows XP
I've accomplished this in the past when writing a file browser by using a dummy HwndSource and adding an event handler via the HwndSource.AddHook() method.
// In object constructor
var hwndSource = new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero); // Set up dummy HwndSource
hwndSource.AddHook(sourceHook);
IntPtr sourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg = WM_DEVICECHANGE)
if (wParam.ToInt32 == DBT_DEVICEARRIVAL) // Do what you need to do
if (wParam.ToInt32 == DBT_DEVICEREMOVALCOMPLETE) // Handle device removal
}
// Uses these defined constants:
private const int WM_DEVICECHANGE = 0x219;
private const int DBT_DEVICEARRIVAL = 0x8000;
private const int DBT_DEVICEREMOVALCOMPLETE = 0x8004;
The MSDN for WM_DEVICECHANGE also has info for other const definitions that may be useful:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx

How to detect when the user switches to the Log On screen?

I need to know when the user switches to the logon screen (as triggered by ctrl-alt-del) in order to circumvent a pesky bug in WPF. I want to work around this bug by reinitializing my GUI after returning from the logon screen. Currently it works, but I have to trigger it manually.
I have found SystemEvents.SessionSwitch, but unfortunately this is only triggered when logging off.
How can I detect when the logon screen is displayed by forming ctrl-alt-del?
The tricky thing is that this is not a session change, but rather just a desktop change. In particular, Ctrl+Alt+Del switches to a secured desktop associated with Winlogon.
I don't think you're really supposed to detect this kind of thing (that is, after all, the whole point of having a "secure desktop"), but you could probably do it using an Active Accessibility hook. Call the SetWinEventHook function to install an event hook for the EVENT_SYSTEM_DESKTOPSWITCH event and see what notifications you receive.
To get it going, you'll need to do the following:
Ensure that you're pumping a message loop on your client thread in order to receive event notifications. This shouldn't be a problem for a standard WPF application.
Make sure that you specify the WINEVENT_OUTOFCONTEXT flag, considering that you're working from managed code. You don't want the system to attempt to inject your DLL that contains the callback function into every process. Instead, this will cause the callback function to be called asynchronously from a queue; much safer from the land of managed code.
A little bit of P/Invoke magic. To get you started…
const uint WINEVENT_OUTOFCONTEXT = 0x0;
const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin,
uint eventMax,
IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc,
uint idProcess,
uint idThread,
uint dwFlags);
delegate void WinEventDelegate(IntPtr hWinEventHook,
uint event,
IntPtr hwnd,
int idObject,
int idChild,
uint dwEventThread,
uint dwmsEventTime);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
The process which gets started to show the logon screen seems to be called LogonUI.exe.
Using the Windows Management Instrumentation (WMI) infrastructure you can listen for processes which start and shut down. You will need to reference the System.Management assembly.
var interval = new TimeSpan( 0, 0, 1 );
const string isWin32Process = "TargetInstance isa \"Win32_Process\"";
// Listen for started processes.
WqlEventQuery startQuery
= new WqlEventQuery( "__InstanceCreationEvent", interval, isWin32Process );
_startWatcher = new ManagementEventWatcher( startQuery );
_startWatcher.Start();
_startWatcher.EventArrived += OnStartEventArrived;
// Listen for closed processes.
WqlEventQuery stopQuery
= new WqlEventQuery( "__InstanceDeletionEvent", interval, isWin32Process );
_stopWatcher = new ManagementEventWatcher( stopQuery );
_stopWatcher.Start();
_stopWatcher.EventArrived += OnStopEventArrived;
Handling these events, you can get information about the started or closed process. This way you can verify when LogonUI.exe was shut down, and subsequently trigger the required actions.
void OnStopEventArrived( object sender, EventArrivedEventArgs e )
{
var o = (ManagementBaseObject)e.NewEvent[ "TargetInstance" ];
string name = (string)o[ "Name" ];
...
}

How to press the Windows key programmatically using C# SendKeys

Basically I want to simulate in code a user clicking on the windows key. I know there is SendKeys which allows me to send key presses to windows if I get a handle to them, but what I can't figure out is what I need to get a handle on in order to send Windows key commands. E.g. Windows key + L. Having read into this a bit it appears that CTRL-ESC should pop up the Start Menu also but not sure how to tell it to send the keys to Windows (if this is even possible). Any help would be much appreciated.
Cheers!
I don't think you can do this using SendKeys, you will need to p/invoke to an API function instead, probably keybd_event to send either CTRL+ESC or the Windows key.
Here is an example of opening the start menu this way in VB and here is keybd_event with its C# signature on pinvoke.net.
Some of the things that a user would do via a WinKey shortcut can be done programmatically in other ways. To take your WinKey+L example, you could instead just use the following statement:
Process.Start("rundll32.exe", "user32.dll,LockWorkStation");
If you could elaborate on what exactly you're trying to accomplish, maybe there's a better way than keybd_event (as Dale has suggested).
I've used the class provided here by user703016 and worked fine!
for ref:
using System.Runtime.InteropServices;
using System.Windows.Forms;
static class KeyboardSend
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
private const int KEYEVENTF_EXTENDEDKEY = 1;
private const int KEYEVENTF_KEYUP = 2;
public static void KeyDown(Keys vKey)
{
keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
public static void KeyUp(Keys vKey)
{
keybd_event((byte)vKey, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
used in this way:
KeyboardSend.KeyDown(Keys.LWin);
KeyboardSend.KeyDown(Keys.D4);
KeyboardSend.KeyUp(Keys.LWin);
KeyboardSend.KeyUp(Keys.D4);
You need to use a global keyboard hook to hook into keyboards outside your application. There's an article on how to do it here.

Categories

Resources