Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2018-06

GetAppConfigDir(False) in a Citrix environment

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bart

Hi,

One of my apps also runs in a Citrix environment.
It does not retrieve it's settings.

If appears that GetAppConfigDir(False) returns
"C:\Users\<username>\AppData\Local".
(%LOCALAPPDATA%=C:\Users\902617\AppData\Local)
Whereas %APPDATA% points to "\\prof001\profiles\<username>\AppData", and this is also the location where programs like FireFox write there config files to.

While my program actually writes to
"C:\Users\<username>\AppData\Local\somsubfolder\programname.ini" (the file exists and contains the content it should have), upon restart of the program that ini file does not exist anymore.
So this location is pretty useless.

Any thoughts on retrieving the sensible place to store configuration files in such an environment, or how to detect I'm in such an environment?

Bart

Reply by email

Michael Van Canneyt
to Bart
Bart wrote 21 lines
Hi, One of my apps also runs in a Citrix environment. It does not retrieve it's settings. If appears that GetAppConfigDir(False) returns "C:\Users\<username>\AppData\Local". (%LOCALAPPDATA%=C:\Users\902617\AppData\Local) Whereas %APPDATA% points to "\\prof001\profiles\<username>\AppData", and this is also the location where programs like FireFox write there config files to. While my program actually writes to "C:\Users\<username>\AppData\Local\somsubfolder\programname.ini" (the file exists and contains the content it should have), upon restart of the program that ini file does not exist anymore. So this location is pretty useless. Any thoughts on retrieving the sensible place to store configuration files in such an environment, or how to detect I'm in such an environment?

https://stackoverflow.com/questions/4186153/api-for-determining-if-app-is-running-on-citrix-or-terminal-services https://helgeklein.com/blog/2014/08/app-running-citrix-xendesktopxenapp/

AppConfigDir uses

GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA);

if you see you're under Citrix, you could use

GetWindowsSpecialDir(CSIDL_APPDATA);

Michael.

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt

Oh wow, talk about perfect timing. This afternoon I had to look into a bug where our app also runs under a Citrix environment, and on reboot (or new session) the settings are lost.

Thanks for the info Michael.

G.

Michael Van Canneyt wrote 13 lines
> Any thoughts on retrieving the sensible place to store configuration > files in such an environment, or how to detect I'm in such an > environment? https://stackoverflow.com/questions/4186153/api-for-determining-if-app-is-running-on-citrix-or-terminal-services https://helgeklein.com/blog/2014/08/app-running-citrix-xendesktopxenapp/ AppConfigDir uses GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA); if you see you're under Citrix, you could use GetWindowsSpecialDir(CSIDL_APPDATA);

Reply by email

Bart
to Graeme Geldenhuys
Graeme Geldenhuys wrote
Oh wow, talk about perfect timing. This afternoon I had to look into a bug where our app also runs under a Citrix environment, and on reboot (or new session) the settings are lost.

@Graeme: did you manage to translate all that into pascal? If so, do you care to share it?

Bart

Reply by email

Bart
to Graeme Geldenhuys
Graeme Geldenhuys wrote
I haven't had time to look at that job at work yet, but it's on my todo list and should be done in the next week. I don't mind sharing the solution.

This is the easy part:

const
  WTS_CURRENT_SERVER_HANDLE = DWORD(0);
  WTS_CURRENT_SESSION = DWORD(-1);
  WTS_PROTOCOL_TYPE_CONSOLE = 0;
  WTS_SESSION_TYPE_ICA = 1;
  WTS_SESSION_TYPE_RDP = 2;

type
WTS_INFO_CLASS = (
WTSInitialProgram ,
WTSApplicationName ,
WTSWorkingDirectory ,
WTSOEMId ,
WTSSessionId ,
WTSUserName ,
WTSWinStationName ,
WTSDomainName ,
WTSConnectState ,
WTSClientBuildNumber ,
WTSClientName ,
WTSClientDirectory ,
WTSClientProductId ,
WTSClientHardwareId ,
WTSClientAddress ,
WTSClientDisplay ,
WTSClientProtocolType ,
WTSIdleTime ,
WTSLogonTime ,
WTSIncomingBytes ,
WTSOutgoingBytes ,
WTSIncomingFrames ,
WTSOutgoingFrames ,
WTSClientInfo ,
WTSSessionInfo ,
WTSSessionInfoEx ,
WTSConfigInfo ,
WTSValidationInfo ,
WTSSessionAddressV4 ,

  WTSIsRemoteSession);
function WTSQuerySessionInformationA(hServer: HANDLE;
  SessionId: DWORD;
  WTSInfoClass: WTS_INFO_CLASS;
  var ppBuffer: LPTSTR;
  var pBytesReturned: DWORD): BOOL; stdcall; external 'wtsapi32.dll'
name 'WTSQuerySessionInformationA';
procedure WTSFreeMemory(pMemory: Pointer); stdcall; external
'wtsapi32.dll'name 'WTSFreeMemory';
function WTSGetSessionType: Word;
var
  pBuf: Pointer;
  pBytesReturned: DWORD;
begin
  Result := Word(-1);
  pBuf := nil;
  pBytesReturned := 0;
  if not WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION, WTSClientProtocolType, pBuf, pBytesReturned) then
    Exit;
  if (pBytesReturned > 0) {should be 2} then
  begin
    Result := PWord(pBuf)^;
    WTSFreeMemory(pBuf);
  end;
end;
function WTSSessionTypeToStr(ProtocolID: Word): String;
begin
  case ProtocolID of
    WTS_PROTOCOL_TYPE_CONSOLE: Result := 'WTS_PROTOCOL_TYPE_CONSOLE';
    WTS_SESSION_TYPE_ICA: Result := 'WTS_PROTOCOL_TYPE_ICA';
    WTS_SESSION_TYPE_RDP: Result := 'WTS_PROTOCOL_TYPE_RDP';
    else Result := 'WTS_SESSION_TYPE_UNKNOWN';
  end;//case
end;

Now only the hard part remains ...

Bart

Reply by email