Programming guide
When you write Windows applications using the Microsoft Windows SDK, call WFAPI functions only when necessary. Your C applications can check for the presence of Wfapi.dll (for 32-bit applications) or Wfapi64.dll (for 64-bit applications), enabling them to run on any Windows 10 or greater Workstation or Server environment. These options help make your applications as portable as possible. The server and workstation are used interchangeably in the following functions:
Function summary
C Function | Description |
---|---|
WFCloseServer() | Closes an open server handle. |
WFDisconnectSession() | Disconnects a specified session. |
WFDisconnectSessionEx() | Forces an immediate disconnect of a specified session. |
WFEnumerateProcessesA() WFEnumerateProcessesW() | Retrieves a list of processes on the specified server. |
WFEnumerateProcessesExA() WFEnumerateProcessesEXW() | Retrieves a list of processes on a specified server. |
WFEnumerateSessionsA() WFEnumerateSessionsW() | Retrieves a list of sessions on a specified server. |
WFFreeMemory() | Frees memory allocated by WFAPI functions. |
WFLogoffSession() | Logs off a specified session. |
WFOpenServerA() WFOpenServerW() | Opens a handle to a specified server. |
WFQuerySessionInformationA() WFQuerySessionInformationW() | Retrieves information about a specified session on a server. |
WFQueryUserConfigA() WFQueryUserConfigW() | Retrieves configuration information about a specified user on a server. |
WFSendMessageA() WFSendMessageW() | Sends a message box to a specified session. |
WFSetUserConfigA() WFSetUserConfigW() | Modifies configuration information for a specified user on a server. |
WFShutdownSystem() | Shuts down and optionally restarts the current server. |
WFTerminateProcess() | Terminates a specified process on a server. |
WFVirtualChannelClose() | Closes an open virtual channel handle. |
WFVirtualChannelOpen() | Opens a handle to a specific virtual channel. |
WFVirtualChannelPurgeInput() | Purges all queued input data sent from the client to the server on a specified virtual channel. |
WFVirtualChannelPurgeOutput() | Purges all queued output data sent from the server to the client on a specified virtual channel. |
WFVirtualChannelQuery() | Queries data related to a virtual channel. |
WFVirtualChannelRead() | Reads data from a virtual channel. |
WFVirtualChannelReadEx() | Reads data from a virtual channel. |
WFVirtualChannelWrite() | Writes data to a virtual channel. |
WFWaitSystemEvent() | Waits for an event (for example, ICA session create, delete, and connect) before it returns. |
WFWaitSystemEvent() | Verify the ability to wait on system events like Connect/Disconnect/LogOFF/LogON/Shutdown. |
WFCaptureAppDisplay() | Capture the contents of an application window. |
WFReleaseAppDisplay() | Stop capturing the contents of an application window. |
Function categories
The functions in the WFAPI SDK are grouped into several categories: internal, enumeration, server system, user, session, and virtual channel.
Internal functions
The WFAPI SDK internal functions are:
-
WFOpenServerA() and WFOpenServerW()
-
WFCloseServer()
-
WFFreeMemory()
These functions are internal to the WFAPI; they do not act upon the server or session. Most functions require a handle to a server. A handle is obtained using the WFOpenServerA()/WFOpenServerW() function. The constant WF_CURRENT_SERVER_HANDLE always refers to the current server and can be used without explicitly issuing WFOpenServerA()/WFOpenServerW().
Issue the WFCloseServer() function as part of your program’s clean-up when you are finished with the handle. Do not close WF_CURRENT_SERVER_HANDLE.
If you call a C function that allocates and returns memory, de-allocate the memory using the WFFreeMemory() function when you are finished.
Enumeration functions
The WFAPI SDK enumeration functions are:
-
WFEnumerateProcessesA() and WFEnumerateProcessesW()
-
WFEnumerateProcessesExA() and WFEnumerateProcessesExW()
-
WFEnumerateSessionsA() and WFEnumerateSessionsW()
These functions are used to enumerate processes and sessions. The WFEnumerate Processes, WFEnumerateProcessesEx, and WFEnumerateSessions functions require a server handle.
The WFEnumerateProcessEx functions return more detailed information than the WFEnumerateProcesses functions.
Server system functions
The WFAPI SDK server system functions are:
-
WFShutdownSystem()
-
WFWaitSystemEvent()
These functions are used to manage a server system. The WFShutdownSystem() and WFWaitSystemEvent() functions require a server handle. WFShutdownSystem() shuts down and optionally restarts the current server, and can be used to disable logons. WFWaitSystemEvent() waits for an event (ICA session create/delete/connect, user logon/logoff, and so on) before it returns.
User functions
The WFAPI SDK user functions are:
-
WFQueryUserConfigA() and WFQueryUserConfigW()
-
WFSetUserConfigA() and WFSetUserConfigW()
These functions are used to retrieve or set user configuration information. Both functions require a server name, a user name, and the class of information that is operated on. A handle is not required. The constant WF_CURRENT_SERVER_NAME refers to the current server.
These functions are passed a server name instead of a handle because user account information often resides on a domain controller.
-
Use the Windows function NetGetDCName() to retrieve the name of the primary domain controller for the WFSetUserConfig() function.
-
Use the Windows function NetGetAnyDCName() to retrieve the name of any domain controller for the WFQueryUserConfig() function.
You can use any domain controller to query domain information; however, you must use the primary domain controller when changing domain information. This is in agreement with other Microsoft API functions. The Visual Basic USER example program demonstrates the use of the NetGetAnyDCName() function.
Session functions
The WFAPI SDK session functions are:
-
WFQuerySessionInformationA() and WFQuerySessionInformationW()
-
WFSendMessageA() and WFSendMessageW()
-
WFDisconnectSession() and WFDisconnectSessionEx()
-
WFLogoffSession()
-
WFTerminateProcess()
These functions are used to operate on active sessions. All functions require a server handle and a session ID.
Virtual channel functions
The WFAPI SDK virtual channel functions are:
-
WFVirtualChannelOpen()
-
WFVirtualChannelClose()
-
WFVirtualChannelRead()
-
WFVirtualChannelReadEx()
-
WFVirtualChannelWrite()
-
WFVirtualChannelPurgeInput()
-
WFVirtualChannelPurgeOutput()
-
WFVirtualChannelQuery()
The ICA protocol provides multiplexed management of multiple virtual channels. A virtual channel is a session-oriented transmission connection that can be used by application layer code. Virtual channels are used to add functional enhancements to the client, independent from the ICA protocol.
The WFVirtualChannelOpen() function requires a server handle, a session ID, and a virtual channel name. It returns a virtual channel handle. The other functions require the resulting virtual channel handle.
Use the WFVirtualChannelClose() function to close the handle when it is no longer needed.
App-sharing functions
The WFAPI SDK app-sharing functions are:
-
WFCaptureAppDisplay
-
WFReleaseAppDisplay
These functions are used to facilitate application sharing by capturing the contents of an application window and making it available to virtual channels through the Citrix virtual channel SDK.
Unicode and ANSI versions
Most functions have both Unicode and ANSI versions. ANSI is an older, more common standard, but is difficult to use simultaneously with multiple languages. Unicode is a 16-bit (wide) character set that supports up to 65,536 unique characters, allowing for the representation of multiple language characters using a single character set.
For each function that has both ANSI and Unicode declarations, both declarations are listed under the main heading. Each function is declared as either functionnameA( ) for the ANSI version or functionnameW( ) for the Unicode (wide) version.
In C, the additional #define for functionname() allows you to use a compiler directive to use all ANSI or all Unicode functions in the resulting executable. This makes it easy to produce both ANSI and Unicode versions of your programs because you need to change only the makefile.
In Visual Basic, explicit function names must be used for those functions that have both ANSI and Unicode versions defined.
C API calling conventions
C-language programs that use the WFAPI functions must include Wfapi.h, and link to Wfapi.lib for 32-bit applications or Wfapi64.lib for 64-bit applications.
The words IN and OUT that are listed in the function calling conventions are included only for clarification. They are defined as blank in the Windef.h file. If you do not have access to Windef.h, add the following lines to the header file for your project:
#ifndef IN
#define IN
#endif
#ifndef OUT
#define OUT
#endif
WINAPI, as listed in the function calling conventions, is defined in the Windows.h file. If your program uses dynamic linking with runtime binding, you must include Windows.h in the function pointer definition. For more information, see the Testall.c example.
If a function succeeds, the return value is TRUE. If a function fails, the return value is FALSE. Use the GetLastError() function to get the extended error status.
Application programming guidelines
-
Avoid using hard coded paths, such as C:\Temp.
-
Use the Win32 API functions whenever possible. Many Windows API functions have Citrix enhancements to seamlessly support a multiuser environment.
-
Do not assume that temporary files are persistent.
-
Do not assume the existence of a default printer.
-
Be sensitive to the bandwidth used by printing tasks.
-
Do not use machine-specific attributes (such as machine names or IP addresses) for unique identifiers. These items are common to all users on each machine.
-
Write user-specific settings to HKEY_CURRENT_USER, not HKEY_LOCAL_MACHINE.
-
Do not allow “File,” “Run” capabilities.
-
Limit necessary animation to reduce bandwidth consumption.
-
Use solid-color graphics for better ICA compression.
-
Do not overwrite Windows Terminal Services-specific DLLs with Windows DLLs.
-
Do not try to allocate all available memory.
-
Do not use continuous polling loops in your code because they require excessive CPU cycles. Use event-driven techniques instead.
-
Thoroughly test required peripheral devices over all connection types.
-
Do not assume that your application runs on a Windows Explorer shell.
-
Memory leaks and their negative effects are greatly compounded in a multiuser environment.
-
Avoid using bitmaps in graphics; use vector-based graphics instead. For best performance on an ICA device, use the raster operator to “brush” graphics onto the screen.
-
Some applications that use the TCP/IP protocol to communicate use the IP address as the hard-coded identifier of the client. Multiple instances of these applications doesn’t run on a Citrix environment.
-
For an application to properly communicate in a Citrix environment, the application must be able to negotiate a private socket, allowing the client and server to communicate using a unique IP/PORT/SOCKET address.
-
The use of True Type fonts is preferred; these font types are stored on the client. If an application must use custom or Adobe fonts, configure them to be embedded Windows fonts for faster display.
Determining the Citrix VDA version
To determine the version of a Citrix VDA, issue the WFQuerySessionInformation() function with WFInfoClass set to WFVersion. Here is a C code segment extracted from the Testall.c example program.
HANDLE hServer = WF_CURRENT_SERVER_HANDLE;
DWORD SessionId = WF_CURRENT_SESSION;
LPTSTR pSessionInfo;
DWORD ByteCount;
LPOSVERSIONINFO pVerInfo;
if ( !WFQuerySessionInformation( hServer,
SessionId,
WFVersion,
&pSessionInfo,
&ByteCount ) ) {
_tprintf( TEXT("***WFQuerySessionInformation failed, error
%u\n"),
GetLastError() );
return;
}
pVerInfo = (LPOSVERSIONINFO) pSessionInfo;
_tprintf( TEXT("Version: major %u, minor %u, build %u, CSD: %s\n\"), pVerInfo->dwMajorVersion pVerInfo->dwMinorVersion,pVerInfo->dwBuildNumber);
<!--NeedCopy-->
Results
If this function is successful, it returns specific information about the version of the Citrix VDA that is installed on your server. For example, if Citrix Virtual Apps and Desktop Server 7 2203 is installed, the following information is displayed:
Major 7, minor 32, build 0
Note: The results may vary, depending on the system configuration, and the hotfixes and service packs that are installed on the system.