diff --git a/cpp/wiipair/.cproject b/cpp/wiipair/.cproject new file mode 100644 index 0000000..1d598c5 --- /dev/null +++ b/cpp/wiipair/.cproject @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cpp/wiipair/.project b/cpp/wiipair/.project new file mode 100644 index 0000000..27bf4e7 --- /dev/null +++ b/cpp/wiipair/.project @@ -0,0 +1,71 @@ + + + Wiipair + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${workspace_loc:/Wiiscan/Release} + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs new file mode 100644 index 0000000..31dfb57 --- /dev/null +++ b/cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs @@ -0,0 +1,25 @@ +eclipse.preferences.version=1 +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/CPLUS_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/CPLUS_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/appendContributed=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/CPLUS_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/CPLUS_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1313294112/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.1147005981/appendContributed=true diff --git a/cpp/wiipair/Debug/wiipair.exe b/cpp/wiipair/Debug/wiipair.exe new file mode 100644 index 0000000..d8002b3 Binary files /dev/null and b/cpp/wiipair/Debug/wiipair.exe differ diff --git a/cpp/wiipair/Release/wiipair.exe b/cpp/wiipair/Release/wiipair.exe new file mode 100644 index 0000000..2442cc2 Binary files /dev/null and b/cpp/wiipair/Release/wiipair.exe differ diff --git a/cpp/wiipair/include/BluetoothAPIs.h b/cpp/wiipair/include/BluetoothAPIs.h new file mode 100644 index 0000000..39ef8eb --- /dev/null +++ b/cpp/wiipair/include/BluetoothAPIs.h @@ -0,0 +1,1540 @@ + +// +// Copyright 2002 - Microsoft Corporation +// +// Created By: +// Geoff Pease (GPease) 12-JAN-2002 +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define BLUETOOTH_MAX_NAME_SIZE (248) +#define BLUETOOTH_MAX_PASSKEY_SIZE (16) +#define BLUETOOTH_MAX_PASSKEY_BUFFER_SIZE (BLUETOOTH_MAX_PASSKEY_SIZE + 1) + +#ifdef __cplusplus +extern "C" { +#endif + +// *************************************************************************** +// +// Bluetooth Address +// +// *************************************************************************** + +typedef ULONGLONG BTH_ADDR; + +typedef struct _BLUETOOTH_ADDRESS { + union { + BTH_ADDR ullLong; // easier to compare again BLUETOOTH_NULL_ADDRESS + BYTE rgBytes[ 6 ]; // easier to format when broken out + }; + +} BLUETOOTH_ADDRESS_STRUCT; + +#define BLUETOOTH_ADDRESS BLUETOOTH_ADDRESS_STRUCT + +#define BLUETOOTH_NULL_ADDRESS ( (ULONGLONG) 0x0 ) + +// *************************************************************************** +// +// Radio Enumeration +// +// Description: +// This group of APIs enumerates the installed Bluetooth radios. +// +// Sample Usage: +// HANDLE hRadio; +// BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(btfrp) }; +// +// HBLUETOOTH_RADIO_FIND hFind = BluetoothFindFirstRadio( &btfrp, &hRadio ); +// if ( NULL != hFind ) +// { +// do +// { +// // +// // TODO: Do something with the radio handle. +// // +// +// CloseHandle( hRadio ); +// +// } while( BluetoothFindNextRadio( hFind, &hRadio ) ); +// +// BluetoothFindRadioClose( hFind ); +// } +// +// *************************************************************************** + +typedef struct _BLUETOOTH_FIND_RADIO_PARAMS { + DWORD dwSize; // IN sizeof this structure + +} BLUETOOTH_FIND_RADIO_PARAMS; + +typedef HANDLE HBLUETOOTH_RADIO_FIND; + +// +// Description: +// Begins the enumeration of local Bluetooth radios. +// +// Parameters: +// pbtfrp +// A pointer to a BLUETOOTH_FIND_RADIO_PARAMS structure. The dwSize +// member of this structure must match the sizeof the of the structure. +// +// phRadio +// A pointer where the first radio HANDLE enumerated will be returned. +// +// Return Values: +// NULL +// Error opening radios or no devices found. Use GetLastError() for +// more info. +// +// ERROR_INVALID_PARAMETER +// pbtfrp parameter is NULL. +// +// ERROR_REVISION_MISMATCH +// The pbtfrp structure is not the right length. +// +// ERROR_OUTOFMEMORY +// Out of memory. +// +// other Win32 errors. +// +// any other +// Success. The return handle is valid and phRadio points to a valid handle. +// +HBLUETOOTH_RADIO_FIND +WINAPI +BluetoothFindFirstRadio( + BLUETOOTH_FIND_RADIO_PARAMS * pbtfrp, + HANDLE * phRadio + ); + +// +// Description: +// Finds the next installed Bluetooth radio. +// +// Parameters: +// hFind +// The handle returned by BluetoothFindFirstRadio(). +// +// phRadio +// A pointer where the next radio HANDLE enumerated will be returned. +// +// Return Values: +// TRUE +// Next device succesfully found. pHandleOut points to valid handle. +// +// FALSE +// No device found. pHandleOut points to an invalid handle. Call +// GetLastError() for more details. +// +// ERROR_INVALID_HANDLE +// The handle is NULL. +// +// ERROR_NO_MORE_ITEMS +// No more radios found. +// +// ERROR_OUTOFMEMORY +// Out of memory. +// +// other Win32 errors +// +BOOL +WINAPI +BluetoothFindNextRadio( + HBLUETOOTH_RADIO_FIND hFind, + HANDLE * phRadio + ); + +// +// Description: +// Closes the enumeration handle. +// +// Parameters +// hFind +// The handle returned by BluetoothFindFirstRadio(). +// +// Return Values: +// TRUE +// Handle succesfully closed. +// +// FALSE +// Failure. Check GetLastError() for details. +// +// ERROR_INVALID_HANDLE +// The handle is NULL. +// +BOOL +WINAPI +BluetoothFindRadioClose( + HBLUETOOTH_RADIO_FIND hFind + ); + +// *************************************************************************** +// +// Radio Information +// +// *************************************************************************** + +typedef struct _BLUETOOTH_RADIO_INFO { + DWORD dwSize; // Size, in bytes, of this entire data structure + + BLUETOOTH_ADDRESS address; // Address of the local radio + + WCHAR szName[ BLUETOOTH_MAX_NAME_SIZE ]; // Name of the local radio + + ULONG ulClassofDevice; // Class of device for the local radio + + USHORT lmpSubversion; // lmpSubversion, manufacturer specifc. + USHORT manufacturer; // Manufacturer of the radio, BTH_MFG_Xxx value. For the most up to date + // list, goto the Bluetooth specification website and get the Bluetooth + // assigned numbers document. +} BLUETOOTH_RADIO_INFO, *PBLUETOOTH_RADIO_INFO; + +// +// Description: +// Retrieves the information about the radio represented by the handle. +// +// Parameters: +// hRadio +// Handle to a local radio retrieved through BluetoothFindFirstRadio() +// et al or SetupDiEnumerateDeviceInterfaces() +// +// pRadioInfo +// Radio information to be filled in. The dwSize member must match the +// size of the structure. +// +// Return Values: +// ERROR_SUCCESS +// The information was retrieved successfully. +// +// ERROR_INVALID_PARAMETER +// pRadioInfo or hRadio is NULL. +// +// ERROR_REVISION_MISMATCH +// pRadioInfo->dwSize is invalid. +// +// other Win32 error codes. +// +DWORD +WINAPI +BluetoothGetRadioInfo( + HANDLE hRadio, + PBLUETOOTH_RADIO_INFO pRadioInfo + ); + +// *************************************************************************** +// +// Device Information Stuctures +// +// *************************************************************************** + +typedef struct _BLUETOOTH_DEVICE_INFO { + DWORD dwSize; // size, in bytes, of this structure - must be the sizeof(BLUETOOTH_DEVICE_INFO) + + BLUETOOTH_ADDRESS Address; // Bluetooth address + + ULONG ulClassofDevice; // Bluetooth "Class of Device" + + BOOL fConnected; // Device connected/in use + BOOL fRemembered; // Device remembered + BOOL fAuthenticated; // Device authenticated/paired/bonded + + SYSTEMTIME stLastSeen; // Last time the device was seen + SYSTEMTIME stLastUsed; // Last time the device was used for other than RNR, inquiry, or SDP + + WCHAR szName[ BLUETOOTH_MAX_NAME_SIZE ]; // Name of the device + +} BLUETOOTH_DEVICE_INFO_STRUCT; + +#define BLUETOOTH_DEVICE_INFO BLUETOOTH_DEVICE_INFO_STRUCT + +typedef BLUETOOTH_DEVICE_INFO * PBLUETOOTH_DEVICE_INFO; + +// *************************************************************************** +// +// Device Enumeration +// +// Description: +// Enumerates the Bluetooth devices. The types of returned device depends +// on the flags set in the BLUETOOTH_DEVICE_SEARCH_PARAMS (see structure +// definition for details). +// +// Sample Usage: +// HBLUETOOTH_DEVICE_FIND hFind; +// BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { sizeof(btsp) }; +// BLUETOOTH_DEVICE_INFO btdi = { sizeof(btdi) }; +// +// btsp.fReturnAuthenticated = TRUE; +// btsp.fReturnRemembered = TRUE; +// +// hFind = BluetoothFindFirstDevice( &btsp, &btdi ); +// if ( NULL != hFind ) +// { +// do +// { +// // +// // TODO: Do something useful with the device info. +// // +// +// } while( BluetoothFindNextDevice( hFind, &btdi ) ); +// +// BluetoothFindDeviceClose( hFind ); +// } +// +// *************************************************************************** + +typedef struct _BLUETOOTH_DEVICE_SEARCH_PARAMS { + DWORD dwSize; // IN sizeof this structure + + BOOL fReturnAuthenticated; // IN return authenticated devices + BOOL fReturnRemembered; // IN return remembered devices + BOOL fReturnUnknown; // IN return unknown devices + BOOL fReturnConnected; // IN return connected devices + + BOOL fIssueInquiry; // IN issue a new inquiry + UCHAR cTimeoutMultiplier; // IN timeout for the inquiry + + HANDLE hRadio; // IN handle to radio to enumerate - NULL == all radios will be searched + +} BLUETOOTH_DEVICE_SEARCH_PARAMS; + +typedef HANDLE HBLUETOOTH_DEVICE_FIND; + +// +// Description: +// Begins the enumeration of Bluetooth devices. +// +// Parameters: +// pbtsp +// A pointer to a BLUETOOTH_DEVICE_SEARCH_PARAMS structure. This +// structure contains the flags and inputs used to conduct the search. +// See BLUETOOTH_DEVICE_SEARCH_PARAMS for details. +// +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure to return information +// about the first Bluetooth device found. Note that the dwSize member +// of the structure must be the sizeof(BLUETOOTH_DEVICE_INFO) before +// calling because the APIs hast to know the size of the buffer being +// past in. The dwSize member must also match the exact +// sizeof(BLUETOOTH_DEVICE_INFO) or the call will fail. +// +// Return Values: +// NULL +// Error opening radios or not devices found. Use GetLastError for more info. +// +// ERROR_INVALID_PARAMETER +// pbtsp parameter or pbtdi parameter is NULL. +// +// ERROR_REVISION_MISMATCH +// The pbtfrp structure is not the right length. +// +// other Win32 errors +// +// any other value +// Success. The return handle is valid and pbtdi points to valid data. +// +HBLUETOOTH_DEVICE_FIND +WINAPI +BluetoothFindFirstDevice( + BLUETOOTH_DEVICE_SEARCH_PARAMS * pbtsp, + BLUETOOTH_DEVICE_INFO * pbtdi + ); + +// +// Description: +// Finds the next Bluetooth device in the enumeration. +// +// Parameters: +// hFind +// The handle returned from BluetoothFindFirstDevice(). +// +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure to return information +// about the first Bluetooth device found. Note that the dwSize member +// of the structure must be the sizeof(BLUETOOTH_DEVICE_INFO) before +// calling because the APIs hast to know the size of the buffer being +// past in. The dwSize member must also match the exact +// sizeof(BLUETOOTH_DEVICE_INFO) or the call will fail. +// +// Return Values: +// TRUE +// Next device succesfully found. pHandleOut points to valid handle. +// +// FALSE +// No device found. pHandleOut points to an invalid handle. Call +// GetLastError() for more details. +// +// ERROR_INVALID_HANDLE +// The handle is NULL. +// +// ERROR_NO_MORE_ITEMS +// No more radios found. +// +// ERROR_OUTOFMEMORY +// Out of memory. +// +// other Win32 errors +// +BOOL +WINAPI +BluetoothFindNextDevice( + HBLUETOOTH_DEVICE_FIND hFind, + BLUETOOTH_DEVICE_INFO * pbtdi + ); + +// +// Description: +// Closes the enumeration handle. +// +// Parameters: +// hFind +// The handle returned from BluetoothFindFirstDevice(). +// +// Return Values: +// TRUE +// Handle succesfully closed. +// +// FALSE +// Failure. Check GetLastError() for details. +// +// ERROR_INVALID_HANDLE +// The handle is NULL. +// +BOOL +WINAPI +BluetoothFindDeviceClose( + HBLUETOOTH_DEVICE_FIND hFind + ); + +// +// Description: +// Retrieves information about a remote device. +// +// Fill in the dwSize and the Address members of the pbtdi structure +// being passed in. On success, the rest of the members will be filled +// out with the information that the system knows. +// +// Parameters: +// hRadio +// Handle to a local radio retrieved through BluetoothFindFirstRadio() +// et al or SetupDiEnumerateDeviceInterfaces() +// +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure to return information +// about the first Bluetooth device found. The dwSize member of the +// structure must be the sizeof the structure in bytes. The Address +// member must be filled out with the Bluetooth address of the remote +// device. +// +// Return Values: +// ERROR_SUCCESS +// Success. Information returned. +// +// ERROR_REVISION_MISMATCH +// The size of the BLUETOOTH_DEVICE_INFO isn't compatible. Check +// the dwSize member of the BLUETOOTH_DEVICE_INFO structure you +// passed in. +// +// ERROR_NOT_FOUND +// The radio is not known by the system or the Address field of +// the BLUETOOTH_DEVICE_INFO structure is all zeros. +// +// ERROR_INVALID_PARAMETER +// pbtdi is NULL. +// +// other error codes +// +DWORD +WINAPI +BluetoothGetDeviceInfo( + HANDLE hRadio, + BLUETOOTH_DEVICE_INFO * pbtdi + ); + +// +// Description: +// Updates the computer local cache about the device. +// +// Parameters: +// pbtdi +// A pointer to the BLUETOOTH_DEVICE_INFO structure to be updated. +// The following members must be valid: +// dwSize +// Must match the size of the structure. +// Address +// Must be a previously found radio address. +// szName +// New name to be stored. +// +// Return Values: +// ERROR_SUCCESS +// The device information was updated successfully. +// +// ERROR_INVALID_PARAMETER +// pbtdi is NULL. +// +// ERROR_REVISION_MISMATCH +// pbtdi->dwSize is invalid. +// +// other Win32 error codes. +// +DWORD +WINAPI +BluetoothUpdateDeviceRecord( + BLUETOOTH_DEVICE_INFO * pbtdi + ); + +// +// Description: +// Delete the authentication (aka "bond") between the computer and the +// device. Also purges any cached information about the device. +// +// Return Values: +// ERROR_SUCCESS +// The device was removed successfully. +// +// ERROR_NOT_FOUND +// The device was not found. If no Bluetooth radio is installed, +// the devices could not be enumerated or removed. +// +DWORD +WINAPI +BluetoothRemoveDevice( + BLUETOOTH_ADDRESS * pAddress + ); + +// *************************************************************************** +// +// Device Picker Dialog +// +// Description: +// Invokes a common dialog for selecting Bluetooth devices. The list +// of devices displayed to the user is determined by the flags and +// settings the caller specifies in the BLUETOOTH_SELECT_DEVICE_PARAMS +// (see structure definition for more details). +// +// If BluetoothSelectDevices() returns TRUE, the caller must call +// BluetoothSelectDevicesFree() or memory will be leaked within the +// process. +// +// Sample Usage: +// +// BLUETOOTH_SELECT_DEVICE_PARAMS btsdp = { sizeof(btsdp) }; +// +// btsdp.hwndParent = hDlg; +// btsdp.fShowUnknown = TRUE; +// btsdp.fAddNewDeviceWizard = TRUE; +// +// BOOL b = BluetoothSelectDevices( &btsdp ); +// if ( b ) +// { +// BLUETOOTH_DEVICE_INFO * pbtdi = btsdp.pDevices; +// for ( ULONG cDevice = 0; cDevice < btsdp.cNumDevices; cDevice ++ ) +// { +// if ( pbtdi->fAuthenticated || pbtdi->fRemembered ) +// { +// // +// // TODO: Do something usefull with the device info +// // +// } +// +// pbtdi = (BLUETOOTH_DEVICE_INFO *) ((LPBYTE)pbtdi + pbtdi->dwSize); +// } +// +// BluetoothSelectDevicesFree( &btsdp ); +// } +// +// *************************************************************************** + + +typedef struct _BLUETOOTH_COD_PAIRS { + ULONG ulCODMask; // ClassOfDevice mask to compare + LPCWSTR pcszDescription; // Descriptive string of mask + +} BLUETOOTH_COD_PAIRS; + +typedef BOOL (WINAPI *PFN_DEVICE_CALLBACK)(LPVOID pvParam, PBLUETOOTH_DEVICE_INFO pDevice); + +typedef struct _BLUETOOTH_SELECT_DEVICE_PARAMS { + DWORD dwSize; // IN sizeof this structure + + ULONG cNumOfClasses; // IN Number in prgClassOfDevice - if ZERO search for all devices + BLUETOOTH_COD_PAIRS * prgClassOfDevices; // IN Array of CODs to find. + + LPWSTR pszInfo; // IN If not NULL, sets the "information" text + + HWND hwndParent; // IN parent window - NULL == no parent + + BOOL fForceAuthentication; // IN If TRUE, authenication will be forced before returning + BOOL fShowAuthenticated; // IN If TRUE, authenticated devices will be shown in the picker + BOOL fShowRemembered; // IN If TRUE, remembered devices will be shown in the picker + BOOL fShowUnknown; // IN If TRUE, unknown devices that are not authenticated or "remember" will be shown. + + BOOL fAddNewDeviceWizard; // IN If TRUE, invokes the add new device wizard. + BOOL fSkipServicesPage; // IN If TRUE, skips the "Services" page in the wizard. + + PFN_DEVICE_CALLBACK pfnDeviceCallback; // IN If non-NULL, a callback that will be called for each device. If the + // the callback returns TRUE, the item will be added. If the callback is + // is FALSE, the item will not be shown. + LPVOID pvParam; // IN Parameter to be passed to pfnDeviceCallback as the pvParam. + + DWORD cNumDevices; // IN number calles wants - ZERO == no limit. + // OUT the number of devices returned. + + PBLUETOOTH_DEVICE_INFO pDevices; // OUT pointer to an array for BLUETOOTH_DEVICE_INFOs. + // call BluetoothSelectDevicesFree() to free + +} BLUETOOTH_SELECT_DEVICE_PARAMS; + +// +// Description: +// (See header above) +// +// Return Values: +// TRUE +// User selected a device. pbtsdp->pDevices points to valid data. +// Caller should check the fAuthenticated && fRemembered flags to +// determine which devices we successfuly authenticated or valid +// selections by the user. +// +// Use BluetoothSelectDevicesFree() to free the nessecary data +// such as pDevices only if this function returns TRUE. +// +// FALSE +// No valid data returned. Call GetLastError() for possible details +// of the failure. If GLE() is: +// +// ERROR_CANCELLED +// The user cancelled the request. +// +// ERROR_INVALID_PARAMETER +// The pbtsdp is NULL. +// +// ERROR_REVISION_MISMATCH +// The structure passed in as pbtsdp is of an unknown size. +// +// other WIN32 errors +// +BOOL +WINAPI +BluetoothSelectDevices( + BLUETOOTH_SELECT_DEVICE_PARAMS * pbtsdp + ); + +// +// Description: +// This function should only be called if BluetoothSelectDevices() returns +// TRUE. This function will free any memory and resource returned by the +// BluetoothSelectDevices() in the BLUETOOTH_SELECT_DEVICE_PARAMS +// structure. +// +// Return Values: +// TRUE +// Success. +// +// FALSE +// Nothing to free. +// +BOOL +WINAPI +BluetoothSelectDevicesFree( + BLUETOOTH_SELECT_DEVICE_PARAMS * pbtsdp + ); + +// *************************************************************************** +// +// Device Property Sheet +// +// *************************************************************************** + +// +// Description: +// Invokes the CPLs device info property sheet. +// +// Parameters: +// hwndParent +// HWND to parent the property sheet. +// +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure of the device +// to be displayed. +// +// Return Values: +// TRUE +// The property page was successfully displayed. +// +// FALSE +// Failure. The property page was not displayed. Check GetLastError +// for more details. +// +BOOL +WINAPI +BluetoothDisplayDeviceProperties( + HWND hwndParent, + BLUETOOTH_DEVICE_INFO * pbtdi + ); + + +// *************************************************************************** +// +// Radio Authentication +// +// *************************************************************************** + +// +// Description: +// Sends an authentication request to a remote device. +// +// There are two modes of operation. "Wizard mode" and "Blind mode." +// +// "Wizard mode" is invoked when the pszPasskey is NULL. This will cause +// the "Bluetooth Connection Wizard" to be invoked. The user will be +// prompted to enter a passkey during the wizard after which the +// authentication request will be sent. The user will see the success +// or failure of the authentication attempt. The user will also be +// given the oppurtunity to try to fix a failed authentication. +// +// "Blind mode" is invoked when the pszPasskey is non-NULL. This will +// cause the computer to send a authentication request to the remote +// device. No UI is ever displayed. The Bluetooth status code will be +// mapped to a Win32 Error code. +// +// Parameters: +// +// hwndParent +// The window to parent the authentication wizard. If NULL, the +// wizard will be parented off the desktop. +// +// hRadio +// A valid local radio handle or NULL. If NULL, then all radios will +// be tired. If any of the radios succeed, then the call will +// succeed. +// +// pbtdi +// BLUETOOTH_DEVICE_INFO record of the device to be authenticated. +// +// pszPasskey +// PIN to be used to authenticate the device. If NULL, then UI is +// displayed and the user steps through the authentication process. +// If not NULL, no UI is shown. The passkey is NOT NULL terminated. +// +// ulPasskeyLength +// Length of szPassKey in bytes. The length must be less than or +// equal to BLUETOOTH_MAX_PASSKEY_SIZE * sizeof(WCHAR). +// +// Return Values: +// +// ERROR_SUCCESS +// Success. +// +// ERROR_CANCELLED +// User aborted the operation. +// +// ERROR_INVALID_PARAMETER +// The device structure in pbtdi is invalid. +// +// ERROR_NO_MORE_ITEMS +// The device in pbtdi is already been marked as authenticated. +// +// other WIN32 error +// Failure. Return value is the error code. +// +// For "Blind mode," here is the current mapping of Bluetooth status +// code to Win32 error codes: +// +// { BTH_ERROR_SUCCESS, ERROR_SUCCESS }, +// { BTH_ERROR_NO_CONNECTION, ERROR_DEVICE_NOT_CONNECTED }, +// { BTH_ERROR_PAGE_TIMEOUT, WAIT_TIMEOUT }, +// { BTH_ERROR_HARDWARE_FAILURE, ERROR_GEN_FAILURE }, +// { BTH_ERROR_AUTHENTICATION_FAILURE, ERROR_NOT_AUTHENTICATED }, +// { BTH_ERROR_MEMORY_FULL, ERROR_NOT_ENOUGH_MEMORY }, +// { BTH_ERROR_CONNECTION_TIMEOUT, WAIT_TIMEOUT }, +// { BTH_ERROR_LMP_RESPONSE_TIMEOUT, WAIT_TIMEOUT }, +// { BTH_ERROR_MAX_NUMBER_OF_CONNECTIONS, ERROR_REQ_NOT_ACCEP }, +// { BTH_ERROR_PAIRING_NOT_ALLOWED, ERROR_ACCESS_DENIED }, +// { BTH_ERROR_UNSPECIFIED_ERROR, ERROR_NOT_READY }, +// { BTH_ERROR_LOCAL_HOST_TERMINATED_CONNECTION, ERROR_VC_DISCONNECTED }, +// +DWORD +WINAPI +BluetoothAuthenticateDevice( + HWND hwndParent, + HANDLE hRadio, + BLUETOOTH_DEVICE_INFO * pbtbi, + PWCHAR pszPasskey, + ULONG ulPasskeyLength + ); + +// +// Description: +// Allows the caller to prompt for multiple devices to be authenticated +// within a single instance of the "Bluetooth Connection Wizard." +// +// Parameters: +// +// hwndParent +// The window to parent the authentication wizard. If NULL, the +// wizard will be parented off the desktop. +// +// hRadio +// A valid local radio handle or NULL. If NULL, then all radios will +// be tired. If any of the radios succeed, then the call will +// succeed. +// +// cDevices +// Number of devices in the rgbtdi array. +// +// rgbtdi +// An array BLUETOOTH_DEVICE_INFO records of the devices to be +// authenticated. +// +// Return Values: +// +// ERROR_SUCCESS +// Success. Check the fAuthenticate flag on each of the devices. +// +// ERROR_CANCELLED +// User aborted the operation. Check the fAuthenticate flags on +// each device to determine if any of the devices were authenticated +// before the user cancelled the operation. +// +// ERROR_INVALID_PARAMETER +// One of the items in the array of devices is invalid. +// +// ERROR_NO_MORE_ITEMS +// All the devices in the array of devices are already been marked as +// being authenticated. +// +// other WIN32 error +// Failure. Return value is the error code. +// +DWORD +WINAPI +BluetoothAuthenticateMultipleDevices( + HWND hwndParent, + HANDLE hRadio, + DWORD cDevices, + BLUETOOTH_DEVICE_INFO * pbtdi + ); + +// *************************************************************************** +// +// Bluetooth Services +// +// *************************************************************************** + +#define BLUETOOTH_SERVICE_DISABLE 0x00 +#define BLUETOOTH_SERVICE_ENABLE 0x01 +#define BLUETOOTH_SERVICE_MASK ( BLUETOOTH_ENABLE_SERVICE | BLUETOOTH_DISABLE_SERVICE ) + +// +// Description: +// Enables/disables the services for a particular device. +// +// The system maintains a mapping of service guids to supported drivers for +// Bluetooth-enabled devices. Enabling a service installs the corresponding +// device driver. Disabling a service removes the corresponding device driver. +// +// If a non-supported service is enabled, a driver will not be installed. +// +// Parameters +// hRadio +// Handle of the local Bluetooth radio device. +// +// pbtdi +// Pointer to a BLUETOOTH_DEVICE_INFO record. +// +// pGuidService +// The service GUID on the remote device. +// +// dwServiceFlags +// Flags to adjust the service. +// BLUETOOTH_SERVICE_DISABLE - disable the service +// BLUETOOTH_SERVICE_ENABLE - enables the service +// +// Return Values: +// ERROR_SUCCESS +// The call was successful. +// +// ERROR_INVALID_PARAMETER +// dwServiceFlags are invalid. +// +// ERROR_SERVICE_DOES_NOT_EXIST +// The GUID in pGuidService is not supported. +// +// other WIN32 error +// The call failed. +// +DWORD +WINAPI +BluetoothSetServiceState( + HANDLE hRadio, + BLUETOOTH_DEVICE_INFO * pbtdi, + GUID * pGuidService, + DWORD dwServiceFlags + ); + +// +// Description: +// Enumerates the services guids enabled on a particular device. If hRadio +// is NULL, all device will be searched for the device and all the services +// enabled will be returned. +// +// Parameters: +// hRadio +// Handle of the local Bluetooth radio device. If NULL, it will search +// all the radios for the address in the pbtdi. +// +// pbtdi +// Pointer to a BLUETOOTH_DEVICE_INFO record. +// +// pcService +// On input, the number of records pointed to by pGuidServices. +// On output, the number of valid records return in pGuidServices. +// +// pGuidServices +// Pointer to memory that is at least *pcService in length. +// +// Return Values: +// ERROR_SUCCESS +// The call succeeded. pGuidServices is valid. +// +// ERROR_MORE_DATA +// The call succeeded. pGuidService contains an incomplete list of +// enabled service GUIDs. +// +// other WIN32 errors +// The call failed. +// +DWORD +WINAPI +BluetoothEnumerateInstalledServices( + HANDLE hRadio, + BLUETOOTH_DEVICE_INFO * pbtdi, + DWORD * pcServices, + GUID * pGuidServices + ); + +// +// Description: +// Change the discovery state of the local radio(s). +// If hRadio is NULL, all the radios will be set. +// +// Use BluetoothIsDiscoverable() to determine the radios current state. +// +// The system ensures that a discoverable system is connectable, thus +// the radio must allow incoming connections (see +// BluetoothEnableIncomingConnections) prior to making a radio +// discoverable. Failure to do so will result in this call failing +// (returns FALSE). +// +// Parameters: +// hRadio +// If not NULL, changes the state of a specific radio. +// If NULL, the API will interate through all the radios. +// +// fEnabled +// If FALSE, discovery will be disabled. +// +// Return Values +// TRUE +// State was successfully changed. If the caller specified NULL for +// hRadio, at least of the radios accepted the state change. +// +// FALSE +// State was not changed. If the caller specified NULL for hRadio, all +// of the radios did not accept the state change. +// +BOOL +WINAPI +BluetoothEnableDiscovery( + HANDLE hRadio, + BOOL fEnabled + ); + +// +// Description: +// Determines if the Bluetooth radios are discoverable. If there are +// multiple radios, the first one to say it is discoverable will cause +// this function to return TRUE. +// +// Parameters: +// hRadio +// Handle of the radio to check. If NULL, it will check all local +// radios. +// +// Return Values: +// TRUE +// A least one radio is discoverable. +// +// FALSE +// No radios are discoverable. +// +BOOL +WINAPI +BluetoothIsDiscoverable( + HANDLE hRadio + ); + +// +// Description: +// Enables/disables the state of a radio to accept incoming connections. +// If hRadio is NULL, all the radios will be set. +// +// Use BluetoothIsConnectable() to determine the radios current state. +// +// The system enforces that a radio that is not connectable is not +// discoverable too. The radio must be made non-discoverable (see +// BluetoothEnableDiscovery) prior to making a radio non-connectionable. +// Failure to do so will result in this call failing (returns FALSE). +// +// Parameters: +// hRadio +// If not NULL, changes the state of a specific radio. +// If NULL, the API will interate through all the radios. +// +// fEnabled +// If FALSE, incoming connection will be disabled. +// +// Return Values +// TRUE +// State was successfully changed. If the caller specified NULL for +// hRadio, at least of the radios accepted the state change. +// +// FALSE +// State was not changed. If the caller specified NULL for hRadio, all +// of the radios did not accept the state change. +// +BOOL +WINAPI +BluetoothEnableIncomingConnections( + HANDLE hRadio, + BOOL fEnabled + ); + +// +// Description: +// Determines if the Bluetooth radios are connectable. If there are +// multiple radios, the first one to say it is connectable will cause +// this function to return TRUE. +// +// Parameters: +// hRadio +// Handle of the radio to check. If NULL, it will check all local +// radios. +// +// Return Values: +// TRUE +// A least one radio is allowing incoming connections. +// +// FALSE +// No radios are allowing incoming connections. +// +BOOL +WINAPI +BluetoothIsConnectable( + HANDLE hRadio + ); + +// *************************************************************************** +// +// Authentication Registration +// +// *************************************************************************** + +typedef HANDLE HBLUETOOTH_AUTHENTICATION_REGISTRATION; + +typedef BOOL (*PFN_AUTHENTICATION_CALLBACK)(LPVOID pvParam, PBLUETOOTH_DEVICE_INFO pDevice); + +// +// Description: +// Registers a callback function to be called when a particular device +// requests authentication. The request is sent to the last application +// that requested authentication for a particular device. +// +// Parameters: +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure. The Bluetooth +// address will be used for comparision. +// +// phRegHandle +// A pointer to where the registration HANDLE value will be +// stored. Call BluetoothUnregisterAuthentication() to close +// the handle. +// +// pfnCallback +// The function that will be called when the authentication event +// occurs. This function should match PFN_AUTHENTICATION_CALLBACK's +// prototype. +// +// pvParam +// Optional parameter to be past through to the callback function. +// This can be anything the application was to define. +// +// Return Values: +// ERROR_SUCCESS +// Success. A valid registration handle was returned. +// +// ERROR_OUTOFMEMORY +// Out of memory. +// +// other Win32 error. +// Failure. The registration handle is invalid. +// +DWORD +WINAPI +BluetoothRegisterForAuthentication( + BLUETOOTH_DEVICE_INFO * pbtdi, + HBLUETOOTH_AUTHENTICATION_REGISTRATION * phRegHandle, + PFN_AUTHENTICATION_CALLBACK pfnCallback, + PVOID pvParam + ); + +// +// Description: +// Unregisters an authentication callback and closes the handle. See +// BluetoothRegisterForAuthentication() for more information about +// authentication registration. +// +// Parameters: +// hRegHandle +// Handle returned by BluetoothRegisterForAuthentication(). +// +// Return Value: +// TRUE +// The handle was successfully closed. +// +// FALSE +// The handle was not successfully closed. Check GetLastError for +// more details. +// +// ERROR_INVALID_HANDLE +// The handle is NULL. +// +// other Win32 errors. +// +BOOL +WINAPI +BluetoothUnregisterAuthentication( + HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle + ); + +// +// Description: +// This function should be called after receiving an authentication request +// to send the passkey response. +// +// Parameters: +// +// hRadio +// Optional handle to the local radio. If NULL, the function will try +// each radio until one succeeds. +// +// pbtdi +// A pointer to a BLUETOOTH_DEVICE_INFO structure describing the device +// being authenticated. This can be the same structure passed to the +// callback function. +// +// pszPasskey +// A pointer to UNICODE zero-terminated string of the passkey response +// that should be sent back to the authenticating device. +// +// Return Values: +// ERROR_SUCESS +// The device accepted the passkey response. The device is authenticated. +// +// ERROR_CANCELED +// The device denied the passkey reponse. This also will returned if there +// is a communications problem with the local radio. +// +// E_FAIL +// The device returned a failure code during authentication. +// +// other Win32 error codes +// +DWORD +WINAPI +BluetoothSendAuthenticationResponse( + HANDLE hRadio, + BLUETOOTH_DEVICE_INFO * pbtdi, + LPWSTR pszPasskey + ); + +// *************************************************************************** +// +// SDP Parsing Functions +// +// *************************************************************************** + +typedef struct _SDP_ELEMENT_DATA { + // + // Enumeration of SDP element types. Generic element types will have a + // specificType value other then SDP_ST_NONE. The generic types are: + // o SDP_TYPE_UINT + // o SDP_TYPE_INT + // o SDP_TYPE_UUID + // + SDP_TYPE type; + + // + // Specific types for the generic SDP element types. + // + SDP_SPECIFICTYPE specificType; + + // + // Union of all possible data types. type and specificType will indicate + // which field is valid. For types which do not have a valid specificType, + // specific type will be SDP_ST_NONE. + // + union { + // type == SDP_TYPE_INT + SDP_LARGE_INTEGER_16 int128; // specificType == SDP_ST_INT128 + LONGLONG int64; // specificType == SDP_ST_INT64 + LONG int32; // specificType == SDP_ST_INT32 + SHORT int16; // specificType == SDP_ST_INT16 + CHAR int8; // specificType == SDP_ST_INT8 + + // type == SDP_TYPE_UINT + SDP_ULARGE_INTEGER_16 uint128; // specificType == SDP_ST_UINT128 + ULONGLONG uint64; // specificType == SDP_ST_UINT64 + ULONG uint32; // specificType == SDP_ST_UINT32 + USHORT uint16; // specificType == SDP_ST_UINT16 + UCHAR uint8; // specificType == SDP_ST_UINT8 + + // type == SDP_TYPE_BOOLEAN + UCHAR booleanVal; + + // type == SDP_TYPE_UUID + GUID uuid128; // specificType == SDP_ST_UUID128 + ULONG uuid32; // specificType == SDP_ST_UUID32 + USHORT uuid16; // specificType == SDP_ST_UUID32 + + // type == SDP_TYPE_STRING + struct { + // raw string buffer, may not be encoded as ANSI, use + // BluetoothSdpGetString to convert the value if it is described + // by the base language attribute ID list + LPBYTE value; + + // raw length of the string, may not be NULL terminuated + ULONG length; + } string; + + // type == SDP_TYPE_URL + struct { + LPBYTE value; + ULONG length; + } url; + + // type == SDP_TYPE_SEQUENCE + struct { + // raw sequence, starts at sequence element header + LPBYTE value; + + // raw sequence length + ULONG length; + } sequence; + + // type == SDP_TYPE_ALTERNATIVE + struct { + // raw alternative, starts at alternative element header + LPBYTE value; + + // raw alternative length + ULONG length; + } alternative; + + } data; + +} SDP_ELEMENT_DATA, *PSDP_ELEMENT_DATA; + +// +// Description: +// Retrieves and parses the element found at pSdpStream +// +// Parameters: +// IN pSdpStream +// pointer to valid SDP stream +// +// IN cbSdpStreamLength +// length of pSdpStream in bytes +// +// OUT pData +// pointer to be filled in with the data of the SDP element at the +// beginning of pSdpStream +// +// Return Values: +// ERROR_INVALID_PARAMETER +// one of required parameters is NULL or the pSdpStream is invalid +// +// ERROR_SUCCESS +// the sdp element was parsed correctly +// +DWORD +WINAPI +BluetoothSdpGetElementData( + LPBYTE pSdpStream, + ULONG cbSdpStreamLength, + PSDP_ELEMENT_DATA pData + ); + +typedef HANDLE HBLUETOOTH_CONTAINER_ELEMENT; + +// +// Description: +// Iterates over a container stream, returning each elemetn contained with +// in the container element at the beginning of pContainerStream +// +// Parameters: +// IN pContainerStream +// pointer to valid SDP stream whose first element is either a sequence +// or alternative +// +// IN cbContainerlength +// length in bytes of pContainerStream +// +// IN OUT pElement +// Value used to keep track of location within the stream. The first +// time this function is called for a particular container, *pElement +// should equal NULL. Upon subsequent calls, the value should be +// unmodified. +// +// OUT pData +// pointer to be filled in with the data of the SDP element at the +// current element of pContainerStream +// +// Return Values: +// ERROR_SUCCESS +// The call succeeded, pData contains the data +// +// ERROR_NO_MORE_ITEMS +// There are no more items in the list, the caller should cease calling +// BluetoothSdpGetContainerElementData for this container. +// +// ERROR_INVALID_PARAMETER +// A required pointer is NULL or the container is not a valid SDP +// stream +// +// Usage example: +// +// HBLUETOOTH_CONTAINER_ELEMENT element; +// SDP_ELEMENT_DATA data; +// ULONG result; +// +// element = NULL; +// +// while (TRUE) { +// result = BluetoothSdpGetContainerElementData( +// pContainer, ulContainerLength, &element, &data); +// +// if (result == ERROR_NO_MORE_ITEMS) { +// // We are done +// break; +// } +// else if (result != ERROR_SUCCESS) { +// // error +// } +// +// // do something with data ... +// } +// +// +DWORD +WINAPI +BluetoothSdpGetContainerElementData( + LPBYTE pContainerStream, + ULONG cbContainerLength, + HBLUETOOTH_CONTAINER_ELEMENT* pElement, + PSDP_ELEMENT_DATA pData + ); + +// +// Description: +// Retrieves the attribute value for the given attribute ID. pRecordStream +// must be an SDP stream that is formatted as an SDP record, a SEQUENCE +// containing UINT16 + element pairs. +// +// Parameters: +// IN pRecordStream +// pointer to a valid SDP stream which is formatted as a singl SDP +// record +// +// IN cbRecordlnegh +// length of pRecordStream in bytes +// +// IN usAttributeId +// the attribute ID to search for. see bthdef.h for SDP_ATTRIB_Xxx +// values. +// +// OUT pAttributeData +// pointer that will contain the attribute ID's value +// +// Return Values: +// ERRROR_SUCCESS +// Call succeeded, pAttributeData contains the attribute value +// +// ERROR_INVALID_PARAMETER +// One of the required pointers was NULL, pRecordStream was not a valid +// SDP stream, or pRecordStream was not a properly formatted SDP record +// +// ERROR_FILE_NOT_FOUND +// usAttributeId was not found in the record +// +// Usage: +// +// ULONG result; +// SDP_DATA_ELEMENT data; +// +// result = BluetoothSdpGetAttributeValue( +// pRecordStream, cbRecordLength, SDP_ATTRIB_RECORD_HANDLE, &data); +// if (result == ERROR_SUCCESS) { +// printf("record handle is 0x%x\n", data.data.uint32); +// } +// +DWORD +WINAPI +BluetoothSdpGetAttributeValue( + LPBYTE pRecordStream, + ULONG cbRecordLength, + USHORT usAttributeId, + PSDP_ELEMENT_DATA pAttributeData + ); + +// +// These three fields correspond one to one with the triplets defined in the +// SDP specification for the language base attribute ID list. +// +typedef struct _SDP_STRING_TYPE_DATA { + // + // How the string is encoded according to ISO 639:1988 (E/F): "Code + // for the representation of names of languages". + // + USHORT encoding; + + // + // MIBE number from IANA database + // + USHORT mibeNum; + + // + // The base attribute where the string is to be found in the record + // + USHORT attributeId; + +} SDP_STRING_TYPE_DATA, *PSDP_STRING_TYPE_DATA; + +// +// Description: +// Converts a raw string embedded in the SDP record into a UNICODE string +// +// Parameters: +// IN pRecordStream +// a valid SDP stream which is formatted as an SDP record +// +// IN cbRecordLength +// length of pRecordStream in bytes +// +// IN pStringData +// if NULL, then the calling thread's locale will be used to search +// for a matching string in the SDP record. If not NUL, the mibeNum +// and attributeId will be used to find the string to convert. +// +// IN usStringOffset +// the SDP string type offset to convert. usStringOffset is added to +// the base attribute id of the string. SDP specification defined +// offsets are: STRING_NAME_OFFSET, STRING_DESCRIPTION_OFFSET, and +// STRING_PROVIDER_NAME_OFFSET (found in bthdef.h). +// +// OUT pszString +// if NULL, pcchStringLength will be filled in with the required number +// of characters (not bytes) to retrieve the converted string. +// +// IN OUT pcchStringLength +// Upon input, if pszString is not NULL, will contain the length of +// pszString in characters. Upon output, it will contain either the +// number of required characters including NULL if an error is returned +// or the number of characters written to pszString (including NULL). +// +// Return Values: +// ERROR_SUCCES +// Call was successful and pszString contains the converted string +// +// ERROR_MORE_DATA +// pszString was NULL or too small to contain the converted string, +// pccxhStringLength contains the required length in characters +// +// ERROR_INVALID_DATA +// Could not perform the conversion +// +// ERROR_NO_SYSTEM_RESOURCES +// Could not allocate memory internally to perform the conversion +// +// ERROR_INVALID_PARAMETER +// One of the rquired pointers was NULL, pRecordStream was not a valid +// SDP stream, pRecordStream was not a properly formatted record, or +// the desired attribute + offset was not a string. +// +// Other HRESULTs returned by COM +// +DWORD +WINAPI +BluetoothSdpGetString( + LPBYTE pRecordStream, + ULONG cbRecordLength, + PSDP_STRING_TYPE_DATA pStringData, + USHORT usStringOffset, + PWCHAR pszString, + PULONG pcchStringLength + ); + +// *************************************************************************** +// +// Raw Attribute Enumeration +// +// *************************************************************************** + +typedef BOOL (CALLBACK *PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK)( + ULONG uAttribId, + LPBYTE pValueStream, + ULONG cbStreamSize, + LPVOID pvParam + ); + +// +// Description: +// Enumerates through the SDP record stream calling the Callback function +// for each attribute in the record. If the Callback function returns +// FALSE, the enumeration is stopped. +// +// Return Values: +// TRUE +// Success! Something was enumerated. +// +// FALSE +// Failure. GetLastError() could be one of the following: +// +// ERROR_INVALID_PARAMETER +// pSDPStream or pfnCallback is NULL. +// +// ERROR_INVALID_DATA +// The SDP stream is corrupt. +// +// other Win32 errors. +// +#define BluetoothEnumAttributes BluetoothSdpEnumAttributes + +BOOL +WINAPI +BluetoothSdpEnumAttributes( + LPBYTE pSDPStream, + ULONG cbStreamSize, + PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK pfnCallback, + LPVOID pvParam + ); + +#ifdef __cplusplus +} +#endif diff --git a/cpp/wiipair/include/bthdef.h b/cpp/wiipair/include/bthdef.h new file mode 100644 index 0000000..2dd26aa --- /dev/null +++ b/cpp/wiipair/include/bthdef.h @@ -0,0 +1,858 @@ +/*++ + +Copyright (c) 2000 Microsoft Corporation + +Module Name: + + bthdef.h + +Abstract: + + This module contains the Bluetooth common structures and definitions + +Author: + +Notes: + +Environment: + + Kernel mode only + + +Revision History: + + --*/ + +#ifndef __BTHDEF_H__ +#define __BTHDEF_H__ + +#ifndef GUID_DEFS_ONLY + #ifndef NO_BTHSDPDEF_INC + #include "bthsdpdef.h" + #endif // NO_BTHSDPDEF_INC +#endif // GUID_DEFS_ONLY + +#ifndef NO_GUID_DEFS + +// {0850302A-B344-4fda-9BE9-90576B8D46F0} +DEFINE_GUID(GUID_BTHPORT_DEVICE_INTERFACE, 0x850302a, 0xb344, 0x4fda, 0x9b, 0xe9, 0x90, 0x57, 0x6b, 0x8d, 0x46, 0xf0); + +// {EA3B5B82-26EE-450E-B0D8-D26FE30A3869} +DEFINE_GUID(GUID_BLUETOOTH_RADIO_IN_RANGE, 0xea3b5b82, 0x26ee, 0x450e, 0xb0, 0xd8, 0xd2, 0x6f, 0xe3, 0x0a, 0x38, 0x69); + +// {E28867C9-C2AA-4CED-B969-4570866037C4} +DEFINE_GUID(GUID_BLUETOOTH_RADIO_OUT_OF_RANGE, 0xe28867c9, 0xc2aa, 0x4ced, 0xb9, 0x69, 0x45, 0x70, 0x86, 0x60, 0x37, 0xc4); + +// BD198B7C-24AB-4B9A-8C0D-A8EA8349AA16 +DEFINE_GUID(GUID_BLUETOOTH_PIN_REQUEST, 0xbd198b7c, 0x24ab, 0x4b9a, 0x8c, 0x0d, 0xa8, 0xea, 0x83, 0x49, 0xaa, 0x16); + +// {7EAE4030-B709-4AA8-AC55-E953829C9DAA} +DEFINE_GUID(GUID_BLUETOOTH_L2CAP_EVENT, 0x7eae4030, 0xb709, 0x4aa8, 0xac, 0x55, 0xe9, 0x53, 0x82, 0x9c, 0x9d, 0xaa); + +// {FC240062-1541-49BE-B463-84C4DCD7BF7F} +DEFINE_GUID(GUID_BLUETOOTH_HCI_EVENT, 0xfc240062, 0x1541, 0x49be, 0xb4, 0x63, 0x84, 0xc4, 0xdc, 0xd7, 0xbf, 0x7f); + +// +// Bluetooth base UUID for service discovery +// +DEFINE_GUID(Bluetooth_Base_UUID, 0x00000000, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); + +// +// UUID for the root of the browse group list +// + +DEFINE_GUID(SDP_PROTOCOL_UUID, 0x00000001, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(UDP_PROTOCOL_UUID, 0x00000002, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(RFCOMM_PROTOCOL_UUID, 0x00000003, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(TCP_PROTOCOL_UUID, 0x00000004, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(TCSBIN_PROTOCOL_UUID, 0x00000005, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(TCSAT_PROTOCOL_UUID, 0x00000006, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(OBEX_PROTOCOL_UUID, 0x00000008, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(IP_PROTOCOL_UUID, 0x00000009, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(FTP_PROTOCOL_UUID, 0x0000000A, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HTTP_PROTOCOL_UUID, 0x0000000C, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(WSP_PROTOCOL_UUID, 0x0000000E, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(BNEP_PROTOCOL_UUID, 0x0000000F, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(UPNP_PROTOCOL_UUID, 0x00000010, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HID_PROTOCOL_UUID, 0x00000011, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HCCC_PROTOCOL_UUID, 0x00000012, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HCDC_PROTOCOL_UUID, 0x00000014, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HN_PROTOCOL_UUID, 0x00000016, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AVCTP_PROTOCOL_UUID, 0x00000017, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AVDTP_PROTOCOL_UUID, 0x00000019, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(CMPT_PROTOCOL_UUID, 0x0000001B, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(UDI_C_PLANE_PROTOCOL_UUID, 0x0000001D, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(L2CAP_PROTOCOL_UUID, 0x00000100, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); + +#define SDP_PROTOCOL_UUID16 (0x0001) +#define UDP_PROTOCOL_UUID16 (0x0002) +#define RFCOMM_PROTOCOL_UUID16 (0x0003) +#define TCP_PROTOCOL_UUID16 (0x0004) +#define TCSBIN_PROTOCOL_UUID16 (0x0005) +#define TCSAT_PROTOCOL_UUID16 (0x0006) +#define OBEX_PROTOCOL_UUID16 (0x0008) +#define IP_PROTOCOL_UUID16 (0x0009) +#define FTP_PROTOCOL_UUID16 (0x000A) +#define HTTP_PROTOCOL_UUID16 (0x000C) +#define WSP_PROTOCOL_UUID16 (0x000E) +#define BNEP_PROTOCOL_UUID16 (0x000F) +#define UPNP_PROTOCOL_UUID16 (0x0010) +#define HID_PROTOCOL_UUID16 (0x0011) +#define HCCC_PROTOCOL_UUID16 (0x0012) +#define HCDC_PROTOCOL_UUID16 (0x0014) +#define HCN_PROTOCOL_UUID16 (0x0016) +#define AVCTP_PROTOCOL_UUID16 (0x0017) +#define AVDTP_PROTOCOL_UUID16 (0x0019) +#define CMPT_PROTOCOL_UUID16 (0x001B) +#define UDI_C_PLANE_PROTOCOL_UUID16 (0x001D) +#define L2CAP_PROTOCOL_UUID16 (0x0100) + +DEFINE_GUID(ServiceDiscoveryServerServiceClassID_UUID, 0x00001000, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(BrowseGroupDescriptorServiceClassID_UUID, 0x00001001, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(PublicBrowseGroupServiceClass_UUID, 0x00001002, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(SerialPortServiceClass_UUID, 0x00001101, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(LANAccessUsingPPPServiceClass_UUID, 0x00001102, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(DialupNetworkingServiceClass_UUID, 0x00001103, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(IrMCSyncServiceClass_UUID, 0x00001104, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(OBEXObjectPushServiceClass_UUID, 0x00001105, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(OBEXFileTransferServiceClass_UUID, 0x00001106, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(IrMCSyncCommandServiceClass_UUID, 0x00001107, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HeadsetServiceClass_UUID, 0x00001108, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(CordlessTelephonyServiceClass_UUID, 0x00001109, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AudioSourceServiceClass_UUID, 0x0000110A, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AudioSinkServiceClass_UUID, 0x0000110B, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AVRemoteControlTargetServiceClass_UUID, 0x0000110C, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AdvancedAudioDistributionServiceClass_UUID,0x0000110D, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AVRemoteControlServiceClass_UUID, 0x0000110E, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(VideoConferencingServiceClass_UUID, 0x0000110F, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(IntercomServiceClass_UUID, 0x00001110, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(FaxServiceClass_UUID, 0x00001111, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HeadsetAudioGatewayServiceClass_UUID, 0x00001112, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(WAPServiceClass_UUID, 0x00001113, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(WAPClientServiceClass_UUID, 0x00001114, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(PANUServiceClass_UUID, 0x00001115, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(NAPServiceClass_UUID, 0x00001116, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(GNServiceClass_UUID, 0x00001117, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(DirectPrintingServiceClass_UUID, 0x00001118, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ReferencePrintingServiceClass_UUID, 0x00001119, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ImagingServiceClass_UUID, 0x0000111A, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ImagingResponderServiceClass_UUID, 0x0000111B, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ImagingAutomaticArchiveServiceClass_UUID, 0x0000111C, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ImagingReferenceObjectsServiceClass_UUID, 0x0000111D, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HandsfreeServiceClass_UUID, 0x0000111E, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HandsfreeAudioGatewayServiceClass_UUID, 0x0000111F, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(DirectPrintingReferenceObjectsServiceClass_UUID, + 0x00001120, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(ReflectedUIServiceClass_UUID, 0x00001121, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(BasicPringingServiceClass_UUID, 0x00001122, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(PrintingStatusServiceClass_UUID, 0x00001123, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HumanInterfaceDeviceServiceClass_UUID, 0x00001124, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HardcopyCableReplacementServiceClass_UUID, 0x00001125, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HCRPrintServiceClass_UUID, 0x00001126, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(HCRScanServiceClass_UUID, 0x00001127, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(CommonISDNAccessServiceClass_UUID, 0x00001128, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(VideoConferencingGWServiceClass_UUID, 0x00001129, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(UDIMTServiceClass_UUID, 0x0000112A, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(UDITAServiceClass_UUID, 0x0000112B, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(AudioVideoServiceClass_UUID, 0x0000112C, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(PnPInformationServiceClass_UUID, 0x00001200, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(GenericNetworkingServiceClass_UUID, 0x00001201, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(GenericFileTransferServiceClass_UUID, 0x00001202, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(GenericAudioServiceClass_UUID, 0x00001203, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); +DEFINE_GUID(GenericTelephonyServiceClass_UUID, 0x00001204, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB); + +#define ServiceDiscoveryServerServiceClassID_UUID16 (0x1000) +#define BrowseGroupDescriptorServiceClassID_UUID16 (0x1001) +#define PublicBrowseGroupServiceClassID_UUID16 (0x1002) +#define SerialPortServiceClassID_UUID16 (0x1101) +#define LANAccessUsingPPPServiceClassID_UUID16 (0x1102) +#define DialupNetworkingServiceClassID_UUID16 (0x1103) +#define IrMCSyncServiceClassID_UUID16 (0x1104) +#define OBEXObjectPushServiceClassID_UUID16 (0x1105) +#define OBEXFileTransferServiceClassID_UUID16 (0x1106) +#define IrMcSyncCommandServiceClassID_UUID16 (0x1107) +#define HeadsetServiceClassID_UUID16 (0x1108) +#define CordlessServiceClassID_UUID16 (0x1109) +#define AudioSourceServiceClassID_UUID16 (0x110A) +#define AudioSinkSourceServiceClassID_UUID16 (0x110B) +#define AVRemoteControlTargetServiceClassID_UUID16 (0x110C) +#define AdvancedAudioDistributionServiceClassID_UUID16 (0x110D) +#define AVRemoteControlServiceClassID_UUID16 (0x110E) +#define VideoConferencingServiceClassID_UUID16 (0x110F) +#define IntercomServiceClassID_UUID16 (0x1110) +#define FaxServiceClassID_UUID16 (0x1111) +#define HeadsetAudioGatewayServiceClassID_UUID16 (0x1112) +#define WAPServiceClassID_UUID16 (0x1113) +#define WAPClientServiceClassID_UUID16 (0x1114) +#define PANUServiceClassID_UUID16 (0x1115) +#define NAPServiceClassID_UUID16 (0x1116) +#define GNServiceClassID_UUID16 (0x1117) +#define DirectPrintingServiceClassID_UUID16 (0x1118) +#define ReferencePrintingServiceClassID_UUID16 (0x1119) +#define ImagingServiceClassID_UUID16 (0x111A) +#define ImagingResponderServiceClassID_UUID16 (0x111B) +#define ImagingAutomaticArchiveServiceClassID_UUID16 (0x111C) +#define ImagingReferenceObjectsServiceClassID_UUID16 (0x111D) +#define HandsfreeServiceClassID_UUID16 (0x111E) +#define HandsfreeAudioGatewayServiceClassID_UUID16 (0x111F) +#define DirectPrintingReferenceObjectsServiceClassID_UUID16 \ + (0x1120) +#define ReflectsUIServiceClassID_UUID16 (0x1121) +#define BasicPrintingServiceClassID_UUID16 (0x1122) +#define PrintingStatusServiceClassID_UUID16 (0x1123) +#define HumanInterfaceDeviceServiceClassID_UUID16 (0x1124) +#define HardcopyCableReplacementServiceClassID_UUID16 (0x1125) +#define HCRPrintServiceClassID_UUID16 (0x1126) +#define HCRScanServiceClassID_UUID16 (0x1127) +#define CommonISDNAccessServiceClass_UUID16 (0x1128) +#define VideoConferencingGWServiceClass_UUID16 (0x1129) +#define UDIMTServiceClass_UUID16 (0x112A) +#define UDITAServiceClass_UUID16 (0x112B) +#define AudioVideoServiceClass_UUID16 (0x112C) + +#define PnPInformationServiceClassID_UUID16 (0x1200) +#define GenericNetworkingServiceClassID_UUID16 (0x1201) +#define GenericFileTransferServiceClassID_UUID16 (0x1202) +#define GenericAudioServiceClassID_UUID16 (0x1203) +#define GenericTelephonyServiceClassID_UUID16 (0x1204) + +#endif // NO_GUID_DEFS + +#ifndef GUID_DEFS_ONLY + +// +// max length of device friendly name. +// +#define BTH_MAX_NAME_SIZE (248) + +#define BTH_MAX_PIN_SIZE (16) +#define BTH_LINK_KEY_LENGTH (16) + +#define BTH_MFG_ERICSSON (0) +#define BTH_MFG_NOKIA (1) +#define BTH_MFG_INTEL (2) +#define BTH_MFG_IBM (3) +#define BTH_MFG_TOSHIBA (4) +#define BTH_MFG_3COM (5) +#define BTH_MFG_MICROSOFT (6) +#define BTH_MFG_LUCENT (7) +#define BTH_MFG_MOTOROLA (8) +#define BTH_MFG_INFINEON (9) +#define BTH_MFG_CSR (10) +#define BTH_MFG_SILICONWAVE (11) +#define BTH_MFG_DIGIANSWER (12) +#define BTH_MFG_TI (13) +#define BTH_MFG_PARTHUS (14) +#define BTH_MFG_BROADCOM (15) +#define BTH_MFG_MITEL (16) +#define BTH_MFG_WIDCOMM (17) +#define BTH_MFG_ZEEVO (18) +#define BTH_MFG_ATMEL (19) +#define BTH_MFG_MITSIBUSHI (20) +#define BTH_MFG_RTX_TELECOM (21) +#define BTH_MFG_KC_TECHNOLOGY (22) +#define BTH_MFG_NEWLOGIC (23) +#define BTH_MFG_TRANSILICA (24) +#define BTH_MFG_ROHDE_SCHWARZ (25) +#define BTH_MFG_TTPCOM (26) +#define BTH_MFG_SIGNIA (27) +#define BTH_MFG_CONEXANT (28) +#define BTH_MFG_QUALCOMM (29) +#define BTH_MFG_INVENTEL (30) +#define BTH_MFG_AVM_BERLIN (31) +#define BTH_MFG_BANDSPEED (32) +#define BTH_MFG_MANSELLA (33) +#define BTH_MFG_NEC (34) +#define BTH_MFG_WAVEPLUS_TECHNOLOGY_CO (35) +#define BTH_MFG_ALCATEL (36) +#define BTH_MFG_PHILIPS_SEMICONDUCTOR (37) +#define BTH_MFG_C_TECHNOLOGIES (38) +#define BTH_MFG_OPEN_INTERFACE (39) +#define BTH_MFG_RF_MICRO_DEVICES (40) +#define BTH_MFG_HITACHI (41) +#define BTH_MFG_SYMBOL_TECHNOLOGIES (42) +#define BTH_MFG_TENOVIS (43) +#define BTH_MFG_MACRONIX_INTERNATIONAL (44) +#define BTH_MFG_INTERNAL_USE (65535) + +typedef ULONGLONG BTH_ADDR, *PBTH_ADDR; +typedef ULONG BTH_COD, *PBTH_COD; +typedef ULONG BTH_LAP, *PBTH_LAP; + +#define BTH_ADDR_NULL ((ULONGLONG) 0x0000000000000000) + +#define NAP_MASK ((ULONGLONG) 0xFFFF00000000) +#define SAP_MASK ((ULONGLONG) 0x0000FFFFFFFF) + +#define NAP_BIT_OFFSET (8 * 4) +#define SAP_BIT_OFFSET (0) + +#define GET_NAP(_bth_addr) ((USHORT) (((_bth_addr) & NAP_MASK) >> NAP_BIT_OFFSET)) +#define GET_SAP(_bth_addr) ((ULONG) (((_bth_addr) & SAP_MASK) >> SAP_BIT_OFFSET)) + +#define SET_NAP(_nap) (((ULONGLONG) ((USHORT) (_nap))) << NAP_BIT_OFFSET) +#define SET_SAP(_sap) (((ULONGLONG) ((ULONG) (_sap))) << SAP_BIT_OFFSET) + +#define SET_NAP_SAP(_nap, _sap) (SET_NAP(_nap) | SET_SAP(_sap)) + +#define COD_FORMAT_BIT_OFFSET (0) +#define COD_MINOR_BIT_OFFSET (2) +#define COD_MAJOR_BIT_OFFSET (8 * 1) +#define COD_SERVICE_BIT_OFFSET (8 * 1 + 5) + +#define COD_FORMAT_MASK (0x000003) +#define COD_MINOR_MASK (0x0000FC) +#define COD_MAJOR_MASK (0x001F00) +#define COD_SERVICE_MASK (0xFFE000) + + +#define GET_COD_FORMAT(_cod) ( (_cod) & COD_FORMAT_MASK >> COD_FORMAT_BIT_OFFSET) +#define GET_COD_MINOR(_cod) (((_cod) & COD_MINOR_MASK) >> COD_MINOR_BIT_OFFSET) +#define GET_COD_MAJOR(_cod) (((_cod) & COD_MAJOR_MASK) >> COD_MAJOR_BIT_OFFSET) +#define GET_COD_SERVICE(_cod) (((_cod) & COD_SERVICE_MASK) >> COD_SERVICE_BIT_OFFSET) + +#define SET_COD_MINOR(_cod, _minor) (_cod) = ((_cod) & ~COD_MINOR_MASK) | ((_minor) << COD_MINOR_BIT_OFFSET) +#define SET_COD_MAJOR(_cod, _major) (_cod) = ((_cod) & ~COD_MAJOR_MASK) | ((_major) << COD_MAJOR_BIT_OFFSET) +#define SET_COD_SERVICE(_cod, _service) (_cod) = ((_cod) & ~COD_SERVICE_MASK) | ((_service) << COD_SERVICE_BIT_OFFSET) + +#define COD_VERSION (0x0) + +#define COD_SERVICE_LIMITED (0x0001) +#define COD_SERVICE_POSITIONING (0x0008) +#define COD_SERVICE_NETWORKING (0x0010) +#define COD_SERVICE_RENDERING (0x0020) +#define COD_SERVICE_CAPTURING (0x0040) +#define COD_SERVICE_OBJECT_XFER (0x0080) +#define COD_SERVICE_AUDIO (0x0100) +#define COD_SERVICE_TELEPHONY (0x0200) +#define COD_SERVICE_INFORMATION (0x0400) + +#define COD_SERVICE_VALID_MASK (COD_SERVICE_LIMITED | \ + COD_SERVICE_POSITIONING | \ + COD_SERVICE_NETWORKING | \ + COD_SERVICE_RENDERING | \ + COD_SERVICE_CAPTURING | \ + COD_SERVICE_OBJECT_XFER |\ + COD_SERVICE_AUDIO |\ + COD_SERVICE_TELEPHONY |\ + COD_SERVICE_INFORMATION) + +#define COD_SERVICE_MAX_COUNT (9) + +// +// Major class codes +// +#define COD_MAJOR_MISCELLANEOUS (0x00) +#define COD_MAJOR_COMPUTER (0x01) +#define COD_MAJOR_PHONE (0x02) +#define COD_MAJOR_LAN_ACCESS (0x03) +#define COD_MAJOR_AUDIO (0x04) +#define COD_MAJOR_PERIPHERAL (0x05) +#define COD_MAJOR_IMAGING (0x06) +#define COD_MAJOR_UNCLASSIFIED (0x1F) + +// +// Minor class codes specific to each major class +// +#define COD_COMPUTER_MINOR_UNCLASSIFIED (0x00) +#define COD_COMPUTER_MINOR_DESKTOP (0x01) +#define COD_COMPUTER_MINOR_SERVER (0x02) +#define COD_COMPUTER_MINOR_LAPTOP (0x03) +#define COD_COMPUTER_MINOR_HANDHELD (0x04) +#define COD_COMPUTER_MINOR_PALM (0x05) +#define COD_COMPUTER_MINOR_WEARABLE (0x06) + +#define COD_PHONE_MINOR_UNCLASSIFIED (0x00) +#define COD_PHONE_MINOR_CELLULAR (0x01) +#define COD_PHONE_MINOR_CORDLESS (0x02) +#define COD_PHONE_MINOR_SMART (0x03) +#define COD_PHONE_MINOR_WIRED_MODEM (0x04) + +#define COD_AUDIO_MINOR_UNCLASSIFIED (0x00) +#define COD_AUDIO_MINOR_HEADSET (0x01) +#define COD_AUDIO_MINOR_HANDS_FREE (0x02) +#define COD_AUDIO_MINOR_HEADSET_HANDS_FREE (0x03) +#define COD_AUDIO_MINOR_MICROPHONE (0x04) +#define COD_AUDIO_MINOR_LOUDSPEAKER (0x05) +#define COD_AUDIO_MINOR_HEADPHONES (0x06) +#define COD_AUDIO_MINOR_PORTABLE_AUDIO (0x07) +#define COD_AUDIO_MINOR_CAR_AUDIO (0x08) +#define COD_AUDIO_MINOR_SET_TOP_BOX (0x09) +#define COD_AUDIO_MINOR_HIFI_AUDIO (0x0A) +#define COD_AUDIO_MINOR_VCR (0x0B) +#define COD_AUDIO_MINOR_VIDEO_CAMERA (0x0C) +#define COD_AUDIO_MINOR_CAMCORDER (0x0D) +#define COD_AUDIO_MINOR_VIDEO_MONITOR (0x0E) +#define COD_AUDIO_MINOR_VIDEO_DISPLAY_LOUDSPEAKER \ + (0x0F) +#define COD_AUDIO_MINOR_VIDEO_DISPLAY_CONFERENCING \ + (0x10) +// #define COD_AUDIO_MINOR_RESERVED (0x11) +#define COD_AUDIO_MINOR_GAMING_TOY (0x12) + +#define COD_PERIPHERAL_MINOR_KEYBOARD_MASK (0x10) +#define COD_PERIPHERAL_MINOR_POINTER_MASK (0x20) + +#define COD_PERIPHERAL_MINOR_NO_CATEGORY (0x00) +#define COD_PERIPHERAL_MINOR_JOYSTICK (0x01) +#define COD_PERIPHERAL_MINOR_GAMEPAD (0x02) +#define COD_PERIPHERAL_MINOR_REMOTE_CONTROL (0x03) +#define COD_PERIPHERAL_MINOR_SENSING (0x04) + +#define COD_IMAGING_MINOR_DISPLAY_MASK (0x04) +#define COD_IMAGING_MINOR_CAMERA_MASK (0x08) +#define COD_IMAGING_MINOR_SCANNER_MASK (0x10) +#define COD_IMAGING_MINOR_PRINTER_MASK (0x20) + +// +// Cannot use GET_COD_MINOR for this b/c it is embedded in a different manner +// than the rest of the major classes +// + +#define COD_LAN_ACCESS_BIT_OFFSET (5) + +#define COD_LAN_MINOR_MASK (0x00001C) +#define COD_LAN_ACCESS_MASK (0x0000E0) + +#define GET_COD_LAN_MINOR(_cod) (((_cod) & COD_LAN_MINOR_MASK) >> COD_MINOR_BIT_OFFSET) +#define GET_COD_LAN_ACCESS(_cod) (((_cod) & COD_LAN_ACCESS_MASK) >> COD_LAN_ACCESS_BIT_OFFSET) + +// +// LAN access percent usage subcodes +// +#define COD_LAN_MINOR_UNCLASSIFIED (0x00) + +#define COD_LAN_ACCESS_0_USED (0x00) +#define COD_LAN_ACCESS_17_USED (0x01) +#define COD_LAN_ACCESS_33_USED (0x02) +#define COD_LAN_ACCESS_50_USED (0x03) +#define COD_LAN_ACCESS_67_USED (0x04) +#define COD_LAN_ACCESS_83_USED (0x05) +#define COD_LAN_ACCESS_99_USED (0x06) +#define COD_LAN_ACCESS_FULL (0x07) + +// +// Used as an initializer of LAP_DATA +// +#define LAP_GIAC_INIT { 0x33, 0x8B, 0x9E } +#define LAP_LIAC_INIT { 0x00, 0x8B, 0x9E } + +// +// General Inquiry Access Code. +// +#define LAP_GIAC_VALUE (0x009E8B33) + +// +// Limited Inquiry Access Code. +// +#define LAP_LIAC_VALUE (0x009E8B00) + +#define BTH_ADDR_IAC_FIRST (0x9E8B00) +#define BTH_ADDR_IAC_LAST (0x9E8B3f) +#define BTH_ADDR_LIAC (0x9E8B00) +#define BTH_ADDR_GIAC (0x9E8B33) + +typedef UCHAR BTHSTATUS, *PBTHSTATUS; + +#define BTH_ERROR(_btStatus) ((_btStatus) != BTH_ERROR_SUCCESS) +#define BTH_SUCCESS(_btStatus) ((_btStatus) == BTH_ERROR_SUCCESS) + +#define BTH_ERROR_SUCCESS (0x00) +#define BTH_ERROR_UNKNOWN_HCI_COMMAND (0x01) +#define BTH_ERROR_NO_CONNECTION (0x02) +#define BTH_ERROR_HARDWARE_FAILURE (0x03) +#define BTH_ERROR_PAGE_TIMEOUT (0x04) +#define BTH_ERROR_AUTHENTICATION_FAILURE (0x05) +#define BTH_ERROR_KEY_MISSING (0x06) +#define BTH_ERROR_MEMORY_FULL (0x07) +#define BTH_ERROR_CONNECTION_TIMEOUT (0x08) +#define BTH_ERROR_MAX_NUMBER_OF_CONNECTIONS (0x09) +#define BTH_ERROR_MAX_NUMBER_OF_SCO_CONNECTIONS (0x0a) +#define BTH_ERROR_ACL_CONNECTION_ALREADY_EXISTS (0x0b) +#define BTH_ERROR_COMMAND_DISALLOWED (0x0c) +#define BTH_ERROR_HOST_REJECTED_LIMITED_RESOURCES (0x0d) +#define BTH_ERROR_HOST_REJECTED_SECURITY_REASONS (0x0e) +#define BTH_ERROR_HOST_REJECTED_PERSONAL_DEVICE (0x0f) +#define BTH_ERROR_HOST_TIMEOUT (0x10) +#define BTH_ERROR_UNSUPPORTED_FEATURE_OR_PARAMETER (0x11) +#define BTH_ERROR_INVALID_HCI_PARAMETER (0x12) +#define BTH_ERROR_REMOTE_USER_ENDED_CONNECTION (0x13) +#define BTH_ERROR_REMOTE_LOW_RESOURCES (0x14) +#define BTH_ERROR_REMOTE_POWERING_OFF (0x15) +#define BTH_ERROR_LOCAL_HOST_TERMINATED_CONNECTION (0x16) +#define BTH_ERROR_REPEATED_ATTEMPTS (0x17) +#define BTH_ERROR_PAIRING_NOT_ALLOWED (0x18) +#define BTH_ERROR_UKNOWN_LMP_PDU (0x19) +#define BTH_ERROR_UNSUPPORTED_REMOTE_FEATURE (0x1a) +#define BTH_ERROR_SCO_OFFSET_REJECTED (0x1b) +#define BTH_ERROR_SCO_INTERVAL_REJECTED (0x1c) +#define BTH_ERROR_SCO_AIRMODE_REJECTED (0x1d) +#define BTH_ERROR_INVALID_LMP_PARAMETERS (0x1e) +#define BTH_ERROR_UNSPECIFIED_ERROR (0x1f) +#define BTH_ERROR_UNSUPPORTED_LMP_PARM_VALUE (0x20) +#define BTH_ERROR_ROLE_CHANGE_NOT_ALLOWED (0x21) +#define BTH_ERROR_LMP_RESPONSE_TIMEOUT (0x22) +#define BTH_ERROR_LMP_TRANSACTION_COLLISION (0x23) +#define BTH_ERROR_LMP_PDU_NOT_ALLOWED (0x24) +#define BTH_ERROR_ENCRYPTION_MODE_NOT_ACCEPTABLE (0x25) +#define BTH_ERROR_UNIT_KEY_NOT_USED (0x26) +#define BTH_ERROR_QOS_IS_NOT_SUPPORTED (0x27) +#define BTH_ERROR_INSTANT_PASSED (0x28) +#define BTH_ERROR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED (0x29) + +#define BTH_ERROR_UNSPECIFIED (0xFF) + +// +// Min, max, and default L2cap MTU. +// +#define L2CAP_MIN_MTU (48) +#define L2CAP_MAX_MTU (0xFFFF) +#define L2CAP_DEFAULT_MTU (672) + +// +// Max l2cap signal size (48) - size of signal header (4) +// +#define MAX_L2CAP_PING_DATA_LENGTH (44) +#define MAX_L2CAP_INFO_DATA_LENGTH (44) + +// +// the following two structures provides information about +// disocvered remote radios. +// + +#define BDIF_ADDRESS (0x00000001) +#define BDIF_COD (0x00000002) +#define BDIF_NAME (0x00000004) +#define BDIF_PAIRED (0x00000008) +#define BDIF_PERSONAL (0x00000010) +#define BDIF_CONNECTED (0x00000020) + +#define BDIF_VALID_FLAGS \ + (BDIF_ADDRESS | BDIF_COD | BDIF_NAME | BDIF_PAIRED | BDIF_PERSONAL | \ + BDIF_CONNECTED) + +typedef struct _BTH_DEVICE_INFO { + // + // Combination BDIF_Xxx flags + // + ULONG flags; + + // + // Address of remote device. + // + BTH_ADDR address; + + // + // Class Of Device. + // + BTH_COD classOfDevice; + + // + // name of the device + // + CHAR name[BTH_MAX_NAME_SIZE]; + +} BTH_DEVICE_INFO, *PBTH_DEVICE_INFO; + +// +// Buffer associated with GUID_BLUETOOTH_RADIO_IN_RANGE +// +typedef struct _BTH_RADIO_IN_RANGE { + // + // Information about the remote radio + // + BTH_DEVICE_INFO deviceInfo; + + // + // The previous flags value for the BTH_DEVICE_INFO. The receiver of this + // notification can compare the deviceInfo.flags and previousDeviceFlags + // to determine what has changed about this remote radio. + // + // For instance, if BDIF_NAME is set in deviceInfo.flags and not in + // previousDeviceFlags, the remote radio's has just been retrieved. + // + ULONG previousDeviceFlags; + +} BTH_RADIO_IN_RANGE, *PBTH_RADIO_IN_RANGE; + +// +// Buffer associated with GUID_BLUETOOTH_L2CAP_EVENT +// +typedef struct _BTH_L2CAP_EVENT_INFO { + // + // Remote radio address which the L2CAP event is associated with + // + BTH_ADDR bthAddress; + + // + // The PSM that is either being connected to or disconnected from + // + USHORT psm; + + // + // If != 0, then the channel has just been established. If == 0, then the + // channel has been destroyed. Notifications for a destroyed channel will + // only be sent for channels successfully established. + // + UCHAR connected; + + // + // If != 0, then the local host iniated the l2cap connection. If == 0, then + // the remote host initated the connection. This field is only valid if + // connect is != 0. + // + UCHAR initiated; + +} BTH_L2CAP_EVENT_INFO, *PBTH_L2CAP_EVENT_INFO; + +#define HCI_CONNNECTION_TYPE_ACL (1) +#define HCI_CONNNECTION_TYPE_SCO (2) + +// +// Buffer associated with GUID_BLUETOOTH_HCI_EVENT +// +typedef struct _BTH_HCI_EVENT_INFO { + // + // Remote radio address which the HCI event is associated with + // + BTH_ADDR bthAddress; + + // + // HCI_CONNNECTION_TYPE_XXX value + // + UCHAR connectionType; + + // + // If != 0, then the underlying connection to the remote radio has just + // been estrablished. If == 0, then the underlying conneciton has just been + // destroyed. + // + UCHAR connected; + +} BTH_HCI_EVENT_INFO, *PBTH_HCI_EVENT_INFO; + +#define MAX_UUIDS_IN_QUERY (12) + +#define BTH_VID_DEFAULT_VALUE (0xFFFF) + +#define SDP_ERROR_INVALID_SDP_VERSION (0x0001) +#define SDP_ERROR_INVALID_RECORD_HANDLE (0x0002) +#define SDP_ERROR_INVALID_REQUEST_SYNTAX (0x0003) +#define SDP_ERROR_INVALID_PDU_SIZE (0x0004) +#define SDP_ERROR_INVALID_CONTINUATION_STATE (0x0005) +#define SDP_ERROR_INSUFFICIENT_RESOURCES (0x0006) + +// +// Defined by windows to handle server errors that are not described by the +// above errors. Start at 0x0100 so we don't go anywhere near the spec +// defined values. +// + +// +// Success, nothing went wrong +// +#define SDP_ERROR_SUCCESS ((SDP_ERROR) 0x0000) + +// +// The SDP PDU or parameters other than the SDP stream response was not correct +// +#define SDP_ERROR_SERVER_INVALID_RESPONSE ((SDP_ERROR) 0x0100) + +// +// The SDP response stream did not parse correctly. +// +#define SDP_ERROR_SERVER_RESPONSE_DID_NOT_PARSE ((SDP_ERROR) 0x0200) + +// +// The SDP response stream was successfully parsed, but did not match the +// required format for the query. +// +#define SDP_ERROR_SERVER_BAD_FORMAT ((SDP_ERROR) 0x0300) + +// +// SDP was unable to send a continued query back to the server +// +#define SDP_ERROR_COULD_NOT_SEND_CONTINUE ((SDP_ERROR) 0x0400) + +// +// Server sent a response that was too large to fit in the caller's buffer. +// +#define SDP_ERROR_RESPONSE_TOO_LARGE ((SDP_ERROR) 0x0500) + + +#define SDP_ATTRIB_RECORD_HANDLE (0x0000) +#define SDP_ATTRIB_CLASS_ID_LIST (0x0001) +#define SDP_ATTRIB_RECORD_STATE (0x0002) +#define SDP_ATTRIB_SERVICE_ID (0x0003) +#define SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST (0x0004) +#define SDP_ATTRIB_BROWSE_GROUP_LIST (0x0005) +#define SDP_ATTRIB_LANG_BASE_ATTRIB_ID_LIST (0x0006) +#define SDP_ATTRIB_INFO_TIME_TO_LIVE (0x0007) +#define SDP_ATTRIB_AVAILABILITY (0x0008) +#define SDP_ATTRIB_PROFILE_DESCRIPTOR_LIST (0x0009) +#define SDP_ATTRIB_DOCUMENTATION_URL (0x000A) +#define SDP_ATTRIB_CLIENT_EXECUTABLE_URL (0x000B) +#define SDP_ATTRIB_ICON_URL (0x000C) +#define SDP_ATTRIB_ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST \ + (0x000D) + +// +// Attribute IDs in the range of 0x000D - 0x01FF are reserved for future use +// +#define SDP_ATTRIB_PROFILE_SPECIFIC (0x0200) + +#define LANG_BASE_LANGUAGE_INDEX (0x0000) +#define LANG_BASE_ENCODING_INDEX (0x0001) +#define LANG_BASE_OFFSET_INDEX (0x0002) +#define LANG_DEFAULT_ID (0x0100) + +#define STRING_NAME_OFFSET (0x0000) +#define STRING_DESCRIPTION_OFFSET (0x0001) +#define STRING_PROVIDER_NAME_OFFSET (0x0002) + +#define SDP_ATTRIB_SDP_VERSION_NUMBER_LIST (0x0200) +#define SDP_ATTRIB_SDP_DATABASE_STATE (0x0201) + +#define SDP_ATTRIB_BROWSE_GROUP_ID (0x0200) + +#define SDP_ATTRIB_CORDLESS_EXTERNAL_NETWORK (0x0301) + +#define SDP_ATTRIB_FAX_CLASS_1_SUPPORT (0x0302) +#define SDP_ATTRIB_FAX_CLASS_2_0_SUPPORT (0x0303) +#define SDP_ATTRIB_FAX_CLASS_2_SUPPORT (0x0304) +#define SDP_ATTRIB_FAX_AUDIO_FEEDBACK_SUPPORT (0x0305) + +#define SDP_ATTRIB_HEADSET_REMOTE_AUDIO_VOLUME_CONTROL (0x0302) + +#define SDP_ATTRIB_LAN_LPSUBNET (0x0200) + +#define SDP_ATTRIB_OBJECT_PUSH_SUPPORTED_FORMATS_LIST (0x0303) + +#define SDP_ATTRIB_SYNCH_SUPPORTED_DATA_STORES_LIST (0x0301) + +// this is in the assigned numbers doc, but it does not show up in any profile +#define SDP_ATTRIB_SERVICE_VERSION (0x0300) + +#define SDP_ATTRIB_PAN_NETWORK_ADDRESS (0x0306) +#define SDP_ATTRIB_PAN_WAP_GATEWAY (0x0307) +#define SDP_ATTRIB_PAN_HOME_PAGE_URL (0x0308) +#define SDP_ATTRIB_PAN_WAP_STACK_TYPE (0x0309) +#define SDP_ATTRIB_PAN_SECURITY_DESCRIPTION (0x030A) +#define SDP_ATTRIB_PAN_NET_ACCESS_TYPE (0x030B) +#define SDP_ATTRIB_PAN_MAX_NET_ACCESS_RATE (0x030C) + +#define SDP_ATTRIB_IMAGING_SUPPORTED_CAPABILITIES (0x0310) +#define SDP_ATTRIB_IMAGING_SUPPORTED_FEATURES (0x0311) +#define SDP_ATTRIB_IMAGING_SUPPORTED_FUNCTIONS (0x0312) +#define SDP_ATTRIB_IMAGING_TOTAL_DATA_CAPACITY (0x0313) + +#define SDP_ATTRIB_DI_SPECIFICATION_ID (0x0200) +#define SDP_ATTRIB_DI_VENDOR_ID (0x0201) +#define SDP_ATTRIB_DI_PRODUCT_ID (0x0202) +#define SDP_ATTRIB_DI_VERSION (0x0203) +#define SDP_ATTRIB_DI_PRIMARY_RECORD (0x0204) +#define SDP_ATTRIB_DI_VENDOR_ID_SOURCE (0x0205) + +#define SDP_ATTRIB_HID_DEVICE_RELEASE_NUMBER (0x0200) +#define SDP_ATTRIB_HID_PARSER_VERSION (0x0201) +#define SDP_ATTRIB_HID_DEVICE_SUBCLASS (0x0202) +#define SDP_ATTRIB_HID_COUNTRY_CODE (0x0203) +#define SDP_ATTRIB_HID_VIRTUAL_CABLE (0x0204) +#define SDP_ATTRIB_HID_RECONNECT_INITIATE (0x0205) +#define SDP_ATTRIB_HID_DESCRIPTOR_LIST (0x0206) +#define SDP_ATTRIB_HID_LANG_ID_BASE_LIST (0x0207) +#define SDP_ATTRIB_HID_SDP_DISABLE (0x0208) +#define SDP_ATTRIB_HID_BATTERY_POWER (0x0209) +#define SDP_ATTRIB_HID_REMOTE_WAKE (0x020A) +#define SDP_ATTRIB_HID_REPORT_LIST (0x020B) +#define SDP_ATTRIB_HID_SUPERVISION_TIMEOUT (0x020C) +#define SDP_ATTRIB_HID_NORMALLY_CONNECTABLE (0x020D) +#define SDP_ATTRIB_HID_BOOT_DEVICE (0x020E) + +// +// Profile specific values +// +#define CORDLESS_EXTERNAL_NETWORK_PSTN (0x01) +#define CORDLESS_EXTERNAL_NETWORK_ISDN (0x02) +#define CORDLESS_EXTERNAL_NETWORK_GSM (0x03) +#define CORDLESS_EXTERNAL_NETWORK_CDMA (0x04) +#define CORDLESS_EXTERNAL_NETWORK_ANALOG_CELLULAR (0x05) +#define CORDLESS_EXTERNAL_NETWORK_PACKET_SWITCHED (0x06) +#define CORDLESS_EXTERNAL_NETWORK_OTHER (0x07) + +#define OBJECT_PUSH_FORMAT_VCARD_2_1 (0x01) +#define OBJECT_PUSH_FORMAT_VCARD_3_0 (0x02) +#define OBJECT_PUSH_FORMAT_VCAL_1_0 (0x03) +#define OBJECT_PUSH_FORMAT_ICAL_2_0 (0x04) +#define OBJECT_PUSH_FORMAT_VNOTE (0x05) +#define OBJECT_PUSH_FORMAT_VMESSAGE (0x06) +#define OBJECT_PUSH_FORMAT_ANY (0xFF) + +#define SYNCH_DATA_STORE_PHONEBOOK (0x01) +#define SYNCH_DATA_STORE_CALENDAR (0x03) +#define SYNCH_DATA_STORE_NOTES (0x05) +#define SYNCH_DATA_STORE_MESSAGES (0x06) + +#define DI_VENDOR_ID_SOURCE_BLUETOOTH_SIG (0x0001) +#define DI_VENDOR_ID_SOURCE_USB_IF (0x0002) + +#define PSM_SDP (0x0001) +#define PSM_RFCOMM (0x0003) +#define PSM_TCS_BIN (0x0005) +#define PSM_TCS_BIN_CORDLESS (0x0007) +#define PSM_BNEP (0x000F) +#define PSM_HID_CONTROL (0x0011) +#define PSM_HID_INTERRUPT (0x0013) +#define PSM_AVCTP (0x0017) +#define PSM_AVDTP (0x0019) +#define PSM_UDI_C_PLANE (0x001D) + +// +// Strings +// +#define STR_ADDR_FMTA "(%02x:%02x:%02x:%02x:%02x:%02x)" +#define STR_ADDR_FMTW L"(%02x:%02x:%02x:%02x:%02x:%02x)" + +#define STR_ADDR_SHORT_FMTA "%04x%08x" +#define STR_ADDR_SHORT_FMTW L"%04x%08x" + +#if defined(UNICODE) || defined(BTH_KERN) + +#define STR_ADDR_FMT STR_ADDR_FMTW +#define STR_ADDR_SHORT_FMT STR_ADDR_SHORT_FMTW + +#else // UNICODE + +#define STR_ADDR_FMT STR_ADDR_FMTA +#define STR_ADDR_SHORT_FMT STR_ADDR_SHORT_FMTA + +#endif // UNICODE + +#define GET_BITS(field,offset,mask) ( ( (field) >> (offset) ) & (mask) ) +#define GET_BIT(field,offset) ( GET_BITS(field,offset,0x1) ) + +#define LMP_3_SLOT_PACKETS(x) (GET_BIT(x, 0)) +#define LMP_5_SLOT_PACKETS(x) (GET_BIT(x, 1)) +#define LMP_ENCRYPTION(x) (GET_BIT(x, 2)) +#define LMP_SLOT_OFFSET(x) (GET_BIT(x, 3)) +#define LMP_TIMING_ACCURACY(x) (GET_BIT(x, 4)) +#define LMP_SWITCH(x) (GET_BIT(x, 5)) +#define LMP_HOLD_MODE(x) (GET_BIT(x, 6)) +#define LMP_SNIFF_MODE(x) (GET_BIT(x, 7)) +#define LMP_PARK_MODE(x) (GET_BIT(x, 8)) +#define LMP_RSSI(x) (GET_BIT(x, 9)) +#define LMP_CHANNEL_QUALITY_DRIVEN_MODE(x) (GET_BIT(x,10)) +#define LMP_SCO_LINK(x) (GET_BIT(x,11)) +#define LMP_HV2_PACKETS(x) (GET_BIT(x,12)) +#define LMP_HV3_PACKETS(x) (GET_BIT(x,13)) +#define LMP_MU_LAW_LOG(x) (GET_BIT(x,14)) +#define LMP_A_LAW_LOG(x) (GET_BIT(x,15)) +#define LMP_CVSD(x) (GET_BIT(x,16)) +#define LMP_PAGING_SCHEME(x) (GET_BIT(x,17)) +#define LMP_POWER_CONTROL(x) (GET_BIT(x,18)) +#define LMP_TRANSPARENT_SCO_DATA(x) (GET_BIT(x,19)) +#define LMP_FLOW_CONTROL_LAG(x) (GET_BITS(x,20,0x3)) + +#endif // GUID_DEFS_ONLY + +#endif // __BTHDEF_H__ diff --git a/cpp/wiipair/include/bthsdpdef.h b/cpp/wiipair/include/bthsdpdef.h new file mode 100644 index 0000000..d4027f1 --- /dev/null +++ b/cpp/wiipair/include/bthsdpdef.h @@ -0,0 +1,111 @@ +#ifndef __BTHSDPDEF_H__ +#define __BTHSDPDEF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct SDP_LARGE_INTEGER_16 { + ULONGLONG LowPart; + LONGLONG HighPart; +}; + + +struct SDP_ULARGE_INTEGER_16 { + ULONGLONG LowPart; + ULONGLONG HighPart; +}; + +typedef struct SDP_ULARGE_INTEGER_16 SDP_ULARGE_INTEGER_16, *PSDP_ULARGE_INTEGER_16, *LPSDP_ULARGE_INTEGER_16; +typedef struct SDP_LARGE_INTEGER_16 SDP_LARGE_INTEGER_16, *PSDP_LARGE_INTEGER_16, *LPSDP_LARGE_INTEGER_16; + +enum NodeContainerType { + NodeContainerTypeSequence, + NodeContainerTypeAlternative +}; + +typedef enum NodeContainerType NodeContainerType; + +typedef USHORT SDP_ERROR, *PSDP_ERROR; + +enum SDP_TYPE { + SDP_TYPE_NIL = 0x00, + SDP_TYPE_UINT = 0x01, + SDP_TYPE_INT = 0x02, + SDP_TYPE_UUID = 0x03, + SDP_TYPE_STRING = 0x04, + SDP_TYPE_BOOLEAN = 0x05, + SDP_TYPE_SEQUENCE = 0x06, + SDP_TYPE_ALTERNATIVE = 0x07, + SDP_TYPE_URL = 0x08, + SDP_TYPE_CONTAINER = 0x20 +}; +// 9 - 31 are reserved +typedef enum SDP_TYPE SDP_TYPE; + +// allow for a little easier type checking / sizing for integers and UUIDs +// ((SDP_ST_XXX & 0xF0) >> 4) == SDP_TYPE_XXX +// size of the data (in bytes) is encoded as ((SDP_ST_XXX & 0xF0) >> 8) +enum SDP_SPECIFICTYPE { + SDP_ST_NONE = 0x0000, + + SDP_ST_UINT8 = 0x0010, + SDP_ST_UINT16 = 0x0110, + SDP_ST_UINT32 = 0x0210, + SDP_ST_UINT64 = 0x0310, + SDP_ST_UINT128 = 0x0410, + + SDP_ST_INT8 = 0x0020, + SDP_ST_INT16 = 0x0120, + SDP_ST_INT32 = 0x0220, + SDP_ST_INT64 = 0x0320, + SDP_ST_INT128 = 0x0420, + + SDP_ST_UUID16 = 0x0130, + SDP_ST_UUID32 = 0x0220, + SDP_ST_UUID128 = 0x0430 +}; +typedef enum SDP_SPECIFICTYPE SDP_SPECIFICTYPE; + +typedef struct _SdpAttributeRange { + USHORT minAttribute; + USHORT maxAttribute; +} SdpAttributeRange; + + +typedef +#ifdef USE_MIDL_SYNTAX + [switch_type(unsigned short)] +#endif + union SdpQueryUuidUnion { +#ifdef USE_MIDL_SYNTAX + [case(SDP_ST_UUID128)] +#endif + GUID uuid128; + +#ifdef USE_MIDL_SYNTAX + [case(SDP_ST_UUID32)] +#endif _NTDDK_ + ULONG uuid32; + +#ifdef USE_MIDL_SYNTAX + [case(SDP_ST_UUID16)] +#endif _NTDDK_ + USHORT uuid16; +} SdpQueryUuidUnion; + +typedef struct _SdpQueryUuid { +#ifdef USE_MIDL_SYNTAX + [switch_is(uuidType)] +#endif + SdpQueryUuidUnion u; + + USHORT uuidType; +} SdpQueryUuid; + + +#ifdef __cplusplus +}; +#endif + +#endif // __BTHSDPDEF_H__ diff --git a/cpp/wiipair/include/strsafe.h b/cpp/wiipair/include/strsafe.h new file mode 100644 index 0000000..f725eae --- /dev/null +++ b/cpp/wiipair/include/strsafe.h @@ -0,0 +1,6611 @@ +/****************************************************************** +* * +* strsafe.h -- This module defines safer C library string * +* routine replacements. These are meant to make C * +* a bit more safe in reference to security and * +* robustness * +* * +* Copyright (c) Microsoft Corp. All rights reserved. * +* * +******************************************************************/ +#ifndef _STRSAFE_H_INCLUDED_ +#define _STRSAFE_H_INCLUDED_ +#pragma once + +#include // for _vsnprintf, _vsnwprintf, getc, getwc +#include // for memset +#include // for va_start, etc. + + +#ifndef _SIZE_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 size_t; +#else +typedef __w64 unsigned int size_t; +#endif // !_WIN64 +#define _SIZE_T_DEFINED +#endif // !_SIZE_T_DEFINED + +#if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +typedef long HRESULT; +#endif // !_HRESULT_DEFINED + +#ifndef SUCCEEDED +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#endif + +#ifndef FAILED +#define FAILED(hr) ((HRESULT)(hr) < 0) +#endif + +#ifndef S_OK +#define S_OK ((HRESULT)0x00000000L) +#endif + +#ifdef __cplusplus +#define _STRSAFE_EXTERN_C extern "C" +#else +#define _STRSAFE_EXTERN_C extern +#endif + +// If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then +// #define STRSAFE_LIB before including this header file. +#if defined(STRSAFE_LIB) +#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall +#pragma comment(lib, "strsafe.lib") +#elif defined(STRSAFE_LIB_IMPL) +#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall +#else +#define STRSAFEAPI __inline HRESULT __stdcall +#define STRSAFE_INLINE +#endif + +// Some functions always run inline because they use stdin and we want to avoid building multiple +// versions of strsafe lib depending on if you use msvcrt, libcmt, etc. +#define STRSAFE_INLINE_API __inline HRESULT __stdcall + +// The user can request no "Cb" or no "Cch" fuctions, but not both! +#if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS) +#error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !! +#endif + +// This should only be defined when we are building strsafe.lib +#ifdef STRSAFE_LIB_IMPL +#define STRSAFE_INLINE +#endif + + +// If both strsafe.h and ntstrsafe.h are included, only use definitions from one. +#ifndef _NTSTRSAFE_H_INCLUDED_ + +#define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX) + +// Flags for controling the Ex functions +// +// STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern +#define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers +#define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator +#define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it +#define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0') +#define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it + +#define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION) + +// helper macro to set the fill character and specify buffer filling +#define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL)) +#define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE)) + +#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF)) + +#endif // _NTSTRSAFE_H_INCLUDED_ + +// STRSAFE error return codes +// +#define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER +#define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER +#define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF + +// prototypes for the worker functions +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc); +STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); +STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc); +STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc); +STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc); +STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); +STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend); +STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend); +STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList); +STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList); +STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); +STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); +STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch); +STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch); +#endif // STRSAFE_INLINE + +#ifndef STRSAFE_LIB_IMPL +// these functions are always inline +STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#endif + +#ifdef _NTSTRSAFE_H_INCLUDED_ +#pragma warning(push) +#pragma warning(disable : 4995) +#endif // _NTSTRSAFE_H_INCLUDED_ + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCopy( + OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcpy'. + The size of the destination buffer (in characters) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This routine is not a replacement for strncpy. That function will pad the + destination string with extra null termination characters if the count is + greater than the length of the source string, and it will fail to null + terminate the destination string if the source string length is greater + than or equal to the count. You can not blindly use this instead of strncpy: + it is common for code to use it to "patch" strings and you would introduce + errors if the code started null terminating in the middle of the string. + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was copied without truncation and null terminated, + otherwise it will return a failure code. In failure cases as much of + pszSrc will be copied to pszDest as possible, and pszDest will be null + terminated. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be = (_tcslen(src) + 1) to hold all of the + source including the null terminator + + pszSrc - source string which must be null terminated + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc); +STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); +#ifdef UNICODE +#define StringCchCopy StringCchCopyW +#else +#define StringCchCopy StringCchCopyA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyWorkerA(pszDest, cchDest, pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyWorkerW(pszDest, cchDest, pszSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCopy( + OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcpy'. + The size of the destination buffer (in bytes) is a parameter and this + function will not write past the end of this buffer and it will ALWAYS + null terminate the destination buffer (unless it is zero length). + + This routine is not a replacement for strncpy. That function will pad the + destination string with extra null termination characters if the count is + greater than the length of the source string, and it will fail to null + terminate the destination string if the source string length is greater + than or equal to the count. You can not blindly use this instead of strncpy: + it is common for code to use it to "patch" strings and you would introduce + errors if the code started null terminating in the middle of the string. + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was copied without truncation and null terminated, + otherwise it will return a failure code. In failure cases as much of pszSrc + will be copied to pszDest as possible, and pszDest will be null terminated. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to + hold all of the source including the null terminator + + pszSrc - source string which must be null terminated + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc); +STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc); +#ifdef UNICODE +#define StringCbCopy StringCbCopyW +#else +#define StringCbCopy StringCbCopyA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc) +{ + HRESULT hr; + size_t cchDest; + + // convert to count of characters + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyWorkerA(pszDest, cchDest, pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc) +{ + HRESULT hr; + size_t cchDest; + + // convert to count of characters + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyWorkerW(pszDest, cchDest, pszSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCopyEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + IN LPCTSTR pszSrc OPTIONAL, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcpy' with + some additional parameters. In addition to functionality provided by + StringCchCopy, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be = (_tcslen(pszSrc) + 1) to hold all of + the source including the null terminator + + pszSrc - source string which must be null terminated + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return the + number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcpy + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCchCopyEx StringCchCopyExW +#else +#define StringCchCopyEx StringCchCopyExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} + +STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCopyEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + IN LPCTSTR pszSrc OPTIONAL, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcpy' with + some additional parameters. In addition to functionality provided by + StringCbCopy, this routine also returns a pointer to the end of the + destination string and the number of bytes left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to + hold all of the source including the null terminator + + pszSrc - source string which must be null terminated + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcbRemaining - pcbRemaining is non-null,the function will return the + number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcpy + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCbCopyEx StringCbCopyExW +#else +#define StringCbCopyEx StringCbCopyExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCopyN( + OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszSrc, + IN size_t cchSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncpy'. + The size of the destination buffer (in characters) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This routine is meant as a replacement for strncpy, but it does behave + differently. This function will not pad the destination buffer with extra + null termination characters if cchSrc is greater than the length of pszSrc. + + This function returns a hresult, and not a pointer. It returns + S_OK if the entire string or the first cchSrc characters were copied + without truncation and the resultant destination string was null terminated, + otherwise it will return a failure code. In failure cases as much of pszSrc + will be copied to pszDest as possible, and pszDest will be null terminated. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be = (_tcslen(src) + 1) to hold all of the + source including the null terminator + + pszSrc - source string + + cchSrc - maximum number of characters to copy from source string, + not including the null terminator. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc); +STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc); +#ifdef UNICODE +#define StringCchCopyN StringCchCopyNW +#else +#define StringCchCopyN StringCchCopyNA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc) +{ + HRESULT hr; + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc); + } + + return hr; +} + +STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc) +{ + HRESULT hr; + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCopyN( + OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszSrc, + IN size_t cbSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncpy'. + The size of the destination buffer (in bytes) is a parameter and this + function will not write past the end of this buffer and it will ALWAYS + null terminate the destination buffer (unless it is zero length). + + This routine is meant as a replacement for strncpy, but it does behave + differently. This function will not pad the destination buffer with extra + null termination characters if cbSrc is greater than the size of pszSrc. + + This function returns a hresult, and not a pointer. It returns + S_OK if the entire string or the first cbSrc characters were + copied without truncation and the resultant destination string was null + terminated, otherwise it will return a failure code. In failure cases as + much of pszSrc will be copied to pszDest as possible, and pszDest will be + null terminated. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to + hold all of the source including the null terminator + + pszSrc - source string + + cbSrc - maximum number of bytes to copy from source string, + not including the null terminator. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc); +STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc); +#ifdef UNICODE +#define StringCbCopyN StringCbCopyNW +#else +#define StringCbCopyN StringCbCopyNA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc) +{ + HRESULT hr; + size_t cchDest; + size_t cchSrc; + + // convert to count of characters + cchDest = cbDest / sizeof(char); + cchSrc = cbSrc / sizeof(char); + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc); + } + + return hr; +} + +STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc) +{ + HRESULT hr; + size_t cchDest; + size_t cchSrc; + + // convert to count of characters + cchDest = cbDest / sizeof(wchar_t); + cchSrc = cbSrc / sizeof(wchar_t); + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCopyNEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + IN LPCTSTR pszSrc OPTIONAL, + IN size_t cchSrc, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncpy' with + some additional parameters. In addition to functionality provided by + StringCchCopyN, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination + string including the null terminator. The flags parameter allows + additional controls. + + This routine is meant as a replacement for strncpy, but it does behave + differently. This function will not pad the destination buffer with extra + null termination characters if cchSrc is greater than the length of pszSrc. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be = (_tcslen(pszSrc) + 1) to hold all of + the source including the null terminator + + pszSrc - source string + + cchSrc - maximum number of characters to copy from the source + string + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return the + number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcpy + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCchCopyNEx StringCchCopyNExW +#else +#define StringCchCopyNEx StringCchCopyNExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} + +STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCopyNEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + IN LPCTSTR pszSrc OPTIONAL, + IN size_t cbSrc, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncpy' with + some additional parameters. In addition to functionality provided by + StringCbCopyN, this routine also returns a pointer to the end of the + destination string and the number of bytes left in the destination string + including the null terminator. The flags parameter allows additional controls. + + This routine is meant as a replacement for strncpy, but it does behave + differently. This function will not pad the destination buffer with extra + null termination characters if cbSrc is greater than the size of pszSrc. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to + hold all of the source including the null terminator + + pszSrc - source string + + cbSrc - maximum number of bytes to copy from source string + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcbRemaining - pcbRemaining is non-null,the function will return the + number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcpy + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all copied and the + resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the copy + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCbCopyNEx StringCbCopyNExW +#else +#define StringCbCopyNEx StringCbCopyNExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchSrc; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + cchSrc = cbSrc / sizeof(char); + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchSrc; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + cchSrc = cbSrc / sizeof(wchar_t); + + if ((cchDest > STRSAFE_MAX_CCH) || + (cchSrc > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCat( + IN OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcat'. + The size of the destination buffer (in characters) is a parameter and this + function will not write past the end of this buffer and it will ALWAYS + null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was concatenated without truncation and null terminated, + otherwise it will return a failure code. In failure cases as much of pszSrc + will be appended to pszDest as possible, and pszDest will be null + terminated. + +Arguments: + + pszDest - destination string which must be null terminated + + cchDest - size of destination buffer in characters. + length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1) + to hold all of the combine string plus the null + terminator + + pszSrc - source string which must be null terminated + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCchCatEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error occurs, + the destination buffer is modified to contain a truncated + version of the ideal result and is null terminated. This + is useful for situations where truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc); +STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); +#ifdef UNICODE +#define StringCchCat StringCchCatW +#else +#define StringCchCat StringCchCatA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatWorkerA(pszDest, cchDest, pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatWorkerW(pszDest, cchDest, pszSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCat( + IN OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszSrc + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcat'. + The size of the destination buffer (in bytes) is a parameter and this + function will not write past the end of this buffer and it will ALWAYS + null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was concatenated without truncation and null terminated, + otherwise it will return a failure code. In failure cases as much of pszSrc + will be appended to pszDest as possible, and pszDest will be null + terminated. + +Arguments: + + pszDest - destination string which must be null terminated + + cbDest - size of destination buffer in bytes. + length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR) + to hold all of the combine string plus the null + terminator + + pszSrc - source string which must be null terminated + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCbCatEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error occurs, + the destination buffer is modified to contain a truncated + version of the ideal result and is null terminated. This + is useful for situations where truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc); +STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc); +#ifdef UNICODE +#define StringCbCat StringCbCatW +#else +#define StringCbCat StringCbCatA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatWorkerA(pszDest, cchDest, pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatWorkerW(pszDest, cchDest, pszSrc); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCatEx( + IN OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + IN LPCTSTR pszSrc OPTIONAL, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcat' with + some additional parameters. In addition to functionality provided by + StringCchCat, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string which must be null terminated + + cchDest - size of destination buffer in characters + length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string which must be null terminated + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function appended any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return the + number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcat + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any pre-existing + or truncated string + + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any pre-existing or + truncated string + + STRSAFE_NO_TRUNCATION + if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest + will not contain a truncated string, it will remain unchanged. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCchCatEx StringCchCatExW +#else +#define StringCchCatEx StringCchCatExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} + +STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCatEx( + IN OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + IN LPCTSTR pszSrc OPTIONAL, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strcat' with + some additional parameters. In addition to functionality provided by + StringCbCat, this routine also returns a pointer to the end of the + destination string and the number of bytes left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string which must be null terminated + + cbDest - size of destination buffer in bytes. + length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string which must be null terminated + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function appended any data, the result will point to the + null termination character + + pcbRemaining - if pcbRemaining is non-null, the function will return + the number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + this flag is useful for emulating functions like lstrcat + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any pre-existing + or truncated string + + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any pre-existing or + truncated string + + STRSAFE_NO_TRUNCATION + if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest + will not contain a truncated string, it will remain unchanged. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated + and the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCbCatEx StringCbCatExW +#else +#define StringCbCatEx StringCbCatExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCatN( + IN OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszSrc, + IN size_t cchMaxAppend + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncat'. + The size of the destination buffer (in characters) is a parameter as well as + the maximum number of characters to append, excluding the null terminator. + This function will not write past the end of the destination buffer and it will + ALWAYS null terminate pszDest (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if all of pszSrc or the first cchMaxAppend characters were appended + to the destination string and it was null terminated, otherwise it will + return a failure code. In failure cases as much of pszSrc will be appended + to pszDest as possible, and pszDest will be null terminated. + +Arguments: + + pszDest - destination string which must be null terminated + + cchDest - size of destination buffer in characters. + length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string + + cchMaxAppend - maximum number of characters to append + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if all of pszSrc or the first cchMaxAppend characters + were concatenated to pszDest and the resultant dest + string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend); +STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend); +#ifdef UNICODE +#define StringCchCatN StringCchCatNW +#else +#define StringCchCatN StringCchCatNA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend); + } + + return hr; +} + +STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCatN( + IN OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszSrc, + IN size_t cbMaxAppend + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncat'. + The size of the destination buffer (in bytes) is a parameter as well as + the maximum number of bytes to append, excluding the null terminator. + This function will not write past the end of the destination buffer and it will + ALWAYS null terminate pszDest (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if all of pszSrc or the first cbMaxAppend bytes were appended + to the destination string and it was null terminated, otherwise it will + return a failure code. In failure cases as much of pszSrc will be appended + to pszDest as possible, and pszDest will be null terminated. + +Arguments: + + pszDest - destination string which must be null terminated + + cbDest - size of destination buffer in bytes. + length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string + + cbMaxAppend - maximum number of bytes to append + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require + the handling of NULL values. + +Return Value: + + S_OK - if all of pszSrc or the first cbMaxAppend bytes were + concatenated to pszDest and the resultant dest string + was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend); +STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend); +#ifdef UNICODE +#define StringCbCatN StringCbCatNW +#else +#define StringCbCatN StringCbCatNA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchMaxAppend; + + cchMaxAppend = cbMaxAppend / sizeof(char); + + hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend); + } + + return hr; +} + +STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchMaxAppend; + + cchMaxAppend = cbMaxAppend / sizeof(wchar_t); + + hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchCatNEx( + IN OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + IN LPCTSTR pszSrc OPTIONAL, + IN size_t cchMaxAppend, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncat', with + some additional parameters. In addition to functionality provided by + StringCchCatN, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string which must be null terminated + + cchDest - size of destination buffer in characters. + length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string + + cchMaxAppend - maximum number of characters to append + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function appended any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return the + number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any pre-existing + or truncated string + + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any pre-existing or + truncated string + + STRSAFE_NO_TRUNCATION + if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest + will not contain a truncated string, it will remain unchanged. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if all of pszSrc or the first cchMaxAppend characters + were concatenated to pszDest and the resultant dest + string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCchCatNEx StringCchCatNExW +#else +#define StringCchCatNEx StringCchCatNExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} + +STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbCatNEx( + IN OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + IN LPCTSTR pszSrc OPTIONAL, + IN size_t cbMaxAppend, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strncat', with + some additional parameters. In addition to functionality provided by + StringCbCatN, this routine also returns a pointer to the end of the + destination string and the number of bytes left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string which must be null terminated + + cbDest - size of destination buffer in bytes. + length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR) + to hold all of the combine string plus the null + terminator. + + pszSrc - source string + + cbMaxAppend - maximum number of bytes to append + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function appended any data, the result will point to the + null termination character + + pcbRemaining - if pcbRemaining is non-null, the function will return the + number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any pre-existing + or truncated string + + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any pre-existing or + truncated string + + STRSAFE_NO_TRUNCATION + if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest + will not contain a truncated string, it will remain unchanged. + +Notes: + Behavior is undefined if source and destination strings overlap. + + pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag + is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc + may be NULL. An error may still be returned even though NULLS are ignored + due to insufficient space. + +Return Value: + + S_OK - if all of pszSrc or the first cbMaxAppend bytes were + concatenated to pszDest and the resultant dest string + was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the operation + failed due to insufficient space. When this error + occurs, the destination buffer is modified to contain + a truncated version of the ideal result and is null + terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCbCatNEx StringCbCatNExW +#else +#define StringCbCatNEx StringCbCatNExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchMaxAppend; + + cchMaxAppend = cbMaxAppend / sizeof(char); + + hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchMaxAppend; + + cchMaxAppend = cbMaxAppend / sizeof(wchar_t); + + hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchVPrintf( + OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszFormat, + IN va_list argList + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'vsprintf'. + The size of the destination buffer (in characters) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was printed without truncation and null terminated, + otherwise it will return a failure code. In failure cases it will return + a truncated version of the ideal result. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters + length must be sufficient to hold the resulting formatted + string, including the null terminator. + + pszFormat - format string which must be null terminated + + argList - va_list from the variable arguments according to the + stdarg.h convention + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you + require the handling of NULL values. + +Return Value: + + S_OK - if there was sufficient space in the dest buffer for + the resultant string and it was null terminated. + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList); +STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList); +#ifdef UNICODE +#define StringCchVPrintf StringCchVPrintfW +#else +#define StringCchVPrintf StringCchVPrintfA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); + } + + return hr; +} + +STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbVPrintf( + OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszFormat, + IN va_list argList + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'vsprintf'. + The size of the destination buffer (in bytes) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was printed without truncation and null terminated, + otherwise it will return a failure code. In failure cases it will return + a truncated version of the ideal result. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes + length must be sufficient to hold the resulting formatted + string, including the null terminator. + + pszFormat - format string which must be null terminated + + argList - va_list from the variable arguments according to the + stdarg.h convention + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you + require the handling of NULL values. + + +Return Value: + + S_OK - if there was sufficient space in the dest buffer for + the resultant string and it was null terminated. + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList); +STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList); +#ifdef UNICODE +#define StringCbVPrintf StringCbVPrintfW +#else +#define StringCbVPrintf StringCbVPrintfA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); + } + + return hr; +} + +STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchPrintf( + OUT LPTSTR pszDest, + IN size_t cchDest, + IN LPCTSTR pszFormat, + ... + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'sprintf'. + The size of the destination buffer (in characters) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was printed without truncation and null terminated, + otherwise it will return a failure code. In failure cases it will return + a truncated version of the ideal result. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters + length must be sufficient to hold the resulting formatted + string, including the null terminator. + + pszFormat - format string which must be null terminated + + ... - additional parameters to be formatted according to + the format string + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you + require the handling of NULL values. + +Return Value: + + S_OK - if there was sufficient space in the dest buffer for + the resultant string and it was null terminated. + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...); +STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...); +#ifdef UNICODE +#define StringCchPrintf StringCchPrintfW +#else +#define StringCchPrintf StringCchPrintfA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); + + va_end(argList); + } + + return hr; +} + +STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); + + va_end(argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbPrintf( + OUT LPTSTR pszDest, + IN size_t cbDest, + IN LPCTSTR pszFormat, + ... + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'sprintf'. + The size of the destination buffer (in bytes) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This function returns a hresult, and not a pointer. It returns + S_OK if the string was printed without truncation and null terminated, + otherwise it will return a failure code. In failure cases it will return + a truncated version of the ideal result. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes + length must be sufficient to hold the resulting formatted + string, including the null terminator. + + pszFormat - format string which must be null terminated + + ... - additional parameters to be formatted according to + the format string + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you + require the handling of NULL values. + + +Return Value: + + S_OK - if there was sufficient space in the dest buffer for + the resultant string and it was null terminated. + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...); +STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...); +#ifdef UNICODE +#define StringCbPrintf StringCbPrintfW +#else +#define StringCbPrintf StringCbPrintfA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); + + va_end(argList); + } + + return hr; +} + +STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...) +{ + HRESULT hr; + size_t cchDest; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); + + va_end(argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchPrintfEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags, + IN LPCTSTR pszFormat OPTIONAL, + ... + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'sprintf' with + some additional parameters. In addition to functionality provided by + StringCchPrintf, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be sufficient to contain the resulting + formatted string plus the null terminator. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function printed any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return + the number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + + pszFormat - format string which must be null terminated + + ... - additional parameters to be formatted according to + the format string + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS + flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and + pszFormat may be NULL. An error may still be returned even though NULLS + are ignored due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...); +STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...); +#ifdef UNICODE +#define StringCchPrintfEx StringCchPrintfExW +#else +#define StringCchPrintfEx StringCchPrintfExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + va_list argList; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + va_start(argList, pszFormat); + + hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); + + va_end(argList); + } + + return hr; +} + +STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + va_list argList; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + va_start(argList, pszFormat); + + hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); + + va_end(argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbPrintfEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags, + IN LPCTSTR pszFormat OPTIONAL, + ... + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'sprintf' with + some additional parameters. In addition to functionality provided by + StringCbPrintf, this routine also returns a pointer to the end of the + destination string and the number of bytes left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be sufficient to contain the resulting + formatted string plus the null terminator. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function printed any data, the result will point to the + null termination character + + pcbRemaining - if pcbRemaining is non-null, the function will return + the number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + + pszFormat - format string which must be null terminated + + ... - additional parameters to be formatted according to + the format string + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS + flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and + pszFormat may be NULL. An error may still be returned even though NULLS + are ignored due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...); +STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...); +#ifdef UNICODE +#define StringCbPrintfEx StringCbPrintfExW +#else +#define StringCbPrintfEx StringCbPrintfExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); + + va_end(argList); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + va_list argList; + + va_start(argList, pszFormat); + + hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); + + va_end(argList); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchVPrintfEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags, + IN LPCTSTR pszFormat OPTIONAL, + IN va_list argList + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'vsprintf' with + some additional parameters. In addition to functionality provided by + StringCchVPrintf, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + length must be sufficient to contain the resulting + formatted string plus the null terminator. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function printed any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return + the number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + + pszFormat - format string which must be null terminated + + argList - va_list from the variable arguments according to the + stdarg.h convention + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS + flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and + pszFormat may be NULL. An error may still be returned even though NULLS + are ignored due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); +STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); +#ifdef UNICODE +#define StringCchVPrintfEx StringCchVPrintfExW +#else +#define StringCchVPrintfEx StringCchVPrintfExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); + } + + return hr; +} + +STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbVPrintfEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags, + IN LPCTSTR pszFormat OPTIONAL, + IN va_list argList + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'vsprintf' with + some additional parameters. In addition to functionality provided by + StringCbVPrintf, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + length must be sufficient to contain the resulting + formatted string plus the null terminator. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return + a pointer to the end of the destination string. If the + function printed any data, the result will point to the + null termination character + + pcbRemaining - if pcbRemaining is non-null, the function will return + the number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")) + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. This will overwrite any truncated + string returned when the failure is + STRSAFE_E_INSUFFICIENT_BUFFER + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. This will overwrite any truncated string + returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. + + pszFormat - format string which must be null terminated + + argList - va_list from the variable arguments according to the + stdarg.h convention + +Notes: + Behavior is undefined if destination, format strings or any arguments + strings overlap. + + pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS + flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and + pszFormat may be NULL. An error may still be returned even though NULLS + are ignored due to insufficient space. + +Return Value: + + S_OK - if there was source data and it was all concatenated and + the resultant dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that the print + operation failed due to insufficient space. When this + error occurs, the destination buffer is modified to + contain a truncated version of the ideal result and is + null terminated. This is useful for situations where + truncation is ok. + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function + +--*/ + +STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); +STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); +#ifdef UNICODE +#define StringCbVPrintfEx StringCbVPrintfExW +#else +#define StringCbVPrintfEx StringCbVPrintfExA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchGets( + OUT LPTSTR pszDest, + IN size_t cchDest + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'gets'. + The size of the destination buffer (in characters) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This routine is not a replacement for fgets. That function does not replace + newline characters with a null terminator. + + This function returns a hresult, and not a pointer. It returns + S_OK if any characters were read from stdin and copied to pszDest and + pszDest was null terminated, otherwise it will return a failure code. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + +Notes: + pszDest should not be NULL. See StringCchGetsEx if you require the handling + of NULL values. + + cchDest must be > 1 for this function to succeed. + +Return Value: + + S_OK - data was read from stdin and copied, and the resultant + dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_END_OF_FILE / + HRESULT_CODE(hr) == ERROR_HANDLE_EOF + - this return value indicates an error or end-of-file + condition, use feof or ferror to determine which one has + occured. + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that there was + insufficient space in the destination buffer to copy any + data + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +#ifndef STRSAFE_LIB_IMPL +STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest); +STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest); +#ifdef UNICODE +#define StringCchGets StringCchGetsW +#else +#define StringCchGets StringCchGetsA +#endif // !UNICODE + +STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0); + } + + return hr; +} + +STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0); + } + + return hr; +} +#endif // !STRSAFE_NO_CCH_FUNCTIONS +#endif // !STRSAFE_LIB_IMPL + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbGets( + OUT LPTSTR pszDest, + IN size_t cbDest + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'gets'. + The size of the destination buffer (in bytes) is a parameter and + this function will not write past the end of this buffer and it will + ALWAYS null terminate the destination buffer (unless it is zero length). + + This routine is not a replacement for fgets. That function does not replace + newline characters with a null terminator. + + This function returns a hresult, and not a pointer. It returns + S_OK if any characters were read from stdin and copied to pszDest + and pszDest was null terminated, otherwise it will return a failure code. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + +Notes: + pszDest should not be NULL. See StringCbGetsEx if you require the handling + of NULL values. + + cbDest must be > sizeof(TCHAR) for this function to succeed. + +Return Value: + + S_OK - data was read from stdin and copied, and the resultant + dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_END_OF_FILE / + HRESULT_CODE(hr) == ERROR_HANDLE_EOF + - this return value indicates an error or end-of-file + condition, use feof or ferror to determine which one has + occured. + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that there was + insufficient space in the destination buffer to copy any + data + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +#ifndef STRSAFE_LIB_IMPL +STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest); +STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest); +#ifdef UNICODE +#define StringCbGets StringCbGetsW +#else +#define StringCbGets StringCbGetsA +#endif // !UNICODE + +STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest) +{ + HRESULT hr; + size_t cchDest; + + // convert to count of characters + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0); + } + + return hr; +} + +STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest) +{ + HRESULT hr; + size_t cchDest; + + // convert to count of characters + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0); + } + + return hr; +} +#endif // !STRSAFE_NO_CB_FUNCTIONS +#endif // !STRSAFE_LIB_IMPL + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchGetsEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cchDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcchRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'gets' with + some additional parameters. In addition to functionality provided by + StringCchGets, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cchDest - size of destination buffer in characters. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcchRemaining - if pcchRemaining is non-null, the function will return the + number of characters left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. + +Notes: + pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified. + If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be + returned even though NULLS are ignored + + cchDest must be > 1 for this function to succeed. + +Return Value: + + S_OK - data was read from stdin and copied, and the resultant + dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_END_OF_FILE / + HRESULT_CODE(hr) == ERROR_HANDLE_EOF + - this return value indicates an error or end-of-file + condition, use feof or ferror to determine which one has + occured. + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that there was + insufficient space in the destination buffer to copy any + data + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +#ifndef STRSAFE_LIB_IMPL +STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCchGetsEx StringCchGetsExW +#else +#define StringCchGetsEx StringCchGetsExA +#endif // !UNICODE + +STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 + cbDest = cchDest * sizeof(char); + + hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} + +STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr; + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cbDest; + + // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + cbDest = cchDest * sizeof(wchar_t); + + hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags); + } + + return hr; +} +#endif // !STRSAFE_NO_CCH_FUNCTIONS +#endif // !STRSAFE_LIB_IMPL + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbGetsEx( + OUT LPTSTR pszDest OPTIONAL, + IN size_t cbDest, + OUT LPTSTR* ppszDestEnd OPTIONAL, + OUT size_t* pcbRemaining OPTIONAL, + IN DWORD dwFlags + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'gets' with + some additional parameters. In addition to functionality provided by + StringCbGets, this routine also returns a pointer to the end of the + destination string and the number of characters left in the destination string + including the null terminator. The flags parameter allows additional controls. + +Arguments: + + pszDest - destination string + + cbDest - size of destination buffer in bytes. + + ppszDestEnd - if ppszDestEnd is non-null, the function will return a + pointer to the end of the destination string. If the + function copied any data, the result will point to the + null termination character + + pcbRemaining - if pbRemaining is non-null, the function will return the + number of bytes left in the destination string, + including the null terminator + + dwFlags - controls some details of the string copy: + + STRSAFE_FILL_BEHIND_NULL + if the function succeeds, the low byte of dwFlags will be + used to fill the uninitialize part of destination buffer + behind the null terminator + + STRSAFE_IGNORE_NULLS + treat NULL string pointers like empty strings (TEXT("")). + + STRSAFE_FILL_ON_FAILURE + if the function fails, the low byte of dwFlags will be + used to fill all of the destination buffer, and it will + be null terminated. + + STRSAFE_NO_TRUNCATION / + STRSAFE_NULL_ON_FAILURE + if the function fails, the destination buffer will be set + to the empty string. + +Notes: + pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified. + If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be + returned even though NULLS are ignored + + cbDest must be > sizeof(TCHAR) for this function to succeed + +Return Value: + + S_OK - data was read from stdin and copied, and the resultant + dest string was null terminated + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + STRSAFE_E_END_OF_FILE / + HRESULT_CODE(hr) == ERROR_HANDLE_EOF + - this return value indicates an error or end-of-file + condition, use feof or ferror to determine which one has + occured. + + STRSAFE_E_INSUFFICIENT_BUFFER / + HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER + - this return value is an indication that there was + insufficient space in the destination buffer to copy any + data + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +#ifndef STRSAFE_LIB_IMPL +STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags); +STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); +#ifdef UNICODE +#define StringCbGetsEx StringCbGetsExW +#else +#define StringCbGetsEx StringCbGetsExA +#endif // !UNICODE + +STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(char); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || + (hr == STRSAFE_E_INSUFFICIENT_BUFFER) || + (hr == STRSAFE_E_END_OF_FILE)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); + } + } + + return hr; +} + +STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) +{ + HRESULT hr; + size_t cchDest; + size_t cchRemaining = 0; + + cchDest = cbDest / sizeof(wchar_t); + + if (cchDest > STRSAFE_MAX_CCH) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags); + } + + if (SUCCEEDED(hr) || + (hr == STRSAFE_E_INSUFFICIENT_BUFFER) || + (hr == STRSAFE_E_END_OF_FILE)) + { + if (pcbRemaining) + { + // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); + } + } + + return hr; +} +#endif // !STRSAFE_NO_CB_FUNCTIONS +#endif // !STRSAFE_LIB_IMPL + +#ifndef STRSAFE_NO_CCH_FUNCTIONS +/*++ + +STDAPI +StringCchLength( + IN LPCTSTR psz, + IN size_t cchMax, + OUT size_t* pcch OPTIONAL + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strlen'. + It is used to make sure a string is not larger than a given length, and + it optionally returns the current length in characters not including + the null terminator. + + This function returns a hresult, and not a pointer. It returns + S_OK if the string is non-null and the length including the null + terminator is less than or equal to cchMax characters. + +Arguments: + + psz - string to check the length of + + cchMax - maximum number of characters including the null terminator + that psz is allowed to contain + + pcch - if the function succeeds and pcch is non-null, the current length + in characters of psz excluding the null terminator will be returned. + This out parameter is equivalent to the return value of strlen(psz) + +Notes: + psz can be null but the function will fail + + cchMax should be greater than zero or the function will fail + +Return Value: + + S_OK - psz is non-null and the length including the null + terminator is less than or equal to cchMax characters + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch); +STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch); +#ifdef UNICODE +#define StringCchLength StringCchLengthW +#else +#define StringCchLength StringCchLengthA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch) +{ + HRESULT hr; + + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringLengthWorkerA(psz, cchMax, pcch); + } + + return hr; +} + +STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch) +{ + HRESULT hr; + + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringLengthWorkerW(psz, cchMax, pcch); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CCH_FUNCTIONS + + +#ifndef STRSAFE_NO_CB_FUNCTIONS +/*++ + +STDAPI +StringCbLength( + IN LPCTSTR psz, + IN size_t cbMax, + OUT size_t* pcb OPTIONAL + ); + +Routine Description: + + This routine is a safer version of the C built-in function 'strlen'. + It is used to make sure a string is not larger than a given length, and + it optionally returns the current length in bytes not including + the null terminator. + + This function returns a hresult, and not a pointer. It returns + S_OK if the string is non-null and the length including the null + terminator is less than or equal to cbMax bytes. + +Arguments: + + psz - string to check the length of + + cbMax - maximum number of bytes including the null terminator + that psz is allowed to contain + + pcb - if the function succeeds and pcb is non-null, the current length + in bytes of psz excluding the null terminator will be returned. + This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR) + +Notes: + psz can be null but the function will fail + + cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail + +Return Value: + + S_OK - psz is non-null and the length including the null + terminator is less than or equal to cbMax bytes + + failure - you can use the macro HRESULT_CODE() to get a win32 + error code for all hresult failure cases + + It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the + return value of this function. + +--*/ + +STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch); +STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch); +#ifdef UNICODE +#define StringCbLength StringCbLengthW +#else +#define StringCbLength StringCbLengthA +#endif // !UNICODE + +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb) +{ + HRESULT hr; + size_t cchMax; + size_t cch = 0; + + cchMax = cbMax / sizeof(char); + + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringLengthWorkerA(psz, cchMax, &cch); + } + + if (SUCCEEDED(hr) && pcb) + { + // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1 + *pcb = cch * sizeof(char); + } + + return hr; +} + +STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb) +{ + HRESULT hr; + size_t cchMax; + size_t cch = 0; + + cchMax = cbMax / sizeof(wchar_t); + + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = StringLengthWorkerW(psz, cchMax, &cch); + } + + if (SUCCEEDED(hr) && pcb) + { + // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 + *pcb = cch * sizeof(wchar_t); + } + + return hr; +} +#endif // STRSAFE_INLINE +#endif // !STRSAFE_NO_CB_FUNCTIONS + + +// these are the worker functions that actually do the work +#ifdef STRSAFE_INLINE +STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + while (cchDest && (*pszSrc != '\0')) + { + *pszDest++ = *pszSrc++; + cchDest--; + } + + if (cchDest == 0) + { + // we are going to truncate pszDest + pszDest--; + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDest= '\0'; + } + + return hr; +} + +STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + while (cchDest && (*pszSrc != L'\0')) + { + *pszDest++ = *pszSrc++; + cchDest--; + } + + if (cchDest == 0) + { + // we are going to truncate pszDest + pszDest--; + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDest= L'\0'; + } + + return hr; +} + +STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszSrc == NULL) + { + pszSrc = ""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually src data to copy + if (*pszSrc != '\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while (cchRemaining && (*pszSrc != '\0')) + { + *pszDestEnd++= *pszSrc++; + cchRemaining--; + } + + if (cchRemaining > 0) + { + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); + } + } + else + { + // we are going to truncate pszDest + pszDestEnd--; + cchRemaining++; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDestEnd = '\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || + // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszSrc == NULL) + { + pszSrc = L""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually src data to copy + if (*pszSrc != L'\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while (cchRemaining && (*pszSrc != L'\0')) + { + *pszDestEnd++= *pszSrc++; + cchRemaining--; + } + + if (cchRemaining > 0) + { + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + } + } + else + { + // we are going to truncate pszDest + pszDestEnd--; + cchRemaining++; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDestEnd = L'\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + while (cchDest && cchSrc && (*pszSrc != '\0')) + { + *pszDest++= *pszSrc++; + cchDest--; + cchSrc--; + } + + if (cchDest == 0) + { + // we are going to truncate pszDest + pszDest--; + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDest= '\0'; + } + + return hr; +} + +STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + while (cchDest && cchSrc && (*pszSrc != L'\0')) + { + *pszDest++= *pszSrc++; + cchDest--; + cchSrc--; + } + + if (cchDest == 0) + { + // we are going to truncate pszDest + pszDest--; + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDest= L'\0'; + } + + return hr; +} + +STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszSrc == NULL) + { + pszSrc = ""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually src data to copy + if (*pszSrc != '\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while (cchRemaining && cchSrc && (*pszSrc != '\0')) + { + *pszDestEnd++= *pszSrc++; + cchRemaining--; + cchSrc--; + } + + if (cchRemaining > 0) + { + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); + } + } + else + { + // we are going to truncate pszDest + pszDestEnd--; + cchRemaining++; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDestEnd = '\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || + // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszSrc == NULL) + { + pszSrc = L""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually src data to copy + if (*pszSrc != L'\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while (cchRemaining && cchSrc && (*pszSrc != L'\0')) + { + *pszDestEnd++= *pszSrc++; + cchRemaining--; + cchSrc--; + } + + if (cchRemaining > 0) + { + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + } + } + else + { + // we are going to truncate pszDest + pszDestEnd--; + cchRemaining++; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + + *pszDestEnd = L'\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc) +{ + HRESULT hr; + size_t cchDestCurrent; + + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + hr = StringCopyWorkerA(pszDest + cchDestCurrent, + cchDest - cchDestCurrent, + pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) +{ + HRESULT hr; + size_t cchDestCurrent; + + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + hr = StringCopyWorkerW(pszDest + cchDestCurrent, + cchDest - cchDestCurrent, + pszSrc); + } + + return hr; +} + +STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchDestCurrent; + + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest == 0) && (cbDest == 0)) + { + cchDestCurrent = 0; + } + else + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + else + { + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (pszSrc == NULL) + { + pszSrc = ""; + } + } + else + { + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + // only fail if there was actually src data to append + if (*pszSrc != '\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass + // those flags through + hr = StringCopyExWorkerA(pszDestEnd, + cchRemaining, + (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), + pszSrc, + &pszDestEnd, + &cchRemaining, + dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA() + + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else + if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & STRSAFE_NULL_ON_FAILURE) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || + // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + size_t cchDestCurrent; + + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest == 0) && (cbDest == 0)) + { + cchDestCurrent = 0; + } + else + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + else + { + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (pszSrc == NULL) + { + pszSrc = L""; + } + } + else + { + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + // only fail if there was actually src data to append + if (*pszSrc != L'\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass + // those flags through + hr = StringCopyExWorkerW(pszDestEnd, + cchRemaining, + (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), + pszSrc, + &pszDestEnd, + &cchRemaining, + dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW() + + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & STRSAFE_NULL_ON_FAILURE) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend) +{ + HRESULT hr; + size_t cchDestCurrent; + + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + hr = StringCopyNWorkerA(pszDest + cchDestCurrent, + cchDest - cchDestCurrent, + pszSrc, + cchMaxAppend); + } + + return hr; +} + +STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend) +{ + HRESULT hr; + size_t cchDestCurrent; + + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + hr = StringCopyNWorkerW(pszDest + cchDestCurrent, + cchDest - cchDestCurrent, + pszSrc, + cchMaxAppend); + } + + return hr; +} + +STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + size_t cchDestCurrent = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest == 0) && (cbDest == 0)) + { + cchDestCurrent = 0; + } + else + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + else + { + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (pszSrc == NULL) + { + pszSrc = ""; + } + } + else + { + hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + // only fail if there was actually src data to append + if (*pszSrc != '\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass + // those flags through + hr = StringCopyNExWorkerA(pszDestEnd, + cchRemaining, + (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), + pszSrc, + cchMaxAppend, + &pszDestEnd, + &cchRemaining, + dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA() + + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + size_t cchDestCurrent = 0; + + + // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || + // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest == 0) && (cbDest == 0)) + { + cchDestCurrent = 0; + } + else + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + else + { + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (pszSrc == NULL) + { + pszSrc = L""; + } + } + else + { + hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); + + if (SUCCEEDED(hr)) + { + pszDestEnd = pszDest + cchDestCurrent; + cchRemaining = cchDest - cchDestCurrent; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + // only fail if there was actually src data to append + if (*pszSrc != L'\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass + // those flags through + hr = StringCopyNExWorkerW(pszDestEnd, + cchRemaining, + (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), + pszSrc, + cchMaxAppend, + &pszDestEnd, + &cchRemaining, + dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW() + + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + int iRet; + size_t cchMax; + + // leave the last space for the null terminator + cchMax = cchDest - 1; + + iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; + + // we have truncated pszDest + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; + } + } + + return hr; +} + +STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr = S_OK; + + if (cchDest == 0) + { + // can not null terminate a zero-byte dest buffer + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + int iRet; + size_t cchMax; + + // leave the last space for the null terminator + cchMax = cchDest - 1; + + iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList); + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = L'\0'; + + // we have truncated pszDest + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = L'\0'; + } + } + + return hr; +} + +STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszFormat == NULL) + { + pszFormat = ""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually a non-empty format string + if (*pszFormat != '\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + int iRet; + size_t cchMax; + + // leave the last space for the null terminator + cchMax = cchDest - 1; + + iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // we have truncated pszDest + pszDestEnd = pszDest + cchMax; + cchRemaining = 1; + + // need to null terminate the string + *pszDestEnd = '\0'; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // string fit perfectly + pszDestEnd = pszDest + cchMax; + cchRemaining = 1; + + // need to null terminate the string + *pszDestEnd = '\0'; + } + else if (((size_t)iRet) < cchMax) + { + // there is extra room + pszDestEnd = pszDest + iRet; + cchRemaining = cchDest - iRet; + + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); + } + } + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || + // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + + if (pszFormat == NULL) + { + pszFormat = L""; + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest == 0) + { + pszDestEnd = pszDest; + cchRemaining = 0; + + // only fail if there was actually a non-empty format string + if (*pszFormat != L'\0') + { + if (pszDest == NULL) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + } + } + else + { + int iRet; + size_t cchMax; + + // leave the last space for the null terminator + cchMax = cchDest - 1; + + iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList); + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // we have truncated pszDest + pszDestEnd = pszDest + cchMax; + cchRemaining = 1; + + // need to null terminate the string + *pszDestEnd = L'\0'; + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // string fit perfectly + pszDestEnd = pszDest + cchMax; + cchRemaining = 1; + + // need to null terminate the string + *pszDestEnd = L'\0'; + } + else if (((size_t)iRet) < cchMax) + { + // there is extra room + pszDestEnd = pszDest + iRet; + cchRemaining = cchDest - iRet; + + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + } + } + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch) +{ + HRESULT hr = S_OK; + size_t cchMaxPrev = cchMax; + + while (cchMax && (*psz != '\0')) + { + psz++; + cchMax--; + } + + if (cchMax == 0) + { + // the string is longer than cchMax + hr = STRSAFE_E_INVALID_PARAMETER; + } + + if (SUCCEEDED(hr) && pcch) + { + *pcch = cchMaxPrev - cchMax; + } + + return hr; +} + +STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch) +{ + HRESULT hr = S_OK; + size_t cchMaxPrev = cchMax; + + while (cchMax && (*psz != L'\0')) + { + psz++; + cchMax--; + } + + if (cchMax == 0) + { + // the string is longer than cchMax + hr = STRSAFE_E_INVALID_PARAMETER; + } + + if (SUCCEEDED(hr) && pcch) + { + *pcch = cchMaxPrev - cchMax; + } + + return hr; +} +#endif // STRSAFE_INLINE + +#ifndef STRSAFE_LIB_IMPL +STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + char* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest <= 1) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + if (cchDest == 1) + { + *pszDestEnd = '\0'; + } + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else + { + char ch; + + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n') + { + if (ch == EOF) + { + if (pszDestEnd == pszDest) + { + // we failed to read anything from stdin + hr = STRSAFE_E_END_OF_FILE; + } + break; + } + + *pszDestEnd = ch; + + pszDestEnd++; + cchRemaining--; + } + + if (cchRemaining > 0) + { + // there is extra room + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); + } + } + + *pszDestEnd = '\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = '\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = '\0'; + } + } + } + } + + if (SUCCEEDED(hr) || + (hr == STRSAFE_E_INSUFFICIENT_BUFFER) || + (hr == STRSAFE_E_END_OF_FILE)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} + +STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) +{ + HRESULT hr = S_OK; + wchar_t* pszDestEnd = pszDest; + size_t cchRemaining = 0; + + // ASSERT(cbDest == (cchDest * sizeof(char)) || + // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); + + // only accept valid flags + if (dwFlags & (~STRSAFE_VALID_FLAGS)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + if (dwFlags & STRSAFE_IGNORE_NULLS) + { + if (pszDest == NULL) + { + if ((cchDest != 0) || (cbDest != 0)) + { + // NULL pszDest and non-zero cchDest/cbDest is invalid + hr = STRSAFE_E_INVALID_PARAMETER; + } + } + } + + if (SUCCEEDED(hr)) + { + if (cchDest <= 1) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + if (cchDest == 1) + { + *pszDestEnd = L'\0'; + } + + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else + { + wchar_t ch; + + pszDestEnd = pszDest; + cchRemaining = cchDest; + + while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n') + { + if (ch == EOF) + { + if (pszDestEnd == pszDest) + { + // we failed to read anything from stdin + hr = STRSAFE_E_END_OF_FILE; + } + break; + } + + *pszDestEnd = ch; + + pszDestEnd++; + cchRemaining--; + } + + if (cchRemaining > 0) + { + // there is extra room + if (dwFlags & STRSAFE_FILL_BEHIND_NULL) + { + memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); + } + } + + *pszDestEnd = L'\0'; + } + } + } + + if (FAILED(hr)) + { + if (pszDest) + { + if (dwFlags & STRSAFE_FILL_ON_FAILURE) + { + memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); + + if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + } + else if (cchDest > 0) + { + pszDestEnd = pszDest + cchDest - 1; + cchRemaining = 1; + + // null terminate the end of the string + *pszDestEnd = L'\0'; + } + } + + if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) + { + if (cchDest > 0) + { + pszDestEnd = pszDest; + cchRemaining = cchDest; + + // null terminate the beginning of the string + *pszDestEnd = L'\0'; + } + } + } + } + + if (SUCCEEDED(hr) || + (hr == STRSAFE_E_INSUFFICIENT_BUFFER) || + (hr == STRSAFE_E_END_OF_FILE)) + { + if (ppszDestEnd) + { + *ppszDestEnd = pszDestEnd; + } + + if (pcchRemaining) + { + *pcchRemaining = cchRemaining; + } + } + + return hr; +} +#endif // !STRSAFE_LIB_IMPL + + +// Do not call these functions, they are worker functions for internal use within this file +#ifdef DEPRECATE_SUPPORTED +#pragma deprecated(StringCopyWorkerA) +#pragma deprecated(StringCopyWorkerW) +#pragma deprecated(StringCopyExWorkerA) +#pragma deprecated(StringCopyExWorkerW) +#pragma deprecated(StringCatWorkerA) +#pragma deprecated(StringCatWorkerW) +#pragma deprecated(StringCatExWorkerA) +#pragma deprecated(StringCatExWorkerW) +#pragma deprecated(StringCatNWorkerA) +#pragma deprecated(StringCatNWorkerW) +#pragma deprecated(StringCatNExWorkerA) +#pragma deprecated(StringCatNExWorkerW) +#pragma deprecated(StringVPrintfWorkerA) +#pragma deprecated(StringVPrintfWorkerW) +#pragma deprecated(StringVPrintfExWorkerA) +#pragma deprecated(StringVPrintfExWorkerW) +#pragma deprecated(StringLengthWorkerA) +#pragma deprecated(StringLengthWorkerW) +#else +#define StringCopyWorkerA StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA; +#define StringCopyWorkerW StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW; +#define StringCopyExWorkerA StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA; +#define StringCopyExWorkerW StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW; +#define StringCatWorkerA StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA; +#define StringCatWorkerW StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW; +#define StringCatExWorkerA StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA; +#define StringCatExWorkerW StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW; +#define StringCatNWorkerA StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA; +#define StringCatNWorkerW StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW; +#define StringCatNExWorkerA StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA; +#define StringCatNExWorkerW StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW; +#define StringVPrintfWorkerA StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA; +#define StringVPrintfWorkerW StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW; +#define StringVPrintfExWorkerA StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA; +#define StringVPrintfExWorkerW StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW; +#define StringLengthWorkerA StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA; +#define StringLengthWorkerW StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW; +#endif // !DEPRECATE_SUPPORTED + + +#ifndef STRSAFE_NO_DEPRECATE +// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want +// this then you can #define STRSAFE_NO_DEPRECATE before including this file. +#ifdef DEPRECATE_SUPPORTED + +// First all the names that are a/w variants (or shouldn't be #defined by now anyway). +#pragma deprecated(lstrcpyA) +#pragma deprecated(lstrcpyW) +#pragma deprecated(lstrcatA) +#pragma deprecated(lstrcatW) +#pragma deprecated(wsprintfA) +#pragma deprecated(wsprintfW) + +#pragma deprecated(StrCpyW) +#pragma deprecated(StrCatW) +#pragma deprecated(StrNCatA) +#pragma deprecated(StrNCatW) +#pragma deprecated(StrCatNA) +#pragma deprecated(StrCatNW) +#pragma deprecated(wvsprintfA) +#pragma deprecated(wvsprintfW) + +#pragma deprecated(strcpy) +#pragma deprecated(wcscpy) +#pragma deprecated(strcat) +#pragma deprecated(wcscat) +#pragma deprecated(sprintf) +#pragma deprecated(swprintf) +#pragma deprecated(vsprintf) +#pragma deprecated(vswprintf) +#pragma deprecated(_snprintf) +#pragma deprecated(_snwprintf) +#pragma deprecated(_vsnprintf) +#pragma deprecated(_vsnwprintf) +#pragma deprecated(gets) +#pragma deprecated(_getws) + +// Then all the windows.h names - we need to undef and redef based on UNICODE setting +#undef lstrcpy +#undef lstrcat +#undef wsprintf +#undef wvsprintf +#pragma deprecated(lstrcpy) +#pragma deprecated(lstrcat) +#pragma deprecated(wsprintf) +#pragma deprecated(wvsprintf) +#ifdef UNICODE +#define lstrcpy lstrcpyW +#define lstrcat lstrcatW +#define wsprintf wsprintfW +#define wvsprintf wvsprintfW +#else +#define lstrcpy lstrcpyA +#define lstrcat lstrcatA +#define wsprintf wsprintfA +#define wvsprintf wvsprintfA +#endif + +// Then the shlwapi names - they key off UNICODE also. +#undef StrCpyA +#undef StrCpy +#undef StrCatA +#undef StrCat +#undef StrNCat +#undef StrCatN +#pragma deprecated(StrCpyA) +#pragma deprecated(StrCatA) +#pragma deprecated(StrCatN) +#pragma deprecated(StrCpy) +#pragma deprecated(StrCat) +#pragma deprecated(StrNCat) +#define StrCpyA lstrcpyA +#define StrCatA lstrcatA +#define StrCatN StrNCat +#ifdef UNICODE +#define StrCpy StrCpyW +#define StrCat StrCatW +#define StrNCat StrNCatW +#else +#define StrCpy lstrcpyA +#define StrCat lstrcatA +#define StrNCat StrNCatA +#endif + +// Then all the CRT names - we need to undef/redef based on _UNICODE value. +#undef _tcscpy +#undef _ftcscpy +#undef _tcscat +#undef _ftcscat +#undef _stprintf +#undef _sntprintf +#undef _vstprintf +#undef _vsntprintf +#undef _getts +#pragma deprecated(_tcscpy) +#pragma deprecated(_ftcscpy) +#pragma deprecated(_tcscat) +#pragma deprecated(_ftcscat) +#pragma deprecated(_stprintf) +#pragma deprecated(_sntprintf) +#pragma deprecated(_vstprintf) +#pragma deprecated(_vsntprintf) +#pragma deprecated(_getts) +#ifdef _UNICODE +#define _tcscpy wcscpy +#define _ftcscpy wcscpy +#define _tcscat wcscat +#define _ftcscat wcscat +#define _stprintf swprintf +#define _sntprintf _snwprintf +#define _vstprintf vswprintf +#define _vsntprintf _vsnwprintf +#define _getts _getws +#else +#define _tcscpy strcpy +#define _ftcscpy strcpy +#define _tcscat strcat +#define _ftcscat strcat +#define _stprintf sprintf +#define _sntprintf _snprintf +#define _vstprintf vsprintf +#define _vsntprintf _vsnprintf +#define _getts gets +#endif + +#else // DEPRECATE_SUPPORTED + +#undef strcpy +#define strcpy strcpy_instead_use_StringCbCopyA_or_StringCchCopyA; + +#undef wcscpy +#define wcscpy wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW; + +#undef strcat +#define strcat strcat_instead_use_StringCbCatA_or_StringCchCatA; + +#undef wcscat +#define wcscat wcscat_instead_use_StringCbCatW_or_StringCchCatW; + +//#undef sprintf +//#define sprintf sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA; + +//#undef swprintf +//#define swprintf swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW; + +#undef vsprintf +#define vsprintf vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; + +#undef vswprintf +#define vswprintf vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; + +#undef _snprintf +#define _snprintf _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA; + +#undef _snwprintf +#define _snwprintf _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW; + +#undef _vsnprintf +#define _vsnprintf _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; + +#undef _vsnwprintf +#define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; + +#undef strcpyA +#define strcpyA strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA; + +#undef strcpyW +#define strcpyW strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW; + +#undef lstrcpy +#define lstrcpy lstrcpy_instead_use_StringCbCopy_or_StringCchCopy; + +#undef lstrcpyA +#define lstrcpyA lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA; + +#undef lstrcpyW +#define lstrcpyW lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW; + +#undef StrCpy +#define StrCpy StrCpy_instead_use_StringCbCopy_or_StringCchCopy; + +#undef StrCpyA +#define StrCpyA StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA; + +#undef StrCpyW +#define StrCpyW StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW; + +#undef _tcscpy +#define _tcscpy _tcscpy_instead_use_StringCbCopy_or_StringCchCopy; + +#undef _ftcscpy +#define _ftcscpy _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy; + +#undef lstrcat +#define lstrcat lstrcat_instead_use_StringCbCat_or_StringCchCat; + +#undef lstrcatA +#define lstrcatA lstrcatA_instead_use_StringCbCatA_or_StringCchCatA; + +#undef lstrcatW +#define lstrcatW lstrcatW_instead_use_StringCbCatW_or_StringCchCatW; + +#undef StrCat +#define StrCat StrCat_instead_use_StringCbCat_or_StringCchCat; + +#undef StrCatA +#define StrCatA StrCatA_instead_use_StringCbCatA_or_StringCchCatA; + +#undef StrCatW +#define StrCatW StrCatW_instead_use_StringCbCatW_or_StringCchCatW; + +#undef StrNCat +#define StrNCat StrNCat_instead_use_StringCbCatN_or_StringCchCatN; + +#undef StrNCatA +#define StrNCatA StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA; + +#undef StrNCatW +#define StrNCatW StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW; + +#undef StrCatN +#define StrCatN StrCatN_instead_use_StringCbCatN_or_StringCchCatN; + +#undef StrCatNA +#define StrCatNA StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA; + +#undef StrCatNW +#define StrCatNW StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW; + +#undef _tcscat +#define _tcscat _tcscat_instead_use_StringCbCat_or_StringCchCat; + +#undef _ftcscat +#define _ftcscat _ftcscat_instead_use_StringCbCat_or_StringCchCat; + +#undef wsprintf +#define wsprintf wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf; + +#undef wsprintfA +#define wsprintfA wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA; + +#undef wsprintfW +#define wsprintfW wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW; + +#undef wvsprintf +#define wvsprintf wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; + +#undef wvsprintfA +#define wvsprintfA wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; + +#undef wvsprintfW +#define wvsprintfW wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; + +#undef _vstprintf +#define _vstprintf _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; + +#undef _vsntprintf +#define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; + +#undef _stprintf +#define _stprintf _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf; + +#undef _sntprintf +#define _sntprintf _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf; + +#undef _getts +#define _getts _getts_instead_use_StringCbGets_or_StringCchGets; + +#undef gets +#define gets _gets_instead_use_StringCbGetsA_or_StringCchGetsA; + +#undef _getws +#define _getws _getws_instead_use_StringCbGetsW_or_StringCchGetsW; + +#endif // !DEPRECATE_SUPPORTED +#endif // !STRSAFE_NO_DEPRECATE + +#ifdef _NTSTRSAFE_H_INCLUDED_ +#pragma warning(pop) +#endif // _NTSTRSAFE_H_INCLUDED_ + +#endif // _STRSAFE_H_INCLUDED_ diff --git a/cpp/wiipair/lib/DelcomDLL.lib b/cpp/wiipair/lib/DelcomDLL.lib new file mode 100644 index 0000000..0c540c6 Binary files /dev/null and b/cpp/wiipair/lib/DelcomDLL.lib differ diff --git a/cpp/wiipair/lib/advapi32.lib b/cpp/wiipair/lib/advapi32.lib new file mode 100644 index 0000000..2812216 Binary files /dev/null and b/cpp/wiipair/lib/advapi32.lib differ diff --git a/cpp/wiipair/lib/comdlg32.lib b/cpp/wiipair/lib/comdlg32.lib new file mode 100644 index 0000000..181fca1 Binary files /dev/null and b/cpp/wiipair/lib/comdlg32.lib differ diff --git a/cpp/wiipair/lib/gdi32.lib b/cpp/wiipair/lib/gdi32.lib new file mode 100644 index 0000000..63172a5 Binary files /dev/null and b/cpp/wiipair/lib/gdi32.lib differ diff --git a/cpp/wiipair/lib/irprops.lib b/cpp/wiipair/lib/irprops.lib new file mode 100644 index 0000000..1761118 Binary files /dev/null and b/cpp/wiipair/lib/irprops.lib differ diff --git a/cpp/wiipair/lib/kernel32.lib b/cpp/wiipair/lib/kernel32.lib new file mode 100644 index 0000000..77b0e53 Binary files /dev/null and b/cpp/wiipair/lib/kernel32.lib differ diff --git a/cpp/wiipair/lib/libcpmt.lib b/cpp/wiipair/lib/libcpmt.lib new file mode 100644 index 0000000..85e91bb Binary files /dev/null and b/cpp/wiipair/lib/libcpmt.lib differ diff --git a/cpp/wiipair/lib/odbc32.lib b/cpp/wiipair/lib/odbc32.lib new file mode 100644 index 0000000..1add151 Binary files /dev/null and b/cpp/wiipair/lib/odbc32.lib differ diff --git a/cpp/wiipair/lib/odbccp32.lib b/cpp/wiipair/lib/odbccp32.lib new file mode 100644 index 0000000..0f2ef09 Binary files /dev/null and b/cpp/wiipair/lib/odbccp32.lib differ diff --git a/cpp/wiipair/lib/ole32.lib b/cpp/wiipair/lib/ole32.lib new file mode 100644 index 0000000..17d6af8 Binary files /dev/null and b/cpp/wiipair/lib/ole32.lib differ diff --git a/cpp/wiipair/lib/oleaut32.lib b/cpp/wiipair/lib/oleaut32.lib new file mode 100644 index 0000000..1955d00 Binary files /dev/null and b/cpp/wiipair/lib/oleaut32.lib differ diff --git a/cpp/wiipair/lib/shell32.lib b/cpp/wiipair/lib/shell32.lib new file mode 100644 index 0000000..b723320 Binary files /dev/null and b/cpp/wiipair/lib/shell32.lib differ diff --git a/cpp/wiipair/lib/user32.lib b/cpp/wiipair/lib/user32.lib new file mode 100644 index 0000000..eda26c0 Binary files /dev/null and b/cpp/wiipair/lib/user32.lib differ diff --git a/cpp/wiipair/lib/uuid.lib b/cpp/wiipair/lib/uuid.lib new file mode 100644 index 0000000..f6e4ae2 Binary files /dev/null and b/cpp/wiipair/lib/uuid.lib differ diff --git a/cpp/wiipair/lib/wiiuse.lib b/cpp/wiipair/lib/wiiuse.lib new file mode 100644 index 0000000..6425e72 Binary files /dev/null and b/cpp/wiipair/lib/wiiuse.lib differ diff --git a/cpp/wiipair/lib/winspool.lib b/cpp/wiipair/lib/winspool.lib new file mode 100644 index 0000000..61cb936 Binary files /dev/null and b/cpp/wiipair/lib/winspool.lib differ diff --git a/cpp/wiipair/src/wiipair.cpp b/cpp/wiipair/src/wiipair.cpp new file mode 100644 index 0000000..764bbe2 --- /dev/null +++ b/cpp/wiipair/src/wiipair.cpp @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include +#include + +DWORD ShowErrorCode(LPTSTR msg, DWORD dw) +{ + // Retrieve the system error message for the last-error code + + LPVOID lpMsgBuf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + + _tprintf(_T("%s: %s"), msg, lpMsgBuf); + + LocalFree(lpMsgBuf); + + return dw; +} + + +_TCHAR * FormatBTAddress(BLUETOOTH_ADDRESS address) +{ + static _TCHAR ret[20]; + _stprintf(ret, _T("%02x:%02x:%02x:%02x:%02x:%02x"), + address.rgBytes[5], + address.rgBytes[4], + address.rgBytes[3], + address.rgBytes[2], + address.rgBytes[1], + address.rgBytes[0] + ); + return ret; +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + HANDLE hRadios[256]; + int nRadios; + int nPaired = 0; + + /////////////////////////////////////////////////////////////////////// + // Enumerate BT radios + /////////////////////////////////////////////////////////////////////// + { + HBLUETOOTH_RADIO_FIND hFindRadio; + BLUETOOTH_FIND_RADIO_PARAMS radioParam; + + _tprintf(_T("Enumerating radios...\n")); + + radioParam.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS); + + nRadios = 0; + hFindRadio = BluetoothFindFirstRadio(&radioParam, &hRadios[nRadios++]); + if (hFindRadio) + { + while (BluetoothFindNextRadio(&radioParam, &hRadios[nRadios++])); + BluetoothFindRadioClose(hFindRadio); + } + else + { + ShowErrorCode(_T("Error enumerating radios"), GetLastError()); + return (1); + } + nRadios--; + _tprintf(_T("Found %d radios\n"), nRadios); + } + + /////////////////////////////////////////////////////////////////////// + // Keep looping until we pair with a Wii device + /////////////////////////////////////////////////////////////////////// + + while (nPaired == 0) + { + int radio; + + for (radio = 0; radio < nRadios; radio++) + { + BLUETOOTH_RADIO_INFO radioInfo; + HBLUETOOTH_DEVICE_FIND hFind; + BLUETOOTH_DEVICE_INFO btdi; + BLUETOOTH_DEVICE_SEARCH_PARAMS srch; + + radioInfo.dwSize = sizeof(radioInfo); + btdi.dwSize = sizeof(btdi); + srch.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS); + + ShowErrorCode(_T("BluetoothGetRadioInfo"), BluetoothGetRadioInfo(hRadios[radio], &radioInfo)); + + _tprintf(_T("Radio %d: %ls %s\n"), + radio, + radioInfo.szName, + FormatBTAddress(radioInfo.address) + ); + + srch.fReturnAuthenticated = TRUE; + srch.fReturnRemembered = TRUE; + srch.fReturnConnected = TRUE; + srch.fReturnUnknown = TRUE; + srch.fIssueInquiry = TRUE; + srch.cTimeoutMultiplier = 2; + srch.hRadio = hRadios[radio]; + + _tprintf(_T("Scanning...\n")); + + hFind = BluetoothFindFirstDevice(&srch, &btdi); + + if (hFind == NULL) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + { + _tprintf(_T("No bluetooth devices found.\n")); + } + else + { + ShowErrorCode(_T("Error enumerating devices"), GetLastError()); + return (1); + } + } + else + { + do + { + _tprintf(_T("Found: %s\n"), btdi.szName); + + if (!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01")) + { + WCHAR pass[6]; + DWORD pcServices = 16; + GUID guids[16]; + BOOL error = FALSE; + + if (!error) + { + if (btdi.fRemembered) + { + // Make Windows forget pairing + if (ShowErrorCode(_T("BluetoothRemoveDevice"), BluetoothRemoveDevice(&btdi.Address)) != ERROR_SUCCESS) + error = TRUE; + } + } + + // MAC address is passphrase + pass[0] = radioInfo.address.rgBytes[0]; + pass[1] = radioInfo.address.rgBytes[1]; + pass[2] = radioInfo.address.rgBytes[2]; + pass[3] = radioInfo.address.rgBytes[3]; + pass[4] = radioInfo.address.rgBytes[4]; + pass[5] = radioInfo.address.rgBytes[5]; + + if (!error) + { + // Pair with Wii device + if (ShowErrorCode(_T("BluetoothAuthenticateDevice"), BluetoothAuthenticateDevice(NULL, hRadios[radio], &btdi, pass, 6)) != ERROR_SUCCESS) + error = TRUE; + } + + if (!error) + { + // If this is not done, the Wii device will not remember the pairing + if (ShowErrorCode(_T("BluetoothEnumerateInstalledServices"), BluetoothEnumerateInstalledServices(hRadios[radio], &btdi, &pcServices, guids)) != ERROR_SUCCESS) + error = TRUE; + } + + /*if (!error) + { + // Activate service + if (ShowErrorCode(_T("BluetoothSetServiceState"), BluetoothSetServiceState(hRadios[radio], &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE)) != ERROR_SUCCESS) + error = TRUE; + }*/ + + if (!error) + { + nPaired++; + } + } // if (!wcscmp(btdi.szName, L"Nintendo RVL-WBC-01") || !wcscmp(btdi.szName, L"Nintendo RVL-CNT-01")) + } + while (BluetoothFindNextDevice(hFind, &btdi)); + } // if (hFind == NULL) + } // for (radio = 0; radio < nRadios; radio++) + + Sleep(1000); + } + + /////////////////////////////////////////////////////////////////////// + // Clean up + /////////////////////////////////////////////////////////////////////// + + { + int radio; + + for (radio = 0; radio < nRadios; radio++) + { + CloseHandle(hRadios[radio]); + } + } + + _tprintf(_T("=============================================\n"), nPaired); + _tprintf(_T("%d Wii devices paired\n"), nPaired); + + return 0; +}