CaffeineForCitrixWorkspace
CaffeineForCitrixWorkspace copied to clipboard
Doesn't work with Citrix Workspace app 2012 for Windows
Trying to run CaffeineForCitrixWorkspace with the latest version of Citrix Workspace (2012) doesn't work. Reverting to version 2010 works as a workaround.
I'm not a C# dev but testing manually by inserting Debug.WriteLine
statements led me to this line. In my testing, execution just hangs here indefinitely.
https://github.com/andyjmorgan/CaffeineForCitrixWorkspace/blob/34a16cf8c08d324f8548035b3bcb31e70ccc9c3b/frmHidden.cs#L53
I noticed because the system tray icon is unresponsive when the program is in this state and it doesn't work as expected (keep sessions alive). I'll continue to use version 2010 for now; hope this is helpful to anyone else that gets stuck. Thanks for the useful utility!
I can confirm, that it's not working properly with 20.12.* I also noticed, that the update, seems to have removed the registry entries, so I had to redo those.
The part I'm currently a bit puzzled about is, that as you mentioned, the application will hang on the constructor of the ICAClient, but if I set a break point just before that and run in through a debugger, then step through the code, the constructor will return just fine. Will be playing around with it some more, maybe there's some race condition or assembly loading gone wrong.
Converting the project to .NET 5 didn't help, now I can't even get it to work when stepping through the code in debug mode.
It just keeps hanging during the instance creation of the ICAClient
/ICAClientClass
.
Oddly enough, when you do the same thing with PowerShell the instance is created without issues...
$PF = ${env:ProgramFiles(x86)}
[System.Reflection.Assembly]::LoadFile("$PF\Citrix\ICA Client\WfIcaLib.dll") | Out-Null
$ICA = New-Object WFICALib.ICAClientClass
Write-Host $ICA.Version
Write-Host $ICA.EnumerateCCMSessions()
Still can't explain why the instance creation hangs in C#. I extended the PowerShell script. It should be doing the same as Caffeine itself. One can configure a Windows Schedule with a trigger on start up, that way the PowerShell script will keep running. Might need to look into hiding the window etc. but I guess for now it's better than downgrading.
# Create the following CCM key and DWORD (32-bit) Values and set them to 1
# 32-bit
# HKLM\Software\Citrix\ICA Client\CCM\AllowLiveMonitoring
# HKLM\Software\Citrix\ICA Client\CCM\AllowSimulationAPI
# 64-bit
# HKLM\Software\WOW6432Node\Citrix\ICA Client\CCM\AllowLiveMonitoring
# HKLM\Software\WOW6432Node\Citrix\ICA Client\CCM\AllowSimulationAPI
[System.Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Citrix\ICA Client\WfIcaLib.dll") | Out-Null;
$ICO = New-Object WFICALib.ICAClientClass;
$ICO.OutputMode = [WFICALib.OutputMode]::OutputModeNormal;
do
{
$EnumHandle = $ICO.EnumerateCCMSessions();
$NumSessions = $ICO.GetEnumNameCount($EnumHandle);
Write-Host "Active sessions:" $NumSessions
for ($index = 0; $index -lt $NumSessions; $index++)
{
$sessionid = $ICO.GetEnumNameByIndex($EnumHandle, $index)
$ICO.StartMonitoringCCMSession($sessionid, $true);
$ICO.Session.Keyboard.SendKeyDown(126);
$ICO.StopMonitoringCCMSession($sessionid);
}
$ICO.CloseEnumHandle($EnumHandle) | Out-Null;
} until (Start-Sleep -Seconds 15)
I ended up switching to the long term service release (not affected by this bug), found here: Download Receiver for Windows LTSR - Citrix
Investigated a bit, turns out this is only a problem when embedding the interop types.
To fix, go to the properties of wflcalib under references and change Embed Interop Types to false. Then update the 3 places where the interface was being instantiated and replace with new WFICALib.ICAClientClass();
Enjoy :)
Doesn't work for me unfortunately. I've set Interop Types to false am building as 32-bit (due to COM requirements) and changed the WFICALib usages to use the Class, yet the instantiation just keeps hanging forever.
Still can't really understand this issue, since the PowerShell script essentially doesn't do anything else, yet it continues working...
One guess as to why it doesn't work in an executable, because Citrix hooks itself into every running application and maybe they someone prevent loading the DLL in some way, but it still works fine with the PowerShell script.
If someone knows how to block a DLL from being autoloaded, let me know, then I'd try it out. 🙂
Hey @eXpl0it3r, thanks for the PowerShell script. Unfortunately, I'm getting an error trying to run it. Any ideas on why? It looks like the ICA class doesn't register?
New-Object : Exception calling ".ctor" with "0" argument(s): "Retrieving the COM class factory for component with CLSID
{238F6F83-B8B4-11CF-8771-00A024541EE3} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154
(REGDB_E_CLASSNOTREG))."
At line:3 char:8
+ $ICA = New-Object WFICALib.ICAClientClass
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Make sure you run it in either a x86 or x64 PowerShell instance depending on where Citrix got installed to:
-
C:\Program Files (x86)\Citrix\ICA Client
-> Windows PowerShell (x86) -
C:\Program Files\Citrix\ICA Client
-> Windows PowerShell
That was it, thank you for the swift response. Next question, the script says I have zero (0) sessions even though I have a virtual desktop open. Any advice on how to troubleshoot?
Make sure you have the registry keys set as listed at the top of the screen or when setting up Caffeine
Note again the x86 and x64 differentiation
Hmm, I'm not sure where the disconnect was but it's working now. Perhaps it just needed a reboot? It is Windows after all!
Your script—with x86 PowerShell—works great, thanks again for your help! Now to set this up as a scheduled task...
In case it's useful to anyone else coming across this, here's the Registry file (*.reg) I used. It's the same as what @eXpl0it3r included in the sample script post above.
Windows Registry Editor Version 5.00
;; 32-Bit
[HKEY_LOCAL_MACHINE\Software\Citrix\ICA Client\CCM]
"AllowLiveMonitoring"=dword:00000001
"AllowSimulationAPI"=dword:00000001
;; 64-Bit
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Citrix\ICA Client\CCM]
"AllowLiveMonitoring"=dword:00000001
"AllowSimulationAPI"=dword:00000001
For the powershell script, I'm getting the same issue where it shows zero sessions. Does it matter if I took out the while loop? My plan was to schedule it to repeat from task scheduler. It swear I've seen the exact same code work before and I haven't changed my citrix version (20.10.0.20). Does the script need to run BEFORE any citrix sessions are created? With caffeine v2, if I run it too early, citrix would somehow fail to connect to any sessions. Maybe access conflict with WfIcaLib.dll?
Did you ensure that the registry keys exist at the right place? They are usually deleted after a Citrix update and need to be re-added.
I found the issue, though I don't really understand why. If I run powershell with admin privileges, it doesn't work. That would include running as a task with 'Run with highest privileges'. So as long as I avoid running as admin, it works!
eXpl0it3r, found another issue with your powershell code in my environment. When I run the code, only the first session gets the keypress. I determined this by running an idle timer app in each session and I see that only one of the sessions has its idle timer reset back to zero. If I reverse the order of the FOR loop, then the opposite session is affected.
I'm on citrix workspace 2202.
I tried adding a delay of five seconds between loops but that didn't help. My workaround is to create a new $ICO object for each iteration of the FOR loop:
[System.Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Citrix\ICA Client\WfIcaLib.dll") | Out-Null;
$ICO = New-Object WFICALib.ICAClientClass;
$ICO.OutputMode = [WFICALib.OutputMode]::OutputModeNormal;
$EnumHandle = $ICO.EnumerateCCMSessions();
$NumSessions = $ICO.GetEnumNameCount($EnumHandle);
$ICO.CloseEnumHandle($EnumHandle) | Out-Null;
for ($index = 0; $index -lt $NumSessions; $index++)
{
$ICO = New-Object WFICALib.ICAClientClass;
$ICO.OutputMode = [WFICALib.OutputMode]::OutputModeNormal;
$EnumHandle = $ICO.EnumerateCCMSessions();
$sessionid = $ICO.GetEnumNameByIndex($EnumHandle, $index)
$ICO.StartMonitoringCCMSession($sessionid, $true);
$ICO.Session.Keyboard.SendKeyDown(126);
$ICO.StopMonitoringCCMSession($sessionid);
$ICO.CloseEnumHandle($EnumHandle) | Out-Null;
}
Oh that could well be, I only ever used it with one session 🙂
Oh, man... It is soooo excellent! No .exe needed! Just PowerShell started as normal user!
I have a question about "$ICO.Session.Keyboard.SendKeyDown(126)" - I guess that it is sending key to Citrix session, but what it is "126"?
Other question: do you perhaps know if it possible to do similar thing to prevent block RDP session?
I have a question about "$ICO.Session.Keyboard.SendKeyDown(126)" - I guess that it is sending key to Citrix session, but what it is "126"?
I believe 126 is the ascii code for function 15 aka F15 which doesn't exist on most keyboards but which can sometimes be problematic on things like terminal emulators.
I absolutely love how creative you all have gotten with this. Good job!
I have a question about "$ICO.Session.Keyboard.SendKeyDown(126)" - I guess that it is sending key to Citrix session, but what it is "126"?
I believe 126 is the ascii code for function 15 aka F15 which doesn't exist on most keyboards but which can sometimes be problematic on things like terminal emulators.
Exactly this, I chose this keystroke as not available for most environments, won’t interrupt anything but it doesn’t always play nicely with terminal emulators.
Would a Linux variant be possible? Are the same functions available in the Linux binaries?
Would a Linux variant be possible? Are the same functions available in the Linux binaries?
I don't know but I have written a small script which uses https://github.com/jordansissel/xdotool which is available in most distributions. My first testings are working on my machine.
#!/bin/bash
while true; do
pids=$(xdotool search --classname Wfica)
for pid in $pids; do
name=$(xdotool getwindowname $pid)
if [[ $name != 'wfica' ]]; then
echo sending key to $pid - $name
xdotool key --window $pid alt
fi
done
sleep 60
done
The script looks for windows with a Wfica class and sends a key (alt) to all those windows.