diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5042a9c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/java/bin
diff --git a/cpp/mimis/.settings/org.eclipse.cdt.codan.core.prefs b/cpp/mimis/.settings/org.eclipse.cdt.codan.core.prefs
deleted file mode 100644
index 5d18018..0000000
--- a/cpp/mimis/.settings/org.eclipse.cdt.codan.core.prefs
+++ /dev/null
@@ -1,66 +0,0 @@
-#Wed Sep 28 10:46:29 CEST 2011
-eclipse.preferences.version=1
-org.eclipse.cdt.codan.checkers.errnoreturn=Warning
-org.eclipse.cdt.codan.checkers.errnoreturn.params={implicit\=>false}
-org.eclipse.cdt.codan.checkers.errreturnvalue=Error
-org.eclipse.cdt.codan.checkers.errreturnvalue.params={}
-org.eclipse.cdt.codan.checkers.noreturn=Error
-org.eclipse.cdt.codan.checkers.noreturn.params={implicit\=>false}
-org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
-org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
-org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
-org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false}
-org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
-org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={unknown\=>false,exceptions\=>()}
-org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
-org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
-org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
-org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
-org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
-org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
-org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
-org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
-org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
-org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
-org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
-org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={macro\=>true,exceptions\=>()}
-org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={paramNot\=>false}
-org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={else\=>false,afterelse\=>false}
-org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
-org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={}
-org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
-org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={exceptions\=>("@(\#)","$Id")}
-org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
-org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
diff --git a/cpp/mimis/Debug/copy.bat b/cpp/mimis/Debug/copy.bat
index 6a2bf07..1a0d3a1 100644
--- a/cpp/mimis/Debug/copy.bat
+++ b/cpp/mimis/Debug/copy.bat
@@ -1 +1 @@
-copy mimis.dll ..\..\Mimis\mimis.dll
\ No newline at end of file
+copy mimis.dll ..\..\..\java\mimis.dll
\ No newline at end of file
diff --git a/cpp/mimis/Release/copy.bat b/cpp/mimis/Release/copy.bat
index 6a2bf07..1a0d3a1 100644
--- a/cpp/mimis/Release/copy.bat
+++ b/cpp/mimis/Release/copy.bat
@@ -1 +1 @@
-copy mimis.dll ..\..\Mimis\mimis.dll
\ No newline at end of file
+copy mimis.dll ..\..\..\java\mimis.dll
\ No newline at end of file
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/mimis/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs
similarity index 54%
rename from cpp/mimis/.settings/org.eclipse.cdt.managedbuilder.core.prefs
rename to cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs
index e5d73c0..31dfb57 100644
--- a/cpp/mimis/.settings/org.eclipse.cdt.managedbuilder.core.prefs
+++ b/cpp/wiipair/.settings/org.eclipse.cdt.managedbuilder.core.prefs
@@ -1,26 +1,25 @@
-#Sun Jul 17 20:05:29 CEST 2011
-eclipse.preferences.version=1
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/CPATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/CPATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/CPLUS_INCLUDE_PATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/CPLUS_INCLUDE_PATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/C_INCLUDE_PATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/C_INCLUDE_PATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/append=true
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/appendContributed=true
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/CPATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/CPATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/CPLUS_INCLUDE_PATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/CPLUS_INCLUDE_PATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/C_INCLUDE_PATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/C_INCLUDE_PATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/append=true
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/appendContributed=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/LIBRARY_PATH/delimiter=;
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/LIBRARY_PATH/operation=remove
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/append=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.debug.36925639/appendContributed=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/LIBRARY_PATH/delimiter=;
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/LIBRARY_PATH/operation=remove
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/append=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.cygwin.so.release.2109617530/appendContributed=true
+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/wiiscan/lib/wiiuse.lib b/cpp/wiipair/lib/wiiuse.lib
similarity index 89%
rename from cpp/wiiscan/lib/wiiuse.lib
rename to cpp/wiipair/lib/wiiuse.lib
index 906e164..6425e72 100644
Binary files a/cpp/wiiscan/lib/wiiuse.lib 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;
+}
diff --git a/cpp/wiiscan/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/cpp/wiiscan/.settings/org.eclipse.cdt.managedbuilder.core.prefs
deleted file mode 100644
index 14ad3ce..0000000
--- a/cpp/wiiscan/.settings/org.eclipse.cdt.managedbuilder.core.prefs
+++ /dev/null
@@ -1,14 +0,0 @@
-#Sat Oct 15 11:50:13 CEST 2011
-eclipse.preferences.version=1
-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.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/wiiusej/Debug/wiiusej.dll b/cpp/wiiusej/Debug/wiiusej.dll
new file mode 100644
index 0000000..c432d21
Binary files /dev/null and b/cpp/wiiusej/Debug/wiiusej.dll differ
diff --git a/cpp/wiiusej/lib/wiiuse.lib b/cpp/wiiusej/lib/wiiuse.lib
index 0c6fe6e..6425e72 100644
Binary files a/cpp/wiiusej/lib/wiiuse.lib and b/cpp/wiiusej/lib/wiiuse.lib differ
diff --git a/java/.classpath b/java/.classpath
new file mode 100644
index 0000000..2e201e9
--- /dev/null
+++ b/java/.classpath
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/.project b/java/.project
new file mode 100644
index 0000000..5605d1a
--- /dev/null
+++ b/java/.project
@@ -0,0 +1,17 @@
+
+
+ Mimis
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/WiiPair.exe b/java/WiiPair.exe
new file mode 100644
index 0000000..f16c97d
Binary files /dev/null and b/java/WiiPair.exe differ
diff --git a/java/client.jar b/java/client.jar
new file mode 100644
index 0000000..15b5e21
Binary files /dev/null and b/java/client.jar differ
diff --git a/java/main.jar b/java/main.jar
new file mode 100644
index 0000000..d6166a0
Binary files /dev/null and b/java/main.jar differ
diff --git a/java/mimis.dll b/java/mimis.dll
index 1bfdfea..259eb99 100644
Binary files a/java/mimis.dll and b/java/mimis.dll differ
diff --git a/java/src/mimis/device/wiimote/WiimoteDevice.java b/java/src/mimis/device/wiimote/WiimoteDevice.java
index 77259bf..1d4b04e 100644
--- a/java/src/mimis/device/wiimote/WiimoteDevice.java
+++ b/java/src/mimis/device/wiimote/WiimoteDevice.java
@@ -35,7 +35,6 @@ public class WiimoteDevice extends Component implements Device, GestureListener
protected static WiimoteService wiimoteService;
protected WiimoteTaskMapCycle taskMapCycle;
- protected WiimoteDiscovery wiimoteDiscovery;
protected Wiimote wiimote;
protected boolean connected;
protected GestureDevice gestureDevice;
@@ -52,7 +51,6 @@ public class WiimoteDevice extends Component implements Device, GestureListener
public WiimoteDevice() {
super(TITLE);
taskMapCycle = new WiimoteTaskMapCycle();
- wiimoteDiscovery = new WiimoteDiscovery(this);
gestureDevice = new GestureDevice();
gestureDevice.add(this);
motionDevice = new MotionDevice(this);
@@ -62,14 +60,15 @@ public class WiimoteDevice extends Component implements Device, GestureListener
/* Worker */
protected void activate() throws ActivateException {
- motionDevice.setRouter(router);
- motionDevice.start();
- parser(Action.ADD, taskMapCycle.player);
- wiimote = null;
+ if (wiimote == null) {
+ motionDevice.setRouter(router);
+ motionDevice.start();
+ parser(Action.ADD, taskMapCycle.player);
+ }
try {
connect();
} catch (DeviceNotFoundException e) {
- wiimoteDiscovery.start();
+ log.warn(e);
}
super.activate();
}
@@ -98,13 +97,9 @@ public class WiimoteDevice extends Component implements Device, GestureListener
protected void deactivate() throws DeactivateException {
super.deactivate();
ledWorker.stop();
- wiimoteDiscovery.stop();
motionDevice.stop();
- if (disconnect) {
- if (wiimote != null) {
- wiimote.disconnect();
- }
- wiimoteDiscovery.disconnect();
+ if (disconnect && wiimote != null) {
+ wiimote.disconnect();
disconnect = false;
}
}
@@ -117,7 +112,6 @@ public class WiimoteDevice extends Component implements Device, GestureListener
wiimote = null;
}
wiimoteService.exit();
- wiimoteDiscovery.exit();
motionDevice.exit();
}
@@ -182,22 +176,24 @@ public class WiimoteDevice extends Component implements Device, GestureListener
public void feedback(Feedback feedback) {
if (wiimote != null && active()) {
- //log.debug("Wiimote rumble feedback");
- //wiimote.rumble(RUMBLE);
+ log.debug("Wiimote rumble feedback");
+ wiimote.rumble(RUMBLE);
}
}
/* Connectivity */
public synchronized void connect() throws DeviceNotFoundException {
wiimote = wiimoteService.getDevice(this);
- //wiimote.activateContinuous();
+ wiimote.activateContinuous();
wiimote.activateMotionSensing();
- wiimoteDiscovery.stop();
ledWorker.start();
}
/* Listeners */
public void onButtonsEvent(WiimoteButtonsEvent event) {
+ if (!active) {
+ return;
+ }
int pressed = event.getButtonsJustPressed() - event.getButtonsHeld();
int released = event.getButtonsJustReleased();
try {
@@ -214,6 +210,9 @@ public class WiimoteDevice extends Component implements Device, GestureListener
}
public void onMotionSensingEvent(MotionSensingEvent event) {
+ if (!active) {
+ return;
+ }
gestureDevice.add(event.getGforce());
motionDevice.add(event);
}
diff --git a/java/src/mimis/device/wiimote/WiimoteService.java b/java/src/mimis/device/wiimote/WiimoteService.java
index 6ff2480..2d905be 100644
--- a/java/src/mimis/device/wiimote/WiimoteService.java
+++ b/java/src/mimis/device/wiimote/WiimoteService.java
@@ -30,12 +30,12 @@ import wiiusej.wiiusejevents.wiiuseapievents.StatusEvent;
public class WiimoteService extends WiiUseApiManager implements WiimoteListener {
protected Log log = LogFactory.getLog(getClass());
- public static void main(String[] args) {
+ /*public static void main(String[] args) {
Log log = LogFactory.getLog(WiimoteService.class);
for (Wiimote wm : WiiUseApiManager.getWiimotes(1, false)) {
log.debug(wm);
}
- }
+ }*/
protected final boolean RUMBLE = false;
@@ -81,10 +81,11 @@ public class WiimoteService extends WiiUseApiManager implements WiimoteListener
}
public void onButtonsEvent(WiimoteButtonsEvent event) {
- getWiimoteDevice(event).onButtonsEvent(event);
+ getWiimoteDevice(event).onButtonsEvent(event);
}
public void onMotionSensingEvent(MotionSensingEvent event) {
+
getWiimoteDevice(event).onMotionSensingEvent(event);
}
diff --git a/java/src/mimis/worker/Worker.java b/java/src/mimis/worker/Worker.java
index 2371cb9..7c41120 100644
--- a/java/src/mimis/worker/Worker.java
+++ b/java/src/mimis/worker/Worker.java
@@ -12,24 +12,31 @@ public abstract class Worker implements Runnable {
protected static final boolean THREAD = false;
protected static final int SLEEP = 100;
+ protected boolean thread = true;
protected boolean interrupt;
protected boolean run = false;
protected boolean active = false;
protected boolean activate = false;
protected boolean deactivate = false;
- public final void start(boolean thread) {
+ public Worker() {}
+
+ public Worker(boolean thread) {
+ this.thread = thread;
+ }
+
+ public synchronized final void start(boolean thread) {
if (!active) {
activate = true;
}
if (!run) {
run = true;
if (thread) {
- log.debug("Run directly");
- run();
- } else {
log.debug("Start thread");
new Thread(this, getClass().getName()).start();
+ } else {
+ log.debug("Run directly");
+ run();
}
} else {
notifyAll();
@@ -37,7 +44,7 @@ public abstract class Worker implements Runnable {
}
public synchronized final void start() {
- start(THREAD);
+ start(thread);
}
public synchronized final void stop() {