/************************************************************************* * * regpd.c * * Register APIs for Tds and Pds (transport and protocol drivers) * * Copyright (c) 1998 Microsoft Corporation * * *************************************************************************/ /* * Includes */ #include #include #include #include #include #include /* * External Procedures defined here */ HANDLE WINAPI RegOpenServerW ( LPWSTR pServerName ); HANDLE WINAPI RegOpenServerA ( LPSTR pServerName ); LONG WINAPI RegCloseServer ( HANDLE hServer ); LONG WINAPI RegPdEnumerateW( HANDLE, PWDNAMEW, BOOLEAN, PULONG, PULONG, PPDNAMEW, PULONG ); LONG WINAPI RegPdEnumerateA( HANDLE, PWDNAMEA, BOOLEAN, PULONG, PULONG, PPDNAMEA, PULONG ); LONG WINAPI RegPdCreateW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW, BOOLEAN, PPDCONFIG3W, ULONG ); LONG WINAPI RegPdCreateA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA, BOOLEAN, PPDCONFIG3A, ULONG ); LONG WINAPI RegPdQueryW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW, PPDCONFIG3W, ULONG, PULONG ); LONG WINAPI RegPdQueryA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA, PPDCONFIG3A, ULONG, PULONG ); LONG WINAPI RegPdDeleteW( HANDLE, PWDNAMEW, BOOLEAN, PPDNAMEW ); LONG WINAPI RegPdDeleteA( HANDLE, PWDNAMEA, BOOLEAN, PPDNAMEA ); /* * other internal Procedures used (not defined here) */ VOID CreatePdConfig3( HKEY, PPDCONFIG3, ULONG ); VOID QueryPdConfig3( HKEY, PPDCONFIG3, ULONG ); VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * ); VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * ); VOID PdConfigU2A( PPDCONFIGA, PPDCONFIGW ); VOID PdConfigA2U( PPDCONFIGW, PPDCONFIGA ); VOID PdConfig3U2A( PPDCONFIG3A, PPDCONFIG3W ); VOID PdConfig3A2U( PPDCONFIG3W, PPDCONFIG3A ); VOID PdParamsU2A( PPDPARAMSA, PPDPARAMSW ); VOID PdParamsA2U( PPDPARAMSW, PPDPARAMSA ); VOID AsyncConfigU2A ( PASYNCCONFIGA, PASYNCCONFIGW ); VOID AsyncConfigA2U ( PASYNCCONFIGW, PASYNCCONFIGA ); /***************************************************************************** * * RegOpenServerA * * * ENTRY: * Machine (input) * Name of WinFrame computer to connect to * * EXIT: * handle to a server's Registry (or NULL on error) * ****************************************************************************/ HANDLE WINAPI RegOpenServerA( LPSTR pServerName ) { HKEY hServer; ULONG NameLength; PWCHAR pServerNameW = NULL; if( pServerName == NULL ) { return( (HANDLE)HKEY_LOCAL_MACHINE ); } NameLength = strlen( pServerName ) + 1; pServerNameW = LocalAlloc( 0, NameLength * sizeof(WCHAR) ); if( pServerNameW == NULL ) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return( NULL ); } AnsiToUnicode( pServerNameW, NameLength*sizeof(WCHAR), pServerName ); hServer = RegOpenServerW( pServerNameW ); LocalFree( pServerNameW ); return( (HANDLE) hServer ); } /***************************************************************************** * * RegOpenServerW * * NULL for machine name means local system. * * ENTRY: * Machine (input) * Name of WinFrame computer to connect to * * EXIT: * handle to server's Registry (or NULL on error) * ****************************************************************************/ HANDLE WINAPI RegOpenServerW( LPWSTR pServerName ){ HKEY hKey; if( pServerName == NULL ) return( HKEY_LOCAL_MACHINE ); else { if( RegConnectRegistry( pServerName, HKEY_LOCAL_MACHINE, &hKey ) != ERROR_SUCCESS ){ return( NULL ); } } return( hKey ); } /***************************************************************************** * * RegCloseServer * * Close a connection to a Server Registry. * * ENTRY: * hServer (input) * Handle to close * * EXIT: * ERROR_SUCCESS - no error * ****************************************************************************/ LONG WINAPI RegCloseServer( HANDLE hServer ) { return( RegCloseKey( (HKEY)hServer ) ); } /******************************************************************************* * * RegPdEnumerateA (ANSI stub) * * Returns a list of configured Pds in the registry. * * ENTRY: * * see RegPdEnumerateW * * EXIT: * * see RegPdEnumerateW, plus * * ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed * ******************************************************************************/ LONG WINAPI RegPdEnumerateA( HANDLE hServer, PWDNAMEA pWdName, BOOLEAN bTd, PULONG pIndex, PULONG pEntries, PPDNAMEA pPdName, PULONG pByteCount ) { WDNAMEW WdNameW; PPDNAMEW pBuffer = NULL, pPdNameW; LONG Status; ULONG Count, ByteCountW = (*pByteCount << 1); /* * If the caller supplied a buffer and the length is not 0, * allocate a corresponding (*2) buffer for UNICODE strings. */ if ( pPdName && ByteCountW ) { if ( !(pBuffer = LocalAlloc(0, ByteCountW)) ) return ( ERROR_NOT_ENOUGH_MEMORY ); } /* * Convert ANSI WdName to UNICODE. */ AnsiToUnicode( WdNameW, sizeof(WDNAMEW), pWdName ); /* * Enumerate Pds */ pPdNameW = pBuffer; Status = RegPdEnumerateW( hServer, WdNameW, bTd, pIndex, pEntries, pPdNameW, &ByteCountW ); /* * Always /2 the resultant ByteCount (whether sucessful or not). */ *pByteCount = (ByteCountW >> 1); /* * If the function completed sucessfully and caller * (and stub) defined a buffer to copy into, perform conversion * from UNICODE to ANSI. Note: sucessful return may have copied * 0 items from registry (end of enumeration), denoted by *pEntries * == 0. */ if ( ((Status == ERROR_SUCCESS) || (Status == ERROR_NO_MORE_ITEMS)) && pPdNameW && pPdName ) { for ( Count = *pEntries; Count; Count-- ) { UnicodeToAnsi( pPdName, sizeof(PDNAMEA), pPdNameW ); (char*)pPdName += sizeof(PDNAMEA); (char*)pPdNameW += sizeof(PDNAMEW); } } /* * If we defined a buffer, free it now, then return the status * of the Reg...EnumerateW function call. */ if ( pBuffer ) LocalFree(pBuffer); return ( Status ); } /******************************************************************************* * * RegPdEnumerateW (UNICODE) * * Returns a list of configured Pds in the registry. * * ENTRY: * * hServer (input) * Handle to WinFrame Server * pWdName (input) * Points to the wdname to enumerate pds for * bTd (input) * TRUE to enumerate Transport Drivers (Tds), * FALSE to enumerate Protocol Drivers (Pds) * pIndex (input/output) * Specifies the subkey index for the \Citrix\Wds\\ * subkeys in the registry. Should be set to 0 for the initial call, * and supplied again (as modified by this function) for multi-call * enumeration. * pEntries (input/output) * Points to a variable specifying the number of entries requested. * If the number requested is 0xFFFFFFFF, the function returns as * many entries as possible. When the function finishes successfully, * the variable pointed to by the pEntries parameter contains the * number of entries actually read. * pPdName (input) * Points to the buffer to receive the enumeration results, which are * returned as an array of PDNAME structures. If this parameter is * NULL, then no data will be copied, but just an enumeration count will * be made. * pByteCount (input/output) * Points to a variable that specifies the size, in bytes, of the * pPdName parameter. If the buffer is too small to receive even * one entry, the function returns an error code (ERROR_OUTOFMEMORY) * and this variable receives the required size of the buffer for a * single subkey. When the function finishes sucessfully, the variable * pointed to by the pByteCount parameter contains the number of bytes * actually stored in pPdName. * * EXIT: * * "No Error" codes: * ERROR_SUCCESS - The enumeration completed as requested and there * are more Pds subkeys (PDNAMEs) to be read. * ERROR_NO_MORE_ITEMS - The enumeration completed as requested and there * are no more Pds subkeys (PDNAMEs) to be read. * * "Error" codes: * ERROR_OUTOFMEMORY - The pPdName buffer is too small for even one entry. * ERROR_CANTOPEN - The \Citrix\Wds\\ key can't be opened. * ******************************************************************************/ LONG WINAPI RegPdEnumerateW( HANDLE hServer, PWDNAMEW pWdName, BOOLEAN bTd, PULONG pIndex, PULONG pEntries, PPDNAMEW pPdName, PULONG pByteCount ) { LONG Status; HKEY Handle; ULONG Count; ULONG i; HKEY hkey_local_machine; WCHAR KeyString[256]; if( hServer == NULL ) hkey_local_machine = HKEY_LOCAL_MACHINE; else hkey_local_machine = hServer; /* * Get the number of names to return */ Count = pPdName ? min( *pByteCount / sizeof(PDNAME), *pEntries ) : (ULONG) -1; *pEntries = *pByteCount = 0; /* * Make sure buffer is big enough for at least one name */ if ( Count == 0 ) { *pByteCount = sizeof(PDNAME); return( ERROR_OUTOFMEMORY ); } /* * Open registry (LOCAL_MACHINE\....\Citrix\Wds\\) */ wcscpy( KeyString, WD_REG_NAME ); wcscat( KeyString, L"\\" ); wcscat( KeyString, pWdName ); wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME ); if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0, KEY_ENUMERATE_SUB_KEYS, &Handle ) != ERROR_SUCCESS ) { return( ERROR_CANTOPEN ); } /* * Get list of Tds or Pds */ for ( i = 0; i < Count; i++ ) { PDNAME PdName; if ( (Status = RegEnumKey(Handle, *pIndex, PdName, sizeof(PDNAME)/sizeof(TCHAR) )) != ERROR_SUCCESS ) break; /* * If caller supplied a buffer, then copy the PdName * and increment the pointer and byte count. Always increment the * entry count and index for the next iteration. */ if ( pPdName ) { wcscpy( pPdName, PdName ); (char*)pPdName += sizeof(PDNAME); *pByteCount += sizeof(PDNAME); } (*pEntries)++; (*pIndex)++; } /* * Close registry */ RegCloseKey( Handle ); return( Status ); } /******************************************************************************* * * RegPdCreateA (ANSI stub) * * Creates a new Pd in the registry or updates an existing entry. * (See RegPdCreateW) * * ENTRY: * * see RegPdCreateW * * EXIT: * * see RegPdCreateW * ******************************************************************************/ LONG WINAPI RegPdCreateA( HANDLE hServer, PWDNAMEA pWdName, BOOLEAN bTd, PPDNAMEA pPdName, BOOLEAN bCreate, PPDCONFIG3A pPdConfig, ULONG PdConfigLength ) { PDNAMEW PdNameW; WDNAMEW WdNameW; PDCONFIG3W PdConfig3W; /* * Validate target buffer size. */ if ( PdConfigLength < sizeof(PDCONFIG3A) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Convert ANSI WdName and PdName to UNICODE. */ AnsiToUnicode( WdNameW, sizeof(WDNAMEW), pWdName ); AnsiToUnicode( PdNameW, sizeof(PDNAMEW), pPdName ); /* * Copy PDCONFIG3A elements to PDCONFIG3W elements. */ PdConfig3A2U( &PdConfig3W, pPdConfig ); /* * Call RegPdCreateW & return it's status. */ return ( RegPdCreateW( hServer, WdNameW, bTd, PdNameW, bCreate, &PdConfig3W, sizeof(PdConfig3W)) ); } /******************************************************************************* * * RegPdCreateW (UNICODE) * * Creates a new Pd in the registry or updates an existing entry. The * state of the bCreate flag determines whether this function will expect * to create a new Pd entry (bCreate == TRUE) or expects to update an * existing entry (bCreate == FALSE). * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWdName (input) * Points to the wdname to create pd for * bTd (input) * TRUE to create a Transport Driver (Td), * FALSE to create a Protocol Driver (Pd) * pPdName (input) * Name of a new or exisiting Pd in the registry. * bCreate (input) * TRUE if this is a creation of a new Pd * FALSE if this is an update to an existing Pd * pPdConfig (input) * Pointer to a PDCONFIG3 structure containing configuration * information for the specified Pd name. * PdConfigLength (input) * Specifies the length in bytes of the pPdConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * * ERROR_INSUFFICIENT_BUFFER - pPdConfig buffer too small * ERROR_FILE_NOT_FOUND - can't open ...\Citrix\Wds\\ key * ERROR_CANNOT_MAKE - can't create Pd key (registry problem) * ERROR_ALREADY_EXISTS - create; but Pd key was already present * ERROR_CANTOPEN - update; but Pd key could not be opened * ******************************************************************************/ LONG WINAPI RegPdCreateW( HANDLE hServer, PWDNAMEW pWdName, BOOLEAN bTd, PPDNAMEW pPdName, BOOLEAN bCreate, PPDCONFIG3W pPdConfig, ULONG PdConfigLength ) { HKEY Handle; HKEY Handle1; DWORD Disp; HKEY hkey_local_machine; WCHAR KeyString[256]; if( hServer == NULL ) hkey_local_machine = HKEY_LOCAL_MACHINE; else hkey_local_machine = hServer; /* * Validate length of buffer */ if ( PdConfigLength < sizeof(PDCONFIG3) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Open registry (LOCAL_MACHINE\....\Citrix\Wds\\) */ wcscpy( KeyString, WD_REG_NAME ); wcscat( KeyString, L"\\" ); wcscat( KeyString, pWdName ); wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME ); if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0, KEY_ALL_ACCESS, &Handle1 ) != ERROR_SUCCESS ) { return( ERROR_FILE_NOT_FOUND ); } if ( bCreate ) { /* * Create requested: create a registry key for the specified * Pd name. */ if ( RegCreateKeyEx( Handle1, pPdName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &Handle, &Disp ) != ERROR_SUCCESS ) { RegCloseKey( Handle1 ); return( ERROR_CANNOT_MAKE ); } /* * If an existing key was returned instead of a new one being * created, return error (don't update). */ if ( Disp != REG_CREATED_NEW_KEY ) { RegCloseKey( Handle1 ); RegCloseKey( Handle ); return( ERROR_ALREADY_EXISTS ); } } else { /* * Update requested: open the registry key for the specified * Pd name. */ if ( RegOpenKeyEx( Handle1, pPdName, 0, KEY_ALL_ACCESS, &Handle ) != ERROR_SUCCESS ) { RegCloseKey( Handle1 ); return( ERROR_CANTOPEN ); } } RegCloseKey( Handle1 ); /* * Save Pd information */ CreatePdConfig3( Handle, pPdConfig, 0 ); /* * Close registry handle */ RegCloseKey( Handle ); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegPdQueryA (ANSI stub) * * Query configuration information of a Pd in the registry. * * ENTRY: * * see RegPdQueryW * * EXIT: * * see RegPdQueryW * ******************************************************************************/ LONG WINAPI RegPdQueryA( HANDLE hServer, PWDNAMEA pWdName, BOOLEAN bTd, PPDNAMEA pPdName, PPDCONFIG3A pPdConfig, ULONG PdConfigLength, PULONG pReturnLength ) { PDNAMEW PdNameW; WDNAMEW WdNameW; PDCONFIG3W PdConfig3W; LONG Status; ULONG ReturnLengthW; /* * Validate length and zero-initialize the destination * PDCONFIG3A structure. */ if ( PdConfigLength < sizeof(PDCONFIG3A) ) return( ERROR_INSUFFICIENT_BUFFER ); memset(pPdConfig, 0, PdConfigLength); /* * Convert ANSI WdName and PdName to UNICODE. */ AnsiToUnicode(WdNameW, sizeof(WDNAMEW), pWdName); AnsiToUnicode(PdNameW, sizeof(PDNAMEW), pPdName); /* * Query Pd. */ if ( (Status = RegPdQueryW( hServer, WdNameW, bTd, PdNameW, &PdConfig3W, sizeof(PDCONFIG3W), &ReturnLengthW)) != ERROR_SUCCESS ) return ( Status ); /* * Copy PDCONFIG3W elements to PDCONFIG3A elements. */ PdConfig3U2A( pPdConfig, &PdConfig3W ); *pReturnLength = sizeof(PDCONFIG3A); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegPdQueryW (UNICODE) * * Query configuration information of a Pd in the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWdName (input) * Points to the wdname to query pd for * bTd (input) * TRUE to query a Transport Driver (Td), * FALSE to query a Protocol Driver (Pd) * pPdName (input) * Name of an exisiting Pd in the registry. * pPdConfig (input) * Pointer to a PDCONFIG3 structure that will receive * information about the specified Pd name. * PdConfigLength (input) * Specifies the length in bytes of the pPdConfig buffer. * pReturnLength (output) * Receives the number of bytes placed in the pPdConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * ******************************************************************************/ LONG WINAPI RegPdQueryW( HANDLE hServer, PWDNAMEW pWdName, BOOLEAN bTd, PPDNAMEW pPdName, PPDCONFIG3W pPdConfig, ULONG PdConfigLength, PULONG pReturnLength ) { HKEY Handle; HKEY Handle1; HKEY hkey_local_machine; WCHAR KeyString[256]; if( hServer == NULL ) hkey_local_machine = HKEY_LOCAL_MACHINE; else hkey_local_machine = hServer; /* * Validate length and zero-initialize the destination * PDCONFIG3A structure. */ if ( PdConfigLength < sizeof(PDCONFIG3) ) return( ERROR_INSUFFICIENT_BUFFER ); memset(pPdConfig, 0, PdConfigLength); /* * Open registry (LOCAL_MACHINE\....\Citrix\Wds\\) */ wcscpy( KeyString, WD_REG_NAME ); wcscat( KeyString, L"\\" ); wcscat( KeyString, pWdName ); wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME ); if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0, KEY_READ, &Handle1 ) != ERROR_SUCCESS ) { return( ERROR_FILE_NOT_FOUND ); } /* * Now try to open the specified Pd */ if ( RegOpenKeyEx( Handle1, pPdName, 0, KEY_READ, &Handle ) != ERROR_SUCCESS ) { RegCloseKey( Handle1 ); return( ERROR_FILE_NOT_FOUND ); } RegCloseKey( Handle1 ); /* * Query PDCONFIG3 Structure */ QueryPdConfig3( Handle, pPdConfig, 0 ); /* * Close registry */ RegCloseKey( Handle ); *pReturnLength = sizeof(PDCONFIG3); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegPdDeleteA (ANSI stub) * * Deletes a Pd from the registry. * * ENTRY: * * see RegPdDeleteW * * EXIT: * * see RegPdDeleteW * ******************************************************************************/ LONG WINAPI RegPdDeleteA( HANDLE hServer, PWDNAMEA pWdName, BOOLEAN bTd, PPDNAMEA pPdName ) { WDNAMEW WdNameW; PDNAMEW PdNameW; AnsiToUnicode( WdNameW, sizeof(WdNameW), pWdName ); AnsiToUnicode( PdNameW, sizeof(PdNameW), pPdName ); return ( RegPdDeleteW ( hServer, WdNameW, bTd, PdNameW ) ); } /******************************************************************************* * * RegPdDeleteW (UNICODE) * * Deletes a Pd from the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWdName (input) * Points to the wdname to delete pd from * bTd (input) * TRUE to delete a Transport Driver (Td), * FALSE to delete a Protocol Driver (Pd) * pPdName (input) * Name of a Pd to delete from the registry. * * EXIT: * ERROR_SUCCESS - no error * ******************************************************************************/ LONG WINAPI RegPdDeleteW( HANDLE hServer, PWDNAMEW pWdName, BOOLEAN bTd, PPDNAMEW pPdName ) { LONG Status; HKEY Handle; HKEY Handle1; HKEY hkey_local_machine; WCHAR KeyString[256]; if( hServer == NULL ) hkey_local_machine = HKEY_LOCAL_MACHINE; else hkey_local_machine = hServer; /* * Open registry (LOCAL_MACHINE\....\Citrix\Wds\\) */ wcscpy( KeyString, WD_REG_NAME ); wcscat( KeyString, L"\\" ); wcscat( KeyString, pWdName ); wcscat( KeyString, bTd ? TD_REG_NAME : PD_REG_NAME ); if ( RegOpenKeyEx( hkey_local_machine, KeyString, 0, KEY_READ, &Handle ) != ERROR_SUCCESS ) { return( ERROR_FILE_NOT_FOUND ); } /* * Now try to open the specified Pd */ if ( RegOpenKeyEx( Handle, pPdName, 0, KEY_READ, &Handle1 ) != ERROR_SUCCESS ) { RegCloseKey( Handle ); return( ERROR_FILE_NOT_FOUND ); } /* * Close the Pd key handle, delete the Pd, * and close the parent handle. */ RegCloseKey( Handle1 ); Status = RegDeleteKey( Handle, pPdName ); RegCloseKey( Handle ); return( Status ); }