Move ANCM installers to Universe (#1456)
This commit is contained in:
parent
949c29c59f
commit
dbc1d38a58
|
|
@ -35,3 +35,52 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
License notice for IIS-Common
|
||||
------------------------------------
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
License notice for IIS-Setup
|
||||
------------------------------------
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.0</TargetFramework>
|
||||
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<RestorePackagesPath>$(RepositoryRoot).deps\ANCM</RestorePackagesPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModule" Version="$(MicrosoftAspNetCoreAspNetCoreModulePackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="$(MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<RestoreSources Condition="Exists('$(RepositoryRoot).deps\ANCM')">
|
||||
$(RepositoryRoot).deps\ANCM;
|
||||
</RestoreSources>
|
||||
<RestoreSources>
|
||||
$(RestoreSources);
|
||||
https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;
|
||||
https://api.nuget.org/v3/index.json;
|
||||
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
|
||||
</RestoreSources>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
<Project>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<BUILD_MAJOR>$(_TwoDigitYear)$(_ThreeDigitDayOfYear)</BUILD_MAJOR>
|
||||
<BLDVERMAJOR>$(PRODUCT_MAJOR)</BLDVERMAJOR>
|
||||
<BLDVERMINOR>$(PRODUCT_MINOR)</BLDVERMINOR>
|
||||
<BLDNUMMAJOR>$(BUILD_MAJOR)</BLDNUMMAJOR>
|
||||
<BLDNUMMINOR>$(BUILD_MINOR)</BLDNUMMINOR>
|
||||
<DefineConstants>BLDVERMAJOR=$(BLDVERMAJOR);BLDVERMINOR=$(BLDVERMINOR);BLDNUMMAJOR=$(BLDNUMMAJOR);BLDNUMMINOR=$(BLDNUMMINOR);$(DefineConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include <precomp.h>
|
||||
|
||||
DECLARE_DEBUG_PRINT_OBJECT( "proxyCA.dll" );
|
||||
|
||||
HINSTANCE g_hinst;
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain(
|
||||
HINSTANCE hModule,
|
||||
DWORD dwReason,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER( lpReserved );
|
||||
switch( dwReason )
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
CREATE_DEBUG_PRINT_OBJECT;
|
||||
DisableThreadLibraryCalls( hModule );
|
||||
g_hinst = hModule;
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
struct COMPRESSION_MIME_TYPE
|
||||
{
|
||||
PCWSTR pszMimeType;
|
||||
BOOL fEnabled;
|
||||
};
|
||||
|
||||
COMPRESSION_MIME_TYPE gMimeTypes[] =
|
||||
{ { L"text/event-stream", FALSE} };
|
||||
|
||||
UINT
|
||||
WINAPI
|
||||
RegisterANCMCompressionCA(
|
||||
IN MSIHANDLE
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD i;
|
||||
VARIANT varName;
|
||||
IAppHostWritableAdminManager * pAdminMgr = NULL;
|
||||
IAppHostElement * pHttpCompressionSection = NULL;
|
||||
IAppHostElement * pDynamicCompressionElement = NULL;
|
||||
IAppHostElementCollection * pMimeTypeCollection = NULL;
|
||||
IAppHostElement * pMimeTypeElement = NULL;
|
||||
|
||||
VariantInit(&varName);
|
||||
|
||||
hr = CoCreateInstance(__uuidof(AppHostWritableAdminManager),
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IAppHostWritableAdminManager),
|
||||
(VOID **)&pAdminMgr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = pAdminMgr->GetAdminSection(L"system.webServer/httpCompression",
|
||||
L"MACHINE/WEBROOT/APPHOST",
|
||||
&pHttpCompressionSection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = pHttpCompressionSection->GetElementByName(L"dynamicTypes",
|
||||
&pDynamicCompressionElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = pDynamicCompressionElement->get_Collection(&pMimeTypeCollection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = pMimeTypeCollection->get_Count(&i);
|
||||
if (FAILED(hr) || i == 0)
|
||||
{
|
||||
// failure or DynamicCmpression is not enabled
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i=0; i<_countof(gMimeTypes); i++)
|
||||
{
|
||||
hr = pMimeTypeCollection->CreateNewElement(L"add",
|
||||
&pMimeTypeElement);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = VariantAssign(&varName,
|
||||
gMimeTypes[i].pszMimeType);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = SetElementProperty(pMimeTypeElement,
|
||||
L"mimeType",
|
||||
&varName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
VariantClear(&varName);
|
||||
|
||||
varName.vt = VT_BOOL;
|
||||
varName.boolVal = gMimeTypes[i].fEnabled ? VARIANT_TRUE : VARIANT_FALSE;
|
||||
|
||||
hr = SetElementProperty(pMimeTypeElement,
|
||||
L"enabled",
|
||||
&varName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
VariantClear(&varName);
|
||||
|
||||
hr = pMimeTypeCollection->AddElement(pMimeTypeElement);
|
||||
if (FAILED(hr) &&
|
||||
hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pMimeTypeElement->Release();
|
||||
pMimeTypeElement = NULL;
|
||||
}
|
||||
|
||||
hr = pAdminMgr->CommitChanges();
|
||||
|
||||
exit:
|
||||
|
||||
VariantClear(&varName);
|
||||
|
||||
if (pMimeTypeElement != NULL)
|
||||
{
|
||||
pMimeTypeElement->Release();
|
||||
pMimeTypeElement = NULL;
|
||||
}
|
||||
|
||||
if (pMimeTypeCollection != NULL)
|
||||
{
|
||||
pMimeTypeCollection->Release();
|
||||
pMimeTypeCollection = NULL;
|
||||
}
|
||||
|
||||
if (pDynamicCompressionElement != NULL)
|
||||
{
|
||||
pDynamicCompressionElement->Release();
|
||||
pDynamicCompressionElement = NULL;
|
||||
}
|
||||
|
||||
if (pHttpCompressionSection != NULL)
|
||||
{
|
||||
pHttpCompressionSection->Release();
|
||||
pHttpCompressionSection = NULL;
|
||||
}
|
||||
|
||||
if (pAdminMgr != NULL)
|
||||
{
|
||||
pAdminMgr->Release();
|
||||
pAdminMgr = NULL;
|
||||
}
|
||||
|
||||
return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
LIBRARY aspnetcoreCA
|
||||
|
||||
EXPORTS
|
||||
|
||||
; IIS Common Config custom actions
|
||||
|
||||
IISScheduleInstallCA
|
||||
IISScheduleUninstallCA
|
||||
IISExecuteCA
|
||||
IISBeginTransactionCA
|
||||
IISRollbackTransactionCA
|
||||
IISCommitTransactionCA
|
||||
|
||||
CheckForSharedConfigurationCA
|
||||
|
||||
ScheduleInstallWindowsHotfixCA
|
||||
ExecuteInstallWindowsHotfixCA
|
||||
ExecuteCleanUpWindowsHotfixCA
|
||||
ScheduleRebootIfRequiredCA
|
||||
|
||||
RegisterANCMCompressionCA
|
||||
|
||||
CheckForServicesRunningCA
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#define VER_FILETYPE VFT_DLL
|
||||
#define RC_VERSION_INTERNAL_NAME "aspnetcoreCA\0"
|
||||
#define RC_VERSION_ORIGINAL_FILE_NAME "aspnetcoreCA.dll\0"
|
||||
#define RC_VERSION_FILE_DESCRIPTION "IIS AspNet Core Support Module Custom Action DLL\0"
|
||||
#define PRODUCT_MAJOR 7
|
||||
#define PRODUCT_MINOR 1
|
||||
#define BUILD_MAJOR 1972
|
||||
#define BUILD_MINOR 0
|
||||
|
||||
#include <bldver.rc>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<ANCM-Setup Condition="$(ANCM-Setup) == ''">$(MSBuildThisFileDirectory)..\</ANCM-Setup>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_IIS-SetupExportsPath>$(ANCM-Setup)IIS-Setup\build\exports.props</_IIS-SetupExportsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Condition="$(IIS-Setup) == '' AND Exists('$(_IIS-SetupExportsPath)')" Project="$(_IIS-SetupExportsPath)" />
|
||||
|
||||
<!-- Build error if submodule dependencies could not be found. -->
|
||||
<Import Project="$(IIS-Common)build\versions.props" Condition="Exists('$(IIS-Common)build\versions.props')" />
|
||||
<Import Project="$(IIS-Common)build\settings.props" Condition="Exists('$(IIS-Common)build\settings.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{7C27E72F-54D0-4820-8CFA-5E4BE640974B}</ProjectGuid>
|
||||
<RootNamespace>aspnetcoreca</RootNamespace>
|
||||
<ProjectName>aspnetcoreCA</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<AdditionalIncludeDirectories>$(IIS-Common)version;$(IIS-Common)Include;$(IIS-Setup)iisca\lib;$(WIX)sdk\$(WixPlatformToolset)\inc;$(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>httpapi.lib;shlwapi.lib;ahadmin.lib;xmllite.lib;msi.lib;Version.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>aspnetcoreCA.def</ModuleDefinitionFile>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>
|
||||
<AdditionalOptions>/NODEFAULTLIB:MSVCRT %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="aspnetcoreCA.cpp" />
|
||||
<ClCompile Include="avoid_restart.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="aspnetcoreCA.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="aspnetcoreCA.rc">
|
||||
<AdditionalIncludeDirectories>$(IIS-Common)version</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(IIS-Setup)iisca\lib\iisca.vcxproj">
|
||||
<Project>{7324770c-0871-4d73-be3d-5e2f3e9e1b1e}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(IIS-Common)lib\CommonLib.vcxproj">
|
||||
<Project>{b54a8f61-60de-4ad9-87ca-d102f230678e}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
<Target Name="EnsureImportsExist" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project is trying to import a missing file: {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(IIS-Common)build\versions.props')" Text="$([System.String]::Format('$(ErrorText)', '$(IIS-Common)build\versions.props'))" />
|
||||
<Error Condition="!Exists('$(IIS-Common)build\settings.props')" Text="$([System.String]::Format('$(ErrorText)', '$(IIS-Common)build\settings.props'))" />
|
||||
<Error Condition="!Exists('$(IIS-Common)build\copy-outputs.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(IIS-Common)build\copy-outputs.targets'))" />
|
||||
</Target>
|
||||
<Import Project="$(IIS-Common)build\copy-outputs.targets" Condition="Exists('$(IIS-Common)build\copy-outputs.targets')" />
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#include <precomp.h>
|
||||
#include <Wbemidl.h>
|
||||
|
||||
HRESULT
|
||||
GetServiceCurrentState(
|
||||
__in LPCWSTR pszServiceName,
|
||||
__out SERVICE_STATUS * pServiceStatus
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
SC_HANDLE hServiceControlManager = NULL;
|
||||
SC_HANDLE hService = NULL;
|
||||
|
||||
hServiceControlManager = OpenSCManager( NULL, // Local machine
|
||||
NULL,
|
||||
STANDARD_RIGHTS_READ );
|
||||
if ( hServiceControlManager == NULL )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
DBGERROR_HR(hr);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hService = OpenService( hServiceControlManager,
|
||||
pszServiceName,
|
||||
SERVICE_QUERY_STATUS );
|
||||
if ( hService == NULL )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
DBGERROR_HR(hr);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if ( !QueryServiceStatus( hService,
|
||||
pServiceStatus ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
DBGERROR_HR(hr);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
if ( hService != NULL )
|
||||
{
|
||||
CloseServiceHandle( hService );
|
||||
hService = NULL;
|
||||
}
|
||||
|
||||
if ( hServiceControlManager != NULL )
|
||||
{
|
||||
CloseServiceHandle( hService );
|
||||
hService = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IsServiceRunning(
|
||||
const SERVICE_STATUS & ServiceStatus
|
||||
)
|
||||
{
|
||||
switch( ServiceStatus.dwCurrentState )
|
||||
{
|
||||
case SERVICE_RUNNING:
|
||||
case SERVICE_START_PENDING:
|
||||
case SERVICE_CONTINUE_PENDING:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
IsQfeInstalled(
|
||||
__in LPCWSTR pszQfeName,
|
||||
__out BOOL * pfIsInstalled
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr< IWbemLocator > pLocator;
|
||||
CComPtr< IWbemServices > pService;
|
||||
CComPtr< IEnumWbemClassObject > pEnumerator;
|
||||
ULONG Count = 0;
|
||||
CComPtr< IWbemClassObject > pProcessor;
|
||||
CComBSTR bstrNamespace;
|
||||
CComBSTR bstrQueryLanguage;
|
||||
CComBSTR bstrQuery;
|
||||
|
||||
if ( FAILED( hr = bstrNamespace.Append( L"root\\CIMV2", 10 ) ) ||
|
||||
FAILED( hr = bstrQueryLanguage.Append( L"WQL", 3 ) ) ||
|
||||
FAILED( hr = bstrQuery.Append( L"SELECT HotFixID FROM Win32_QuickFixEngineering WHERE HotFixID='" ) ) ||
|
||||
FAILED( hr = bstrQuery.Append( pszQfeName ) ) ||
|
||||
FAILED( hr = bstrQuery.Append( L"'", 1 ) ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = CoCreateInstance( __uuidof(WbemAdministrativeLocator),
|
||||
NULL, // pUnkOuter
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IWbemLocator),
|
||||
reinterpret_cast< void** >( &pLocator ) );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pLocator->ConnectServer( bstrNamespace,
|
||||
NULL, // strUser
|
||||
NULL, // strPassword
|
||||
NULL, // strLocale
|
||||
WBEM_FLAG_CONNECT_USE_MAX_WAIT,
|
||||
NULL, // strAuthority
|
||||
NULL, // pCtx
|
||||
&pService );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the proxy so that impersonation of the client occurs.
|
||||
//
|
||||
hr = CoSetProxyBlanket( pService,
|
||||
RPC_C_AUTHN_DEFAULT,
|
||||
RPC_C_AUTHZ_NONE,
|
||||
NULL,
|
||||
RPC_C_AUTHN_LEVEL_CONNECT,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
NULL,
|
||||
EOAC_NONE);
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pService->ExecQuery( bstrQueryLanguage,
|
||||
bstrQuery,
|
||||
WBEM_FLAG_FORWARD_ONLY,
|
||||
NULL,
|
||||
&pEnumerator );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pEnumerator->Next( WBEM_INFINITE,
|
||||
1L,
|
||||
&pProcessor,
|
||||
&Count );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*pfIsInstalled = Count > 0;
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
UINT
|
||||
WINAPI
|
||||
CheckForServicesRunningCA(
|
||||
MSIHANDLE hInstall
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fIsServiceRunning = FALSE;
|
||||
SERVICE_STATUS ServiceStatus;
|
||||
LPCWSTR rgServiceNames[] = { L"WAS", L"WMSVC" };
|
||||
|
||||
IISLogInitialize(hInstall, UNITEXT(__FUNCTION__));
|
||||
|
||||
//
|
||||
// Check if any pService is running.
|
||||
//
|
||||
for( DWORD Index = 0; Index < _countof( rgServiceNames ); Index ++ )
|
||||
{
|
||||
hr = GetServiceCurrentState( rgServiceNames[Index],
|
||||
&ServiceStatus );
|
||||
if ( hr == HRESULT_FROM_WIN32( ERROR_SERVICE_DOES_NOT_EXIST ) )
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
else if ( FAILED( hr ) )
|
||||
{
|
||||
IISLogWrite(SETUP_LOG_SEVERITY_ERROR,
|
||||
L"Failed to query the state of the service '%s' hr=0x%x",
|
||||
rgServiceNames[Index],
|
||||
hr );
|
||||
DBGERROR_HR(hr);
|
||||
goto Finished;
|
||||
}
|
||||
else
|
||||
{
|
||||
fIsServiceRunning = IsServiceRunning( ServiceStatus );
|
||||
if ( fIsServiceRunning )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( fIsServiceRunning )
|
||||
{
|
||||
BOOL fQfeInstalled = FALSE;
|
||||
|
||||
hr = IsQfeInstalled( L"KB954438",
|
||||
&fQfeInstalled );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
IISLogWrite(SETUP_LOG_SEVERITY_ERROR,
|
||||
L"Failed to query the hotfix 'KB949172' information hr=0x%x",
|
||||
hr );
|
||||
DBGERROR_HR(hr);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if ( fQfeInstalled )
|
||||
{
|
||||
//
|
||||
// hotfix is already installed.
|
||||
//
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
IISLogClose();
|
||||
return LogMsiCustomActionError( hInstall, 30003 );
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
IISLogClose();
|
||||
|
||||
// TODO Wire up when Rollback CA's are wired up
|
||||
return (SUCCEEDED(hr)) ? ERROR_SUCCESS : ERROR_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<Project>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
|
||||
<Import Project="$(RepositoryRoot)\.deps\dependencies.g.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<AspNetCoreSetupRoot>$(RepositoryRoot)src\Installers\Windows\AspNetCoreModule-Setup\</AspNetCoreSetupRoot>
|
||||
<IIS-Setup>$(AspNetCoreSetupRoot)IIS-Setup\</IIS-Setup>
|
||||
<IIS-Common>$(IIS-Setup)IIS-Common\</IIS-Common>
|
||||
|
||||
<CustomActionVariable>CustomAction=$(AspNetCoreSetupRoot)CustomAction\bin\$(Configuration)\$(Platform)\aspnetcoreca.dll</CustomActionVariable>
|
||||
|
||||
<PreBuiltANCMSchema>$(RepositoryRoot).deps\ANCM\Microsoft.AspNetCore.AspNetCoreModule\$(MicrosoftAspNetCoreAspNetCoreModulePackageVersion)\</PreBuiltANCMSchema>
|
||||
<PreBuiltANCMV2Schema>$(RepositoryRoot).deps\ANCM\Microsoft.AspNetCore.AspNetCoreModuleV2\$(MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion)\</PreBuiltANCMV2Schema>
|
||||
|
||||
<PreBuiltANCMRoot>$(PreBuiltANCMSchema)contentFiles\any\any\</PreBuiltANCMRoot>
|
||||
<PreBuiltANCMV2Root>$(PreBuiltANCMV2Schema)contentFiles\any\any\</PreBuiltANCMV2Root>
|
||||
|
||||
<ANCMOutOfProcessHandlerVersion>2.0.0</ANCMOutOfProcessHandlerVersion>
|
||||
<DefineConstants>ANCMOutOfProcessHandlerVersion=$(ANCMOutOfProcessHandlerVersion);$(DefineConstants)</DefineConstants>
|
||||
<DefineConstants>PreBuiltANCMRoot=$(PreBuiltANCMRoot);PreBuiltANCMV2Root=$(PreBuiltANCMV2Root);$(DefineConstants)</DefineConstants>
|
||||
<DefineConstants>$(CustomActionVariable);PreBuiltANCMSchema=$(PreBuiltANCMSchema);PreBuiltANCMV2Schema=$(PreBuiltANCMV2Schema);$(DefineConstants)</DefineConstants>
|
||||
|
||||
<_TwoDigitYear>$([MSBuild]::Subtract($([System.DateTime]::UtcNow.Year), 2000))</_TwoDigitYear>
|
||||
<_ThreeDigitDayOfYear>$([System.DateTime]::UtcNow.DayOfYear.ToString().PadLeft(3, '0'))</_ThreeDigitDayOfYear>
|
||||
|
||||
|
||||
<BUILD_MAJOR>$(_TwoDigitYear)$(_ThreeDigitDayOfYear)</BUILD_MAJOR>
|
||||
<BLDVERMAJOR>$(PRODUCT_MAJOR)</BLDVERMAJOR>
|
||||
<BLDVERMINOR>$(PRODUCT_MINOR)</BLDVERMINOR>
|
||||
<BLDNUMMAJOR>$(BUILD_MAJOR)</BLDNUMMAJOR>
|
||||
<BLDNUMMINOR>$(BUILD_MINOR)</BLDNUMMINOR>
|
||||
<DefineConstants>BLDVERMAJOR=$(BLDVERMAJOR);BLDVERMINOR=$(BLDVERMINOR);BLDNUMMAJOR=$(BLDNUMMAJOR);BLDNUMMINOR=$(BLDNUMMINOR);$(DefineConstants)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27120.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonLib", "lib\CommonLib.vcxproj", "{B54A8F61-60DE-4AD9-87CA-D102F230678E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reftrace", "reftrace\reftrace.vcxproj", "{A2599642-CBE5-4230-8511-3DC2D81874BE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x64.Build.0 = Debug|x64
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Debug|x86.Build.0 = Debug|Win32
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.ActiveCfg = Release|x64
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x64.Build.0 = Release|x64
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B54A8F61-60DE-4AD9-87CA-D102F230678E}.Release|x86.Build.0 = Release|Win32
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x64.Build.0 = Debug|x64
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x64.ActiveCfg = Release|x64
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x64.Build.0 = Release|x64
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A2599642-CBE5-4230-8511-3DC2D81874BE}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {81F5A61A-A12A-4F53-B0F9-C0E541CA6567}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "percpu.h"
|
||||
|
||||
|
||||
class ALLOC_CACHE_HANDLER
|
||||
{
|
||||
public:
|
||||
|
||||
ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
);
|
||||
|
||||
~ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD cbSize,
|
||||
LONG nThreshold
|
||||
);
|
||||
|
||||
LPVOID
|
||||
Alloc(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Free(
|
||||
__in LPVOID pMemory
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
VOID
|
||||
CleanupLookaside(
|
||||
VOID
|
||||
);
|
||||
|
||||
DWORD
|
||||
QueryDepthForAllSLists(
|
||||
VOID
|
||||
);
|
||||
|
||||
LONG m_nThreshold;
|
||||
DWORD m_cbSize;
|
||||
|
||||
PER_CPU<SLIST_HEADER> * m_pFreeLists;
|
||||
|
||||
//
|
||||
// Total heap allocations done over the lifetime.
|
||||
// Note that this is not interlocked, it is just a hint for debugging.
|
||||
//
|
||||
volatile LONG m_nTotal;
|
||||
|
||||
LONG m_nFillPattern;
|
||||
|
||||
public:
|
||||
|
||||
static
|
||||
HRESULT
|
||||
StaticInitialize(
|
||||
VOID
|
||||
);
|
||||
|
||||
static
|
||||
VOID
|
||||
StaticTerminate(
|
||||
VOID
|
||||
);
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsPageheapEnabled();
|
||||
|
||||
private:
|
||||
|
||||
static LONG sm_nFillPattern;
|
||||
static HANDLE sm_hHeap;
|
||||
};
|
||||
|
||||
|
||||
// You can use ALLOC_CACHE_HANDLER as a per-class allocator
|
||||
// in your C++ classes. Add the following to your class definition:
|
||||
//
|
||||
// protected:
|
||||
// static ALLOC_CACHE_HANDLER* sm_palloc;
|
||||
// public:
|
||||
// static void* operator new(size_t s)
|
||||
// {
|
||||
// IRTLASSERT(s == sizeof(C));
|
||||
// IRTLASSERT(sm_palloc != NULL);
|
||||
// return sm_palloc->Alloc();
|
||||
// }
|
||||
// static void operator delete(void* pv)
|
||||
// {
|
||||
// IRTLASSERT(pv != NULL);
|
||||
// if (sm_palloc != NULL)
|
||||
// sm_palloc->Free(pv);
|
||||
// }
|
||||
//
|
||||
// Obviously, you must initialize sm_palloc before you can allocate
|
||||
// any objects of this class.
|
||||
//
|
||||
// Note that if you derive a class from this base class, the derived class
|
||||
// must also provide its own operator new and operator delete. If not, the
|
||||
// base class's allocator will be called, but the size of the derived
|
||||
// object will almost certainly be larger than that of the base object.
|
||||
// Furthermore, the allocator will not be used for arrays of objects
|
||||
// (override operator new[] and operator delete[]), but this is a
|
||||
// harder problem since the allocator works with one fixed size.
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
HRESULT
|
||||
SetElementProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
IN CONST VARIANT * varPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
IN CONST WCHAR * szPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
OUT BSTR * pbstrPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementStringProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szPropName,
|
||||
OUT STRU * pstrPropValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementBoolProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT BOOL * pBool
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementBoolProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT bool * pBool
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementChildByName(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszElementName,
|
||||
OUT IAppHostElement ** ppChildElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementDWORDProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT DWORD * pdwValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementINTProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT INT * pintValue
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetElementLONGLONGProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT LONGLONG * pllValue
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
GetElementRawTimeSpanProperty(
|
||||
IN IAppHostElement * pElement,
|
||||
IN LPCWSTR pszPropertyName,
|
||||
OUT ULONGLONG * pulonglong
|
||||
);
|
||||
|
||||
#define FIND_ELEMENT_CASE_SENSITIVE 0x00000000
|
||||
#define FIND_ELEMENT_CASE_INSENSITIVE 0x00000001
|
||||
|
||||
HRESULT
|
||||
DeleteElementFromCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
BOOL * pfDeleted
|
||||
);
|
||||
|
||||
HRESULT
|
||||
DeleteAllElementsFromCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
UINT * pNumDeleted
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindElementInCollection(
|
||||
IAppHostElementCollection *pCollection,
|
||||
CONST WCHAR * szKeyName,
|
||||
CONST WCHAR * szKeyValue,
|
||||
ULONG BehaviorFlags,
|
||||
OUT ULONG * pIndex
|
||||
);
|
||||
|
||||
HRESULT
|
||||
VariantAssign(
|
||||
IN OUT VARIANT * pv,
|
||||
IN CONST WCHAR * sz
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetLocationFromFile(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szLocationPath,
|
||||
OUT IAppHostConfigLocation ** ppLocation,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetSectionFromLocation(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN CONST WCHAR * szSectionName,
|
||||
OUT IAppHostElement ** ppSectionElement,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetAdminElement(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearAdminElement(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearElementFromAllSites(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearElementFromAllLocations(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearLocationElements(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN CONST WCHAR * szElementName
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CompareElementName(
|
||||
IN IAppHostElement * pElement,
|
||||
IN CONST WCHAR * szNameToMatch,
|
||||
OUT BOOL * pMatched
|
||||
);
|
||||
|
||||
HRESULT
|
||||
ClearChildElementsByName(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
IN CONST WCHAR * szElementName,
|
||||
OUT BOOL * pFound
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetSitesCollection(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
OUT IAppHostElementCollection ** pSitesCollection
|
||||
);
|
||||
|
||||
HRESULT
|
||||
GetLocationCollection(
|
||||
IN IAppHostAdminManager * pAdminMgr,
|
||||
IN CONST WCHAR * szConfigPath,
|
||||
OUT IAppHostConfigLocationCollection ** pLocationCollection
|
||||
);
|
||||
|
||||
struct ENUM_INDEX
|
||||
{
|
||||
VARIANT Index;
|
||||
ULONG Count;
|
||||
};
|
||||
|
||||
HRESULT
|
||||
FindFirstElement(
|
||||
IN IAppHostElementCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextElement(
|
||||
IN IAppHostElementCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstChildElement(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextChildElement(
|
||||
IN IAppHostChildElementCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstLocation(
|
||||
IN IAppHostConfigLocationCollection * pCollection,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostConfigLocation ** pLocation
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextLocation(
|
||||
IN IAppHostConfigLocationCollection * pCollection,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostConfigLocation ** pLocation
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindFirstLocationElement(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT
|
||||
FindNextLocationElement(
|
||||
IN IAppHostConfigLocation * pLocation,
|
||||
IN OUT ENUM_INDEX * pIndex,
|
||||
OUT IAppHostElement ** pElement
|
||||
);
|
||||
|
||||
HRESULT GetSharedConfigEnabled(
|
||||
BOOL * pfIsSharedConfig
|
||||
);
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _BASE64_HXX_
|
||||
#define _BASE64_HXX_
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt( cchEncodedStringSize ) PWSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCWSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount( cbDecodedBufferSize ) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt( cchEncodedStringSize ) PSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
);
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
);
|
||||
|
||||
#endif // _BASE64_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crtdbg.h>
|
||||
|
||||
|
||||
//
|
||||
// BUFFER_T class shouldn't be used directly. Use BUFFER specialization class instead.
|
||||
// The only BUFFER_T partners are STRU and STRA classes.
|
||||
// BUFFER_T cannot hold other but primitive types since it doesn't call
|
||||
// constructor and destructor.
|
||||
//
|
||||
// Note: Size is in bytes.
|
||||
//
|
||||
template<typename T, DWORD LENGTH>
|
||||
class BUFFER_T
|
||||
{
|
||||
public:
|
||||
|
||||
BUFFER_T()
|
||||
: m_cbBuffer( sizeof(m_rgBuffer) ),
|
||||
m_fHeapAllocated( false ),
|
||||
m_pBuffer(m_rgBuffer)
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Default constructor where the inline buffer is used.
|
||||
|
||||
Arguments:
|
||||
|
||||
None.
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
}
|
||||
|
||||
BUFFER_T(
|
||||
__inout_bcount(cbInit) T* pbInit,
|
||||
__in DWORD cbInit
|
||||
) : m_pBuffer( pbInit ),
|
||||
m_cbBuffer( cbInit ),
|
||||
m_fHeapAllocated( false )
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Instantiate BUFFER, initially using pbInit as buffer
|
||||
This is useful for stack-buffers and inline-buffer class members
|
||||
(see STACK_BUFFER and INLINE_BUFFER_INIT below)
|
||||
|
||||
BUFFER does not free pbInit.
|
||||
|
||||
Arguments:
|
||||
|
||||
pbInit - Initial buffer to use.
|
||||
cbInit - Size of pbInit in bytes (not in elements).
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
_ASSERTE( NULL != pbInit );
|
||||
_ASSERTE( cbInit > 0 );
|
||||
}
|
||||
|
||||
~BUFFER_T()
|
||||
{
|
||||
if( IsHeapAllocated() )
|
||||
{
|
||||
_ASSERTE( NULL != m_pBuffer );
|
||||
HeapFree( GetProcessHeap(), 0, m_pBuffer );
|
||||
m_pBuffer = NULL;
|
||||
m_cbBuffer = 0;
|
||||
m_fHeapAllocated = false;
|
||||
}
|
||||
}
|
||||
|
||||
T*
|
||||
QueryPtr(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Return pointer to data buffer.
|
||||
//
|
||||
return m_pBuffer;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QuerySize(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Return number of bytes.
|
||||
//
|
||||
return m_cbBuffer;
|
||||
}
|
||||
|
||||
__success(return == true)
|
||||
bool
|
||||
Resize(
|
||||
const SIZE_T cbNewSize,
|
||||
const bool fZeroMemoryBeyondOldSize = false
|
||||
)
|
||||
/*++
|
||||
Description:
|
||||
|
||||
Resizes the buffer.
|
||||
|
||||
Arguments:
|
||||
|
||||
cbNewSize - Size in bytes to grow to.
|
||||
fZeroMemoryBeyondOldSize
|
||||
- Whether to zero the region of memory of the
|
||||
new buffer beyond the original size.
|
||||
|
||||
Returns:
|
||||
|
||||
TRUE on success, FALSE on failure.
|
||||
|
||||
--*/
|
||||
{
|
||||
PVOID pNewMem;
|
||||
|
||||
if ( cbNewSize <= m_cbBuffer )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( cbNewSize > MAXDWORD )
|
||||
{
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwHeapAllocFlags = fZeroMemoryBeyondOldSize ? HEAP_ZERO_MEMORY : 0;
|
||||
|
||||
if( IsHeapAllocated() )
|
||||
{
|
||||
pNewMem = HeapReAlloc( GetProcessHeap(), dwHeapAllocFlags, m_pBuffer, cbNewSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewMem = HeapAlloc( GetProcessHeap(), dwHeapAllocFlags, cbNewSize );
|
||||
}
|
||||
|
||||
if( pNewMem == NULL )
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !IsHeapAllocated() )
|
||||
{
|
||||
//
|
||||
// First time this block is allocated. Copy over old contents.
|
||||
//
|
||||
memcpy_s( pNewMem, static_cast<DWORD>(cbNewSize), m_pBuffer, m_cbBuffer );
|
||||
m_fHeapAllocated = true;
|
||||
}
|
||||
|
||||
m_pBuffer = reinterpret_cast<T*>(pNewMem);
|
||||
m_cbBuffer = static_cast<DWORD>(cbNewSize);
|
||||
|
||||
_ASSERTE( m_pBuffer != NULL );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool
|
||||
IsHeapAllocated(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return m_fHeapAllocated;
|
||||
}
|
||||
|
||||
//
|
||||
// The default inline buffer.
|
||||
// This member should be at the beginning for alignment purposes.
|
||||
//
|
||||
T m_rgBuffer[LENGTH];
|
||||
|
||||
//
|
||||
// Is m_pBuffer dynamically allocated?
|
||||
//
|
||||
bool m_fHeapAllocated;
|
||||
|
||||
//
|
||||
// Size of the buffer as requested by client in bytes.
|
||||
//
|
||||
DWORD m_cbBuffer;
|
||||
|
||||
//
|
||||
// Pointer to buffer.
|
||||
//
|
||||
__field_bcount_full(m_cbBuffer)
|
||||
T* m_pBuffer;
|
||||
};
|
||||
|
||||
//
|
||||
// Resizes the buffer by 2 if the ideal size is bigger
|
||||
// than the buffer length. That give us lg(n) allocations.
|
||||
//
|
||||
// Use template inferring like:
|
||||
//
|
||||
// BUFFER buff;
|
||||
// hr = ResizeBufferByTwo(buff, 100);
|
||||
//
|
||||
template<typename T, DWORD LENGTH>
|
||||
HRESULT
|
||||
ResizeBufferByTwo(
|
||||
BUFFER_T<T,LENGTH>& Buffer,
|
||||
SIZE_T cbIdealSize,
|
||||
bool fZeroMemoryBeyondOldSize = false
|
||||
)
|
||||
{
|
||||
if (cbIdealSize > Buffer.QuerySize())
|
||||
{
|
||||
if (!Buffer.Resize(max(cbIdealSize, static_cast<SIZE_T>(Buffer.QuerySize() * 2)),
|
||||
fZeroMemoryBeyondOldSize))
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Lots of code uses BUFFER class to store a bunch of different
|
||||
// structures, so m_rgBuffer needs to be 8 byte aligned when it is used
|
||||
// as an opaque buffer.
|
||||
//
|
||||
#define INLINED_BUFFER_LEN 32
|
||||
typedef BUFFER_T<BYTE, INLINED_BUFFER_LEN> BUFFER;
|
||||
|
||||
//
|
||||
// Assumption of macros below for pointer alignment purposes
|
||||
//
|
||||
C_ASSERT( sizeof(VOID*) <= sizeof(ULONGLONG) );
|
||||
|
||||
//
|
||||
// Declare a BUFFER that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated.
|
||||
//
|
||||
#define STACK_BUFFER( _name, _size ) \
|
||||
ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
|
||||
BUFFER _name( (BYTE*)__aqw##_name, sizeof(__aqw##_name) )
|
||||
|
||||
//
|
||||
// Macros for declaring and initializing a BUFFER that will use inline memory
|
||||
// of <size> bytes as a member of an object.
|
||||
//
|
||||
#define INLINE_BUFFER( _name, _size ) \
|
||||
ULONGLONG __aqw##_name[ ( ( (_size) + sizeof(ULONGLONG) - 1 ) / sizeof(ULONGLONG) ) ]; \
|
||||
BUFFER _name;
|
||||
|
||||
#define INLINE_BUFFER_INIT( _name ) \
|
||||
_name( (BYTE*)__aqw##_name, sizeof( __aqw##_name ) )
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _DATETIME_H_
|
||||
#define _DATETIME_H_
|
||||
|
||||
BOOL
|
||||
StringTimeToFileTime(
|
||||
PCSTR pszTime,
|
||||
ULONGLONG * pulTime
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _DBGUTIL_H_
|
||||
#define _DBGUTIL_H_
|
||||
|
||||
#include <crtdbg.h>
|
||||
|
||||
//
|
||||
// TODO
|
||||
// Using _CrtDbg implementation. If hooking is desired
|
||||
// wrappers should be provided here so that we can reimplement
|
||||
// if neecessary.
|
||||
//
|
||||
// IF_DEBUG/DEBUG FLAGS
|
||||
//
|
||||
// registry configuration
|
||||
//
|
||||
|
||||
//
|
||||
// Debug error levels for DEBUG_FLAGS_VAR.
|
||||
//
|
||||
|
||||
#define DEBUG_FLAG_INFO 0x00000001
|
||||
#define DEBUG_FLAG_WARN 0x00000002
|
||||
#define DEBUG_FLAG_ERROR 0x00000004
|
||||
|
||||
//
|
||||
// Predefined error level values. These are backwards from the
|
||||
// windows definitions.
|
||||
//
|
||||
|
||||
#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
|
||||
#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
|
||||
#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR)
|
||||
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
//
|
||||
// Global variables to control tracing. Generally per module
|
||||
//
|
||||
|
||||
#ifndef DEBUG_FLAGS_VAR
|
||||
#define DEBUG_FLAGS_VAR g_dwDebugFlags
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_LABEL_VAR
|
||||
#define DEBUG_LABEL_VAR g_szDebugLabel
|
||||
#endif
|
||||
|
||||
extern PCSTR DEBUG_LABEL_VAR;
|
||||
extern DWORD DEBUG_FLAGS_VAR;
|
||||
|
||||
//
|
||||
// Module should make this declaration globally.
|
||||
//
|
||||
|
||||
#define DECLARE_DEBUG_PRINT_OBJECT( _pszLabel_ ) \
|
||||
PCSTR DEBUG_LABEL_VAR = _pszLabel_; \
|
||||
DWORD DEBUG_FLAGS_VAR = DEBUG_FLAGS_ANY; \
|
||||
|
||||
#define DECLARE_DEBUG_PRINT_OBJECT2( _pszLabel_, _dwLevel_ ) \
|
||||
PCSTR DEBUG_LABEL_VAR = _pszLabel_; \
|
||||
DWORD DEBUG_FLAGS_VAR = _dwLevel_; \
|
||||
|
||||
//
|
||||
// This doesn't do anything now. Should be safe to call in dll main.
|
||||
//
|
||||
|
||||
#define CREATE_DEBUG_PRINT_OBJECT
|
||||
|
||||
//
|
||||
// Trace macros
|
||||
//
|
||||
|
||||
#define DBG_CONTEXT _CRT_WARN, __FILE__, __LINE__, DEBUG_LABEL_VAR
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBGINFO(args) \
|
||||
{if( DEBUG_FLAGS_VAR & DEBUG_FLAG_INFO ) { _CrtDbgReport args; }}
|
||||
#define DBGWARN(args) \
|
||||
{if( DEBUG_FLAGS_VAR & DEBUG_FLAG_WARN ) { _CrtDbgReport args; }}
|
||||
#define DBGERROR(args) \
|
||||
{if( DEBUG_FLAGS_VAR & DEBUG_FLAG_ERROR ) { _CrtDbgReport args; }}
|
||||
#else
|
||||
#define DBGINFO
|
||||
#define DBGWARN
|
||||
#define DBGERROR
|
||||
#endif
|
||||
|
||||
#define DBGPRINTF DBGINFO
|
||||
|
||||
//
|
||||
// Simple error traces
|
||||
//
|
||||
|
||||
#define DBGERROR_HR( _hr_ ) \
|
||||
DBGERROR(( DBG_CONTEXT, "hr=0x%x\n", _hr_ ))
|
||||
|
||||
#define DBGERROR_STATUS( _status_ ) \
|
||||
DBGERROR(( DBG_CONTEXT, "status=%d\n", _status_ ))
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define DEBUG_FLAG_INFO 0x00000001
|
||||
#define DEBUG_FLAG_WARN 0x00000002
|
||||
#define DEBUG_FLAG_ERROR 0x00000004
|
||||
|
||||
//
|
||||
// Predefined error level values. These are backwards from the
|
||||
// windows definitions.
|
||||
//
|
||||
|
||||
#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN | DEBUG_FLAG_INFO)
|
||||
#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ERROR | DEBUG_FLAG_WARN)
|
||||
#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ERROR)
|
||||
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
#define DEBUG_FLAGS_REGISTRY_LOCATION_A "DebugFlags"
|
||||
|
||||
extern DWORD g_dwDebugFlags;
|
||||
|
||||
static
|
||||
BOOL
|
||||
IfDebug(
|
||||
DWORD dwFlag
|
||||
)
|
||||
{
|
||||
return ( dwFlag & g_dwDebugFlags );
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
DebugPrint(
|
||||
DWORD dwFlag,
|
||||
LPCSTR szString
|
||||
)
|
||||
{
|
||||
STBUFF strOutput;
|
||||
HRESULT hr;
|
||||
|
||||
if ( IfDebug( dwFlag ) )
|
||||
{
|
||||
hr = strOutput.Printf( "[dipmodule.dll] %s\r\n",
|
||||
szString );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
OutputDebugStringA( strOutput.QueryStr() );
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
DebugPrintf(
|
||||
DWORD dwFlag,
|
||||
LPCSTR szFormat,
|
||||
...
|
||||
)
|
||||
{
|
||||
STBUFF strCooked;
|
||||
STBUFF strOutput;
|
||||
va_list args;
|
||||
HRESULT hr;
|
||||
|
||||
if ( IfDebug( dwFlag ) )
|
||||
{
|
||||
va_start( args, szFormat );
|
||||
|
||||
hr = strCooked.Vsprintf( (LPSTR)szFormat, args );
|
||||
|
||||
va_end( args );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
DebugPrint( dwFlag, strCooked.QueryStr() );
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void ReadDebugFlagFromRegistryKey(const char* pszRegKey, IN DWORD dwDefault)
|
||||
{
|
||||
HKEY hkey = NULL;
|
||||
g_dwDebugFlags = dwDefault;
|
||||
DWORD dwType;
|
||||
DWORD dwBuffer;
|
||||
DWORD cbBuffer = sizeof(dwBuffer);
|
||||
|
||||
DWORD dwError = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
pszRegKey,
|
||||
0,
|
||||
KEY_READ,
|
||||
&hkey);
|
||||
if ( dwError == NO_ERROR && hkey != NULL)
|
||||
{
|
||||
dwError = RegQueryValueExA( hkey,
|
||||
DEBUG_FLAGS_REGISTRY_LOCATION_A,
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE)&dwBuffer,
|
||||
&cbBuffer );
|
||||
if( ( dwError == NO_ERROR ) && ( dwType == REG_DWORD ) )
|
||||
{
|
||||
g_dwDebugFlags = dwBuffer;
|
||||
}
|
||||
RegCloseKey( hkey);
|
||||
hkey = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef __HASHFN_H__
|
||||
#define __HASHFN_H__
|
||||
|
||||
|
||||
// Produce a scrambled, randomish number in the range 0 to RANDOM_PRIME-1.
|
||||
// Applying this to the results of the other hash functions is likely to
|
||||
// produce a much better distribution, especially for the identity hash
|
||||
// functions such as Hash(char c), where records will tend to cluster at
|
||||
// the low end of the hashtable otherwise. LKRhash applies this internally
|
||||
// to all hash signatures for exactly this reason.
|
||||
|
||||
inline DWORD
|
||||
HashScramble(DWORD dwHash)
|
||||
{
|
||||
// Here are 10 primes slightly greater than 10^9
|
||||
// 1000000007, 1000000009, 1000000021, 1000000033, 1000000087,
|
||||
// 1000000093, 1000000097, 1000000103, 1000000123, 1000000181.
|
||||
|
||||
// default value for "scrambling constant"
|
||||
const DWORD RANDOM_CONSTANT = 314159269UL;
|
||||
// large prime number, also used for scrambling
|
||||
const DWORD RANDOM_PRIME = 1000000007UL;
|
||||
|
||||
return (RANDOM_CONSTANT * dwHash) % RANDOM_PRIME ;
|
||||
}
|
||||
|
||||
|
||||
// Faster scrambling function suggested by Eric Jacobsen
|
||||
|
||||
inline DWORD
|
||||
HashRandomizeBits(DWORD dw)
|
||||
{
|
||||
return (((dw * 1103515245 + 12345) >> 16)
|
||||
| ((dw * 69069 + 1) & 0xffff0000));
|
||||
}
|
||||
|
||||
|
||||
// Small prime number used as a multiplier in the supplied hash functions
|
||||
const DWORD HASH_MULTIPLIER = 101;
|
||||
|
||||
#undef HASH_SHIFT_MULTIPLY
|
||||
|
||||
#ifdef HASH_SHIFT_MULTIPLY
|
||||
# define HASH_MULTIPLY(dw) (((dw) << 7) - (dw))
|
||||
#else
|
||||
# define HASH_MULTIPLY(dw) ((dw) * HASH_MULTIPLIER)
|
||||
#endif
|
||||
|
||||
// Fast, simple hash function that tends to give a good distribution.
|
||||
// Apply HashScramble to the result if you're using this for something
|
||||
// other than LKRhash.
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
const char* psz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
// force compiler to use unsigned arithmetic
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for ( ; *upsz; ++upsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *upsz;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
__in_ecount(cch) const char* psz,
|
||||
__in DWORD cch,
|
||||
__in DWORD dwHash
|
||||
)
|
||||
{
|
||||
// force compiler to use unsigned arithmetic
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for (DWORD Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++upsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *upsz;
|
||||
}
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Unicode version of above
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
const wchar_t* pwsz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
for ( ; *pwsz; ++pwsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
// Based on length of the string instead of null-terminating character
|
||||
|
||||
inline DWORD
|
||||
HashString(
|
||||
__in_ecount(cch) const wchar_t* pwsz,
|
||||
__in DWORD cch,
|
||||
__in DWORD dwHash
|
||||
)
|
||||
{
|
||||
for (DWORD Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++pwsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pwsz;
|
||||
}
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Quick-'n'-dirty case-insensitive string hash function.
|
||||
// Make sure that you follow up with _stricmp or _mbsicmp. You should
|
||||
// also cache the length of strings and check those first. Caching
|
||||
// an uppercase version of a string can help too.
|
||||
// Again, apply HashScramble to the result if using with something other
|
||||
// than LKRhash.
|
||||
// Note: this is not really adequate for MBCS strings.
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
const char* psz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for ( ; *upsz; ++upsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash)
|
||||
+ (*upsz & 0xDF); // strip off lowercase bit
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
__in_ecount(cch)
|
||||
const char* psz,
|
||||
SIZE_T cch,
|
||||
DWORD dwHash)
|
||||
{
|
||||
const unsigned char* upsz = (const unsigned char*) psz;
|
||||
|
||||
for (SIZE_T Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++upsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash)
|
||||
+ (*upsz & 0xDF); // strip off lowercase bit
|
||||
}
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// Unicode version of above
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
const wchar_t* pwsz,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
for ( ; *pwsz; ++pwsz)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
// Unicode version of above with length
|
||||
|
||||
inline DWORD
|
||||
HashStringNoCase(
|
||||
__in_ecount(cch)
|
||||
const wchar_t* pwsz,
|
||||
SIZE_T cch,
|
||||
DWORD dwHash)
|
||||
{
|
||||
for (SIZE_T Index = 0;
|
||||
Index < cch;
|
||||
++Index, ++pwsz)
|
||||
{
|
||||
dwHash = HASH_MULTIPLY(dwHash) + (*pwsz & 0xFFDF);
|
||||
}
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
// HashBlob returns the hash of a blob of arbitrary binary data.
|
||||
//
|
||||
// Warning: HashBlob is generally not the right way to hash a class object.
|
||||
// Consider:
|
||||
// class CFoo {
|
||||
// public:
|
||||
// char m_ch;
|
||||
// double m_d;
|
||||
// char* m_psz;
|
||||
// };
|
||||
//
|
||||
// inline DWORD Hash(const CFoo& rFoo)
|
||||
// { return HashBlob(&rFoo, sizeof(CFoo)); }
|
||||
//
|
||||
// This is the wrong way to hash a CFoo for two reasons: (a) there will be
|
||||
// a 7-byte gap between m_ch and m_d imposed by the alignment restrictions
|
||||
// of doubles, which will be filled with random data (usually non-zero for
|
||||
// stack variables), and (b) it hashes the address (rather than the
|
||||
// contents) of the string m_psz. Similarly,
|
||||
//
|
||||
// bool operator==(const CFoo& rFoo1, const CFoo& rFoo2)
|
||||
// { return memcmp(&rFoo1, &rFoo2, sizeof(CFoo)) == 0; }
|
||||
//
|
||||
// does the wrong thing. Much better to do this:
|
||||
//
|
||||
// DWORD Hash(const CFoo& rFoo)
|
||||
// {
|
||||
// return HashString(rFoo.m_psz,
|
||||
// HASH_MULTIPLIER * Hash(rFoo.m_ch)
|
||||
// + Hash(rFoo.m_d));
|
||||
// }
|
||||
//
|
||||
// Again, apply HashScramble if using with something other than LKRhash.
|
||||
|
||||
inline DWORD
|
||||
HashBlob(
|
||||
const void* pv,
|
||||
size_t cb,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
const BYTE * pb = static_cast<const BYTE *>(pv);
|
||||
|
||||
while (cb-- > 0)
|
||||
dwHash = HASH_MULTIPLY(dwHash) + *pb++;
|
||||
|
||||
return dwHash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Overloaded hash functions for all the major builtin types.
|
||||
// Again, apply HashScramble to result if using with something other than
|
||||
// LKRhash.
|
||||
//
|
||||
|
||||
inline DWORD Hash(const char* psz)
|
||||
{ return HashString(psz); }
|
||||
|
||||
inline DWORD Hash(const unsigned char* pusz)
|
||||
{ return HashString(reinterpret_cast<const char*>(pusz)); }
|
||||
|
||||
inline DWORD Hash(const signed char* pssz)
|
||||
{ return HashString(reinterpret_cast<const char*>(pssz)); }
|
||||
|
||||
inline DWORD Hash(const wchar_t* pwsz)
|
||||
{ return HashString(pwsz); }
|
||||
|
||||
inline DWORD
|
||||
Hash(
|
||||
const GUID* pguid,
|
||||
DWORD dwHash = 0)
|
||||
{
|
||||
|
||||
return * reinterpret_cast<const DWORD *>(const_cast<GUID*>(pguid)) + dwHash;
|
||||
}
|
||||
|
||||
// Identity hash functions: scalar values map to themselves
|
||||
inline DWORD Hash(char c)
|
||||
{ return c; }
|
||||
|
||||
inline DWORD Hash(unsigned char uc)
|
||||
{ return uc; }
|
||||
|
||||
inline DWORD Hash(signed char sc)
|
||||
{ return sc; }
|
||||
|
||||
inline DWORD Hash(short sh)
|
||||
{ return sh; }
|
||||
|
||||
inline DWORD Hash(unsigned short ush)
|
||||
{ return ush; }
|
||||
|
||||
inline DWORD Hash(int i)
|
||||
{ return i; }
|
||||
|
||||
inline DWORD Hash(unsigned int u)
|
||||
{ return u; }
|
||||
|
||||
inline DWORD Hash(long l)
|
||||
{ return l; }
|
||||
|
||||
inline DWORD Hash(unsigned long ul)
|
||||
{ return ul; }
|
||||
|
||||
inline DWORD Hash(float f)
|
||||
{
|
||||
// be careful of rounding errors when computing keys
|
||||
union {
|
||||
float f;
|
||||
DWORD dw;
|
||||
} u;
|
||||
u.f = f;
|
||||
return u.dw;
|
||||
}
|
||||
|
||||
inline DWORD Hash(double dbl)
|
||||
{
|
||||
// be careful of rounding errors when computing keys
|
||||
union {
|
||||
double dbl;
|
||||
DWORD dw[2];
|
||||
} u;
|
||||
u.dbl = dbl;
|
||||
return u.dw[0] * HASH_MULTIPLIER + u.dw[1];
|
||||
}
|
||||
|
||||
#endif // __HASHFN_H__
|
||||
|
|
@ -0,0 +1,666 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include "rwlock.h"
|
||||
#include "prime.h"
|
||||
|
||||
template <class _Record>
|
||||
class HASH_NODE
|
||||
{
|
||||
template <class _Record, class _Key>
|
||||
friend class HASH_TABLE;
|
||||
|
||||
HASH_NODE(
|
||||
_Record * pRecord,
|
||||
DWORD dwHash
|
||||
) : _pNext (NULL),
|
||||
_pRecord (pRecord),
|
||||
_dwHash (dwHash)
|
||||
{}
|
||||
|
||||
~HASH_NODE()
|
||||
{
|
||||
_ASSERTE(_pRecord == NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
// Next node in the hash table look-aside
|
||||
HASH_NODE<_Record> *_pNext;
|
||||
|
||||
// actual record
|
||||
_Record * _pRecord;
|
||||
|
||||
// hash value
|
||||
DWORD _dwHash;
|
||||
};
|
||||
|
||||
template <class _Record, class _Key>
|
||||
class HASH_TABLE
|
||||
{
|
||||
protected:
|
||||
typedef BOOL
|
||||
(PFN_DELETE_IF)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
typedef VOID
|
||||
(PFN_APPLY)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
public:
|
||||
HASH_TABLE(
|
||||
VOID
|
||||
)
|
||||
: _ppBuckets( NULL ),
|
||||
_nBuckets( 0 ),
|
||||
_nItems( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~HASH_TABLE();
|
||||
|
||||
virtual
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
_Key
|
||||
ExtractKey(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
_Key key
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
BOOL
|
||||
EqualKeys(
|
||||
_Key key1,
|
||||
_Key key2
|
||||
) = 0;
|
||||
|
||||
DWORD
|
||||
Count(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
bool
|
||||
IsInitialized(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
Clear();
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD nBucketSize
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
FindKey(
|
||||
_Key key,
|
||||
_Record ** ppRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
HRESULT
|
||||
InsertRecord(
|
||||
_Record * pRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteKey(
|
||||
_Key key
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
VOID
|
||||
Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
__success(*ppNode != NULL && return != FALSE)
|
||||
BOOL
|
||||
FindNodeInternal(
|
||||
_Key key,
|
||||
DWORD dwHash,
|
||||
__deref_out
|
||||
HASH_NODE<_Record> ** ppNode,
|
||||
__deref_opt_out
|
||||
HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL
|
||||
);
|
||||
|
||||
VOID
|
||||
DeleteNode(
|
||||
HASH_NODE<_Record> * pNode
|
||||
)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
DereferenceRecord(pNode->_pRecord);
|
||||
pNode->_pRecord = NULL;
|
||||
}
|
||||
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
VOID
|
||||
RehashTableIfNeeded(
|
||||
VOID
|
||||
);
|
||||
|
||||
HASH_NODE<_Record> ** _ppBuckets;
|
||||
DWORD _nBuckets;
|
||||
DWORD _nItems;
|
||||
//
|
||||
// Allow to use lock object in const methods.
|
||||
//
|
||||
mutable
|
||||
CWSDRWLock _tableLock;
|
||||
};
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HRESULT
|
||||
HASH_TABLE<_Record,_Key>::Initialize(
|
||||
DWORD nBuckets
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( nBuckets == 0 )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
if (nBuckets >= MAXDWORD/sizeof(HASH_NODE<_Record> *))
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_ASSERTE(_ppBuckets == NULL );
|
||||
if ( _ppBuckets != NULL )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
hr = _tableLock.Init();
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(HASH_NODE<_Record> *));
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Failed;
|
||||
}
|
||||
_nBuckets = nBuckets;
|
||||
|
||||
return S_OK;
|
||||
|
||||
Failed:
|
||||
|
||||
if (_ppBuckets)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HASH_TABLE<_Record,_Key>::~HASH_TABLE()
|
||||
{
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ASSERTE(_nItems == 0);
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
_nBuckets = 0;
|
||||
}
|
||||
|
||||
template< class _Record, class _Key>
|
||||
DWORD
|
||||
HASH_TABLE<_Record,_Key>::Count() const
|
||||
{
|
||||
return _nItems;
|
||||
}
|
||||
|
||||
template< class _Record, class _Key>
|
||||
bool
|
||||
HASH_TABLE<_Record,_Key>::IsInitialized(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return _ppBuckets != NULL;
|
||||
}
|
||||
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::Clear()
|
||||
{
|
||||
HASH_NODE<_Record> *pCurrent;
|
||||
HASH_NODE<_Record> *pNext;
|
||||
|
||||
// This is here in the off cases where someone instantiates a hashtable
|
||||
// and then does an automatic "clear" before its destruction WITHOUT
|
||||
// ever initializing it.
|
||||
if ( ! _tableLock.QueryInited() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pCurrent = _ppBuckets[i];
|
||||
_ppBuckets[i] = NULL;
|
||||
while (pCurrent != NULL)
|
||||
{
|
||||
pNext = pCurrent->_pNext;
|
||||
DeleteNode(pCurrent);
|
||||
pCurrent = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_nItems = 0;
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
__success(*ppNode != NULL && return != FALSE)
|
||||
BOOL
|
||||
HASH_TABLE<_Record,_Key>::FindNodeInternal(
|
||||
_Key key,
|
||||
DWORD dwHash,
|
||||
__deref_out
|
||||
HASH_NODE<_Record> ** ppNode,
|
||||
__deref_opt_out
|
||||
HASH_NODE<_Record> *** pppPreviousNodeNextPointer
|
||||
)
|
||||
/*++
|
||||
Return value indicates whether the item is found
|
||||
key, dwHash - key and hash for the node to find
|
||||
ppNode - on successful return, the node found, on failed return, the first
|
||||
node with hash value greater than the node to be found
|
||||
pppPreviousNodeNextPointer - the pointer to previous node's _pNext
|
||||
|
||||
This routine may be called under either read or write lock
|
||||
--*/
|
||||
{
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
HASH_NODE<_Record> *pNode;
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_dwHash == dwHash)
|
||||
{
|
||||
if (EqualKeys(key,
|
||||
ExtractKey(pNode->_pRecord)))
|
||||
{
|
||||
fFound = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pNode->_dwHash > dwHash)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ppPreviousNodeNextPointer = &(pNode->_pNext);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
|
||||
__analysis_assume( (pNode == NULL && fFound == FALSE) ||
|
||||
(pNode != NULL && fFound == TRUE ) );
|
||||
*ppNode = pNode;
|
||||
if (pppPreviousNodeNextPointer != NULL)
|
||||
{
|
||||
*pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
|
||||
}
|
||||
return fFound;
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::FindKey(
|
||||
_Key key,
|
||||
_Record ** ppRecord
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
|
||||
*ppRecord = NULL;
|
||||
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
if (FindNodeInternal(key, dwHash, &pNode) &&
|
||||
pNode->_pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pNode->_pRecord);
|
||||
*ppRecord = pNode->_pRecord;
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
HRESULT
|
||||
HASH_TABLE<_Record,_Key>::InsertRecord(
|
||||
_Record * pRecord
|
||||
)
|
||||
/*++
|
||||
This method inserts a node for this record and also empty nodes for paths
|
||||
in the heirarchy leading upto this path
|
||||
|
||||
The insert is done under only a read-lock - this is possible by keeping
|
||||
the hashes in a bucket in increasing order and using interlocked operations
|
||||
to actually insert the item in the hash-bucket lookaside list and the parent
|
||||
children list
|
||||
|
||||
Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
|
||||
Never leak this error to the end user because "*file* already exists" may be confusing.
|
||||
--*/
|
||||
{
|
||||
BOOL fLocked = FALSE;
|
||||
_Key key = ExtractKey(pRecord);
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
HRESULT hr = S_OK;
|
||||
HASH_NODE<_Record> * pNewNode;
|
||||
HASH_NODE<_Record> * pNextNode;
|
||||
HASH_NODE<_Record> ** ppPreviousNodeNextPointer;
|
||||
|
||||
//
|
||||
// Ownership of pRecord is not transferred to pNewNode yet, so remember
|
||||
// to either set it to null before deleting pNewNode or add an extra
|
||||
// reference later - this is to make sure we do not do an extra ref/deref
|
||||
// which users may view as getting flushed out of the hash-table
|
||||
//
|
||||
pNewNode = new HASH_NODE<_Record>(pRecord, dwHash);
|
||||
if (pNewNode == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
fLocked = TRUE;
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Find the right place to add this node
|
||||
//
|
||||
if (FindNodeInternal(key, dwHash, &pNextNode, &ppPreviousNodeNextPointer))
|
||||
{
|
||||
//
|
||||
// If node already there, return error
|
||||
//
|
||||
pNewNode->_pRecord = NULL;
|
||||
DeleteNode(pNewNode);
|
||||
|
||||
//
|
||||
// We should never leak this error to the end user
|
||||
// because "file already exists" may be confusing.
|
||||
//
|
||||
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// If another node got inserted in between, we will have to retry
|
||||
//
|
||||
pNewNode->_pNext = pNextNode;
|
||||
} while (InterlockedCompareExchangePointer((PVOID *)ppPreviousNodeNextPointer,
|
||||
pNewNode,
|
||||
pNextNode) != pNextNode);
|
||||
// pass ownership of pRecord now
|
||||
if (pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pRecord);
|
||||
pRecord = NULL;
|
||||
}
|
||||
InterlockedIncrement((LONG *)&_nItems);
|
||||
|
||||
Finished:
|
||||
|
||||
if (fLocked)
|
||||
{
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RehashTableIfNeeded();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::DeleteKey(
|
||||
_Key key
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
|
||||
DWORD dwHash = CalcKeyHash(key);
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
if (FindNodeInternal(key, dwHash, &pNode, &ppPreviousNodeNextPointer))
|
||||
{
|
||||
*ppPreviousNodeNextPointer = pNode->_pNext;
|
||||
DeleteNode(pNode);
|
||||
_nItems--;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
ppPreviousNodeNextPointer = _ppBuckets + i;
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
//
|
||||
// Non empty nodes deleted based on DeleteIf, empty nodes deleted
|
||||
// if they have no children
|
||||
//
|
||||
if (pfnDeleteIf(pNode->_pRecord, pvContext))
|
||||
{
|
||||
*ppPreviousNodeNextPointer = pNode->_pNext;
|
||||
DeleteNode(pNode);
|
||||
_nItems--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ppPreviousNodeNextPointer = &pNode->_pNext;
|
||||
}
|
||||
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> *pNode;
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
pfnApply(pNode->_pRecord, pvContext);
|
||||
}
|
||||
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record, class _Key>
|
||||
VOID
|
||||
HASH_TABLE<_Record,_Key>::RehashTableIfNeeded(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HASH_NODE<_Record> **ppBuckets;
|
||||
DWORD nBuckets;
|
||||
HASH_NODE<_Record> *pNode;
|
||||
HASH_NODE<_Record> *pNextNode;
|
||||
HASH_NODE<_Record> **ppNextPointer;
|
||||
HASH_NODE<_Record> *pNewNextNode;
|
||||
DWORD nNewBuckets;
|
||||
|
||||
//
|
||||
// If number of items has become too many, we will double the hash table
|
||||
// size (we never reduce it however)
|
||||
//
|
||||
if (_nItems <= PRIME::GetPrime(2*_nBuckets))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
nNewBuckets = PRIME::GetPrime(2*_nBuckets);
|
||||
|
||||
if (_nItems <= nNewBuckets)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
nBuckets = nNewBuckets;
|
||||
if (nBuckets >= 0xffffffff/sizeof(HASH_NODE<_Record> *))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
ppBuckets = (HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(HASH_NODE<_Record> *));
|
||||
if (ppBuckets == NULL)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Take out nodes from the old hash table and insert in the new one, make
|
||||
// sure to keep the hashes in increasing order
|
||||
//
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
pNextNode = pNode->_pNext;
|
||||
|
||||
ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
|
||||
pNewNextNode = *ppNextPointer;
|
||||
while (pNewNextNode != NULL &&
|
||||
pNewNextNode->_dwHash <= pNode->_dwHash)
|
||||
{
|
||||
ppNextPointer = &pNewNextNode->_pNext;
|
||||
pNewNextNode = pNewNextNode->_pNext;
|
||||
}
|
||||
pNode->_pNext = pNewNextNode;
|
||||
*ppNextPointer = pNode;
|
||||
|
||||
pNode = pNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, _ppBuckets);
|
||||
_ppBuckets = ppBuckets;
|
||||
_nBuckets = nBuckets;
|
||||
ppBuckets = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
template<typename TYPE, SIZE_T SIZE>
|
||||
class HYBRID_ARRAY
|
||||
{
|
||||
public:
|
||||
|
||||
HYBRID_ARRAY(
|
||||
VOID
|
||||
) : m_pArray(m_InlineArray),
|
||||
m_Capacity(ARRAYSIZE(m_InlineArray))
|
||||
{
|
||||
}
|
||||
|
||||
~HYBRID_ARRAY()
|
||||
{
|
||||
if ( !QueryUsesInlineArray() )
|
||||
{
|
||||
delete [] m_pArray;
|
||||
m_pArray = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SIZE_T
|
||||
QueryCapacity(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Number of elements available in the array.
|
||||
//
|
||||
return m_Capacity;
|
||||
}
|
||||
|
||||
TYPE *
|
||||
QueryArray(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
//
|
||||
// Raw pointer to the current array.
|
||||
//
|
||||
return m_pArray;
|
||||
}
|
||||
|
||||
TYPE &
|
||||
QueryItem(
|
||||
__in const SIZE_T Index
|
||||
)
|
||||
{
|
||||
//
|
||||
// Gets the array item giving the index.
|
||||
//
|
||||
return m_pArray[Index];
|
||||
}
|
||||
|
||||
TYPE &
|
||||
operator [] (const SIZE_T Index)
|
||||
{
|
||||
//
|
||||
// Operator override for convenience.
|
||||
// Please don't add other overloads like '++' '--'
|
||||
// in order to keep it simple.
|
||||
//
|
||||
return m_pArray[Index];
|
||||
}
|
||||
|
||||
const TYPE &
|
||||
operator [] (const SIZE_T Index) const
|
||||
{
|
||||
return m_pArray[Index];
|
||||
}
|
||||
|
||||
template<SIZE_T SourceSize>
|
||||
HRESULT
|
||||
Copy(
|
||||
__in TYPE const (&SourceArray)[SourceSize],
|
||||
__in bool fHasTrivialAssign = false
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Copies a source array like:
|
||||
|
||||
int source[] = { 1, 2, 3 };
|
||||
hr = hybridArray.Copy( source );
|
||||
|
||||
It will statically determinate the length of the source array.
|
||||
|
||||
Arguments:
|
||||
|
||||
SourceArray - The array to copy.
|
||||
SourceSize - The number of array elements.
|
||||
fHasTrivialAssign - True if safe to perform buffer copy.
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
return Copy( SourceArray, SourceSize, fHasTrivialAssign );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in_ecount(SourceSize)
|
||||
const TYPE * pSourceArray,
|
||||
__in const SIZE_T SourceSize,
|
||||
__in bool fHasTrivialAssign = false
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Copies a source array.
|
||||
|
||||
Arguments:
|
||||
|
||||
pSourceArray - The array to copy.
|
||||
SourceSize - The number of array elements.
|
||||
fHasTrivialAssign - True if safe to perform buffer copy.
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = EnsureCapacity( SourceSize,
|
||||
FALSE, // fCopyPrevious
|
||||
FALSE ); // fHasTrivialAssign
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
if ( fHasTrivialAssign ) // Future Work: use std::tr1::has_trivial_assign
|
||||
{
|
||||
CopyMemory(m_pArray, pSourceArray, m_Capacity * sizeof(TYPE));
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( SIZE_T Index = 0; Index < SourceSize; ++Index )
|
||||
{
|
||||
m_pArray[Index] = pSourceArray[Index];
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
EnsureCapacity(
|
||||
__in const SIZE_T MinimumCapacity,
|
||||
__in bool fCopyPrevious,
|
||||
__in bool fHasTrivialAssign = false
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Copies a source array.
|
||||
|
||||
Arguments:
|
||||
|
||||
MinimumCapacity - The expected length of the array.
|
||||
fCopyPrevious - Must be always explicit parameter.
|
||||
True if copy previous array data.
|
||||
fHasTrivialAssign - True if safe to perform buffer copy.
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Caller is responsible for calculating a length that won't cause
|
||||
// too many reallocations in the future.
|
||||
//
|
||||
|
||||
if ( MinimumCapacity <= ARRAYSIZE(m_InlineArray) )
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
TYPE * pNewArray;
|
||||
|
||||
pNewArray = new TYPE[ MinimumCapacity ];
|
||||
if ( pNewArray == NULL )
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if ( fCopyPrevious )
|
||||
{
|
||||
if ( fHasTrivialAssign )
|
||||
{
|
||||
CopyMemory(pNewArray, m_pArray, m_Capacity * sizeof(TYPE));
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( SIZE_T Index = 0; Index < m_Capacity; ++Index )
|
||||
{
|
||||
pNewArray[Index] = m_pArray[Index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( QueryUsesInlineArray() )
|
||||
{
|
||||
m_pArray = pNewArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete [] m_pArray;
|
||||
m_pArray = pNewArray;
|
||||
}
|
||||
|
||||
m_Capacity = MinimumCapacity;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool
|
||||
QueryUsesInlineArray(
|
||||
VOID
|
||||
) const
|
||||
{
|
||||
return m_pArray == m_InlineArray;
|
||||
}
|
||||
|
||||
TYPE m_InlineArray[SIZE];
|
||||
TYPE * m_pArray;
|
||||
SIZE_T m_Capacity;
|
||||
};
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _LIST_ENTRY_H
|
||||
#define _LIST_ENTRY_H
|
||||
|
||||
//
|
||||
// Doubly-linked list manipulation routines.
|
||||
//
|
||||
|
||||
|
||||
#define InitializeListHead32(ListHead) (\
|
||||
(ListHead)->Flink = (ListHead)->Blink = PtrToUlong((ListHead)))
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InitializeListHead(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
ListHead->Flink = ListHead->Blink = ListHead;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
IsListEmpty(
|
||||
IN const LIST_ENTRY * ListHead
|
||||
)
|
||||
{
|
||||
return (BOOLEAN)(ListHead->Flink == ListHead);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
RemoveEntryList(
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
PLIST_ENTRY Flink;
|
||||
|
||||
Flink = Entry->Flink;
|
||||
Blink = Entry->Blink;
|
||||
Blink->Flink = Flink;
|
||||
Flink->Blink = Blink;
|
||||
return (BOOLEAN)(Flink == Blink);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
PLIST_ENTRY
|
||||
RemoveHeadList(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Flink;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
Entry = ListHead->Flink;
|
||||
Flink = Entry->Flink;
|
||||
ListHead->Flink = Flink;
|
||||
Flink->Blink = ListHead;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
PLIST_ENTRY
|
||||
RemoveTailList(
|
||||
IN PLIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
Entry = ListHead->Blink;
|
||||
Blink = Entry->Blink;
|
||||
ListHead->Blink = Blink;
|
||||
Blink->Flink = ListHead;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InsertTailList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Blink;
|
||||
|
||||
Blink = ListHead->Blink;
|
||||
Entry->Flink = ListHead;
|
||||
Entry->Blink = Blink;
|
||||
Blink->Flink = Entry;
|
||||
ListHead->Blink = Entry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InsertHeadList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY Flink;
|
||||
|
||||
Flink = ListHead->Flink;
|
||||
Entry->Flink = Flink;
|
||||
Entry->Blink = ListHead;
|
||||
Flink->Blink = Entry;
|
||||
ListHead->Flink = Entry;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
AppendTailList(
|
||||
IN PLIST_ENTRY ListHead,
|
||||
IN PLIST_ENTRY ListToAppend
|
||||
)
|
||||
{
|
||||
PLIST_ENTRY ListEnd = ListHead->Blink;
|
||||
|
||||
ListHead->Blink->Flink = ListToAppend;
|
||||
ListHead->Blink = ListToAppend->Blink;
|
||||
ListToAppend->Blink->Flink = ListHead;
|
||||
ListToAppend->Blink = ListEnd;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
PSINGLE_LIST_ENTRY
|
||||
PopEntryList(
|
||||
PSINGLE_LIST_ENTRY ListHead
|
||||
)
|
||||
{
|
||||
PSINGLE_LIST_ENTRY FirstEntry;
|
||||
FirstEntry = ListHead->Next;
|
||||
if (FirstEntry != NULL) {
|
||||
ListHead->Next = FirstEntry->Next;
|
||||
}
|
||||
|
||||
return FirstEntry;
|
||||
}
|
||||
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
PushEntryList(
|
||||
PSINGLE_LIST_ENTRY ListHead,
|
||||
PSINGLE_LIST_ENTRY Entry
|
||||
)
|
||||
{
|
||||
Entry->Next = ListHead->Next;
|
||||
ListHead->Next = Entry;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _MACROS_H
|
||||
#define _MACROS_H
|
||||
|
||||
//
|
||||
// The DIFF macro should be used around an expression involving pointer
|
||||
// subtraction. The expression passed to DIFF is cast to a size_t type,
|
||||
// allowing the result to be easily assigned to any 32-bit variable or
|
||||
// passed to a function expecting a 32-bit argument.
|
||||
//
|
||||
|
||||
#define DIFF(x) ((size_t)(x))
|
||||
|
||||
// Change a hexadecimal digit to its numerical equivalent
|
||||
#define TOHEX( ch ) \
|
||||
((ch) > L'9' ? \
|
||||
(ch) >= L'a' ? \
|
||||
(ch) - L'a' + 10 : \
|
||||
(ch) - L'A' + 10 \
|
||||
: (ch) - L'0')
|
||||
|
||||
|
||||
// Change a number to its Hexadecimal equivalent
|
||||
|
||||
#define TODIGIT( nDigit ) \
|
||||
(CHAR)((nDigit) > 9 ? \
|
||||
(nDigit) - 10 + 'A' \
|
||||
: (nDigit) + '0')
|
||||
|
||||
|
||||
inline int
|
||||
SAFEIsSpace(UCHAR c)
|
||||
{
|
||||
return isspace( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsAlNum(UCHAR c)
|
||||
{
|
||||
return isalnum( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsAlpha(UCHAR c)
|
||||
{
|
||||
return isalpha( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsXDigit(UCHAR c)
|
||||
{
|
||||
return isxdigit( c );
|
||||
}
|
||||
|
||||
inline int
|
||||
SAFEIsDigit(UCHAR c)
|
||||
{
|
||||
return isdigit( c );
|
||||
}
|
||||
|
||||
#endif // _MACROS_H
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _MULTISZ_HXX_
|
||||
#define _MULTISZ_HXX_
|
||||
|
||||
# include <stringu.h>
|
||||
|
||||
|
||||
/*++
|
||||
class MULTISZ:
|
||||
|
||||
Intention:
|
||||
A light-weight multi-string class supporting encapsulated string class.
|
||||
|
||||
This object is derived from BUFFER class.
|
||||
It maintains following state:
|
||||
|
||||
m_fValid - whether this object is valid -
|
||||
used only by MULTISZ() init functions
|
||||
* NYI: I need to kill this someday *
|
||||
m_cchLen - string length cached when we update the string.
|
||||
m_cStrings - number of strings.
|
||||
|
||||
Member Functions:
|
||||
There are two categories of functions:
|
||||
1) Safe Functions - which do integrity checking of state
|
||||
2) UnSafe Functions - which do not do integrity checking, but
|
||||
enable writing to the data stream freely.
|
||||
(someday this will be enabled as Safe versions without
|
||||
problem for users)
|
||||
|
||||
--*/
|
||||
class MULTISZ : public BUFFER
|
||||
{
|
||||
public:
|
||||
|
||||
MULTISZ()
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ Reset(); }
|
||||
|
||||
// creates a stack version of the MULTISZ object - uses passed in stack buffer
|
||||
// MULTISZ does not free this pbInit on its own.
|
||||
MULTISZ( __in_bcount(cbInit) WCHAR * pbInit, DWORD cbInit)
|
||||
: BUFFER( (BYTE *) pbInit, cbInit),
|
||||
m_cchLen (0),
|
||||
m_cStrings(0)
|
||||
{}
|
||||
|
||||
MULTISZ( const WCHAR * pchInit )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit(pchInit); }
|
||||
|
||||
MULTISZ( const MULTISZ & str )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit( str.QueryStr()); }
|
||||
|
||||
// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
|
||||
//
|
||||
// Checks and returns TRUE if this string has no valid data else FALSE
|
||||
//
|
||||
BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); }
|
||||
|
||||
BOOL Append( const WCHAR * pchInit ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
(DWORD) (::wcslen(pchInit)) * sizeof(WCHAR)
|
||||
)) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
|
||||
BOOL Append( const WCHAR * pchInit, DWORD cchLen ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
cchLen * sizeof(WCHAR))) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Append( STRU & str )
|
||||
{ return AuxAppend( str.QueryStr(),
|
||||
(str.QueryCCH()) * sizeof(WCHAR)); }
|
||||
|
||||
// Resets the internal string to be NULL string. Buffer remains cached.
|
||||
VOID Reset( VOID)
|
||||
{ DBG_ASSERT( QueryPtr() != NULL);
|
||||
QueryStr()[0] = L'\0';
|
||||
QueryStr()[1] = L'\0';
|
||||
m_cchLen = 2;
|
||||
m_cStrings = 0;
|
||||
}
|
||||
|
||||
BOOL Copy( const WCHAR * pchInit, IN DWORD cbLen ) {
|
||||
if ( QueryPtr() ) { Reset(); }
|
||||
return ( (pchInit != NULL) ?
|
||||
AuxAppend( pchInit, cbLen, FALSE ):
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Copy( const MULTISZ & str )
|
||||
{ return ( Copy(str.QueryStr(), str.QueryCB())); }
|
||||
|
||||
//
|
||||
// Returns the number of bytes in the string including the terminating
|
||||
// NULLs
|
||||
//
|
||||
UINT QueryCB( VOID ) const
|
||||
{ return ( m_cchLen * sizeof(WCHAR)); }
|
||||
|
||||
//
|
||||
// Returns # of characters in the string including the terminating NULLs
|
||||
//
|
||||
UINT QueryCCH( VOID ) const { return (m_cchLen); }
|
||||
|
||||
//
|
||||
// Returns # of strings in the multisz.
|
||||
//
|
||||
|
||||
DWORD QueryStringCount( VOID ) const { return m_cStrings; }
|
||||
|
||||
//
|
||||
// Makes a copy of the stored string in given buffer
|
||||
//
|
||||
BOOL CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const;
|
||||
|
||||
//
|
||||
// Return the string buffer
|
||||
//
|
||||
WCHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
|
||||
WCHAR * QueryStr( VOID ) const { return ((WCHAR *) QueryPtr()); }
|
||||
|
||||
//
|
||||
// Makes a clone of the current string in the string pointer passed in.
|
||||
//
|
||||
BOOL
|
||||
Clone( OUT MULTISZ * pstrClone) const
|
||||
{
|
||||
return ((pstrClone == NULL) ?
|
||||
(SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
|
||||
(pstrClone->Copy( *this))
|
||||
);
|
||||
} // MULTISZ::Clone()
|
||||
|
||||
//
|
||||
// Recalculates the length of *this because we've modified the buffers
|
||||
// directly
|
||||
//
|
||||
|
||||
VOID RecalcLen( VOID )
|
||||
{ m_cchLen = MULTISZ::CalcLength( QueryStr(), &m_cStrings ); }
|
||||
|
||||
//
|
||||
// Calculate total character length of a MULTI_SZ, including the
|
||||
// terminating NULLs.
|
||||
//
|
||||
|
||||
static DWORD CalcLength( const WCHAR * str,
|
||||
LPDWORD pcStrings = NULL );
|
||||
|
||||
//
|
||||
// Determine if the MULTISZ contains a specific string.
|
||||
//
|
||||
|
||||
BOOL FindString( const WCHAR * str );
|
||||
|
||||
BOOL FindString( STRU & str )
|
||||
{ return FindString( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Determine if the MULTISZ contains a specific string - case-insensitive
|
||||
//
|
||||
|
||||
BOOL FindStringNoCase( const WCHAR * str );
|
||||
|
||||
BOOL FindStringNoCase( STRU & str )
|
||||
{ return FindStringNoCase( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Used for scanning a multisz.
|
||||
//
|
||||
|
||||
const WCHAR * First( VOID ) const
|
||||
{ return *QueryStr() == L'\0' ? NULL : QueryStr(); }
|
||||
|
||||
const WCHAR * Next( const WCHAR * Current ) const
|
||||
{ Current += ::wcslen( Current ) + 1;
|
||||
return *Current == L'\0' ? NULL : Current; }
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
MULTISZ* pmszRhs
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
DWORD m_cchLen;
|
||||
DWORD m_cStrings;
|
||||
VOID AuxInit( const WCHAR * pInit );
|
||||
BOOL AuxAppend( const WCHAR * pInit,
|
||||
UINT cbStr, BOOL fAddSlop = TRUE );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Quick macro for declaring a MULTISZ that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated
|
||||
//
|
||||
|
||||
#define STACK_MULTISZ( name, size ) WCHAR __ach##name[size]; \
|
||||
MULTISZ name( __ach##name, sizeof( __ach##name ))
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCWSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZ * pmszList
|
||||
);
|
||||
|
||||
#endif // !_MULTISZ_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _MULTISZA_HXX_
|
||||
#define _MULTISZA_HXX_
|
||||
|
||||
# include <stringa.h>
|
||||
|
||||
|
||||
/*++
|
||||
class MULTISZ:
|
||||
|
||||
Intention:
|
||||
A light-weight multi-string class supporting encapsulated string class.
|
||||
|
||||
This object is derived from BUFFER class.
|
||||
It maintains following state:
|
||||
|
||||
m_fValid - whether this object is valid -
|
||||
used only by MULTISZ() init functions
|
||||
* NYI: I need to kill this someday *
|
||||
m_cchLen - string length cached when we update the string.
|
||||
m_cStrings - number of strings.
|
||||
|
||||
Member Functions:
|
||||
There are two categories of functions:
|
||||
1) Safe Functions - which do integrity checking of state
|
||||
2) UnSafe Functions - which do not do integrity checking, but
|
||||
enable writing to the data stream freely.
|
||||
(someday this will be enabled as Safe versions without
|
||||
problem for users)
|
||||
|
||||
--*/
|
||||
class MULTISZA : public BUFFER
|
||||
{
|
||||
public:
|
||||
|
||||
MULTISZA()
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ Reset(); }
|
||||
|
||||
// creates a stack version of the MULTISZA object - uses passed in stack buffer
|
||||
// MULTISZA does not free this pbInit on its own.
|
||||
MULTISZA( __in_bcount(cbInit) CHAR * pbInit, DWORD cbInit)
|
||||
: BUFFER( (BYTE *) pbInit, cbInit),
|
||||
m_cchLen (0),
|
||||
m_cStrings(0)
|
||||
{}
|
||||
|
||||
MULTISZA( const CHAR * pchInit )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit(pchInit); }
|
||||
|
||||
MULTISZA( const MULTISZA & str )
|
||||
: BUFFER (),
|
||||
m_cchLen ( 0),
|
||||
m_cStrings(0)
|
||||
{ AuxInit( str.QueryStr()); }
|
||||
|
||||
// BOOL IsValid(VOID) const { return ( BUFFER::IsValid()) ; }
|
||||
//
|
||||
// Checks and returns TRUE if this string has no valid data else FALSE
|
||||
//
|
||||
BOOL IsEmpty( VOID) const { return ( *QueryStr() == L'\0'); }
|
||||
|
||||
BOOL Append( const CHAR * pchInit ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
(DWORD) (::strlen(pchInit)) * sizeof(CHAR)
|
||||
)) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
|
||||
BOOL Append( const CHAR * pchInit, DWORD cchLen ) {
|
||||
return ((pchInit != NULL) ? (AuxAppend( pchInit,
|
||||
cchLen * sizeof(CHAR))) :
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Append( STRA & str )
|
||||
{ return AuxAppend( str.QueryStr(),
|
||||
(str.QueryCCH()) * sizeof(CHAR)); }
|
||||
|
||||
// Resets the internal string to be NULL string. Buffer remains cached.
|
||||
VOID Reset( VOID)
|
||||
{ DBG_ASSERT( QueryPtr() != NULL);
|
||||
QueryStr()[0] = L'\0';
|
||||
QueryStr()[1] = L'\0';
|
||||
m_cchLen = 2;
|
||||
m_cStrings = 0;
|
||||
}
|
||||
|
||||
BOOL Copy( const CHAR * pchInit, IN DWORD cbLen ) {
|
||||
if ( QueryPtr() ) { Reset(); }
|
||||
return ( (pchInit != NULL) ?
|
||||
AuxAppend( pchInit, cbLen, FALSE ):
|
||||
TRUE);
|
||||
}
|
||||
|
||||
BOOL Copy( const MULTISZA & str )
|
||||
{ return ( Copy(str.QueryStr(), str.QueryCB())); }
|
||||
|
||||
//
|
||||
// Returns the number of bytes in the string including the terminating
|
||||
// NULLs
|
||||
//
|
||||
UINT QueryCB( VOID ) const
|
||||
{ return ( m_cchLen * sizeof(CHAR)); }
|
||||
|
||||
//
|
||||
// Returns # of characters in the string including the terminating NULLs
|
||||
//
|
||||
UINT QueryCCH( VOID ) const { return (m_cchLen); }
|
||||
|
||||
//
|
||||
// Returns # of strings in the MULTISZA.
|
||||
//
|
||||
|
||||
DWORD QueryStringCount( VOID ) const { return m_cStrings; }
|
||||
|
||||
//
|
||||
// Makes a copy of the stored string in given buffer
|
||||
//
|
||||
BOOL CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const;
|
||||
|
||||
//
|
||||
// Return the string buffer
|
||||
//
|
||||
CHAR * QueryStrA( VOID ) const { return ( QueryStr()); }
|
||||
CHAR * QueryStr( VOID ) const { return ((CHAR *) QueryPtr()); }
|
||||
|
||||
//
|
||||
// Makes a clone of the current string in the string pointer passed in.
|
||||
//
|
||||
BOOL
|
||||
Clone( OUT MULTISZA * pstrClone) const
|
||||
{
|
||||
return ((pstrClone == NULL) ?
|
||||
(SetLastError(ERROR_INVALID_PARAMETER), FALSE) :
|
||||
(pstrClone->Copy( *this))
|
||||
);
|
||||
} // MULTISZA::Clone()
|
||||
|
||||
//
|
||||
// Recalculates the length of *this because we've modified the buffers
|
||||
// directly
|
||||
//
|
||||
|
||||
VOID RecalcLen( VOID )
|
||||
{ m_cchLen = MULTISZA::CalcLength( QueryStr(), &m_cStrings ); }
|
||||
|
||||
//
|
||||
// Calculate total character length of a MULTI_SZ, including the
|
||||
// terminating NULLs.
|
||||
//
|
||||
|
||||
static DWORD CalcLength( const CHAR * str,
|
||||
LPDWORD pcStrings = NULL );
|
||||
|
||||
//
|
||||
// Determine if the MULTISZA contains a specific string.
|
||||
//
|
||||
|
||||
BOOL FindString( const CHAR * str );
|
||||
|
||||
BOOL FindString( STRA & str )
|
||||
{ return FindString( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Determine if the MULTISZA contains a specific string - case-insensitive
|
||||
//
|
||||
|
||||
BOOL FindStringNoCase( const CHAR * str );
|
||||
|
||||
BOOL FindStringNoCase( STRA & str )
|
||||
{ return FindStringNoCase( str.QueryStr() ); }
|
||||
|
||||
//
|
||||
// Used for scanning a MULTISZA.
|
||||
//
|
||||
|
||||
const CHAR * First( VOID ) const
|
||||
{ return *QueryStr() == L'\0' ? NULL : QueryStr(); }
|
||||
|
||||
const CHAR * Next( const CHAR * Current ) const
|
||||
{ Current += ::strlen( Current ) + 1;
|
||||
return *Current == L'\0' ? NULL : Current; }
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
MULTISZA* pmszRhs
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
DWORD m_cchLen;
|
||||
DWORD m_cStrings;
|
||||
VOID AuxInit( const CHAR * pInit );
|
||||
BOOL AuxAppend( const CHAR * pInit,
|
||||
UINT cbStr, BOOL fAddSlop = TRUE );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Quick macro for declaring a MULTISZA that will use stack memory of <size>
|
||||
// bytes. If the buffer overflows then a heap buffer will be allocated
|
||||
//
|
||||
|
||||
#define STACK_MULTISZA( name, size ) CHAR __ach##name[size]; \
|
||||
MULTISZA name( __ach##name, sizeof( __ach##name ))
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZA * pmszList
|
||||
);
|
||||
|
||||
#endif // !_MULTISZA_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef __NORMALIZE_URL__H__
|
||||
#define __NORMALIZE_URL__H__
|
||||
|
||||
HRESULT
|
||||
NormalizeUrl(
|
||||
__inout LPSTR pszUrl
|
||||
);
|
||||
|
||||
|
||||
HRESULT
|
||||
NormalizeUrlW(
|
||||
__inout LPWSTR pszUrl
|
||||
);
|
||||
|
||||
|
||||
|
||||
HRESULT
|
||||
UlCleanAndCopyUrl(
|
||||
__in LPSTR pSource,
|
||||
IN ULONG SourceLength,
|
||||
OUT PULONG pBytesCopied,
|
||||
__inout PWSTR pDestination,
|
||||
__deref_opt_out_opt PWSTR * ppQueryString OPTIONAL
|
||||
);
|
||||
|
||||
HRESULT
|
||||
UlInitializeParsing(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
InitializeNormalizeUrl(
|
||||
VOID
|
||||
);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _ASSERTE
|
||||
#undef _ASSERTE
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
#undef ASSERT
|
||||
#endif
|
||||
|
||||
#if defined( DBG ) && DBG
|
||||
#define SX_ASSERT( _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L#_x ), DbgRaiseAssertionFailure(), FALSE ) ) )
|
||||
#define SX_ASSERTMSG( _m, _x ) ( (VOID)( ( ( _x ) ) ? TRUE : ( __annotation( L"Debug", L"AssertFail", L##_m ), DbgRaiseAssertionFailure(), FALSE ) ) )
|
||||
#define SX_VERIFY( _x ) SX_ASSERT( _x )
|
||||
#define _ASSERTE( _x ) SX_ASSERT( _x )
|
||||
#define ASSERT( _x ) SX_ASSERT( _x )
|
||||
#define assert( _x ) SX_ASSERT( _x )
|
||||
#define DBG_ASSERT( _x ) SX_ASSERT( _x )
|
||||
#define DBG_REQUIRE( _x ) SX_ASSERT( _x )
|
||||
#else
|
||||
#define SX_ASSERT( _x ) ( (VOID)0 )
|
||||
#define SX_ASSERTMSG( _m, _x ) ( (VOID)0 )
|
||||
#define SX_VERIFY( _x ) ( (VOID)( ( _x ) ? TRUE : FALSE ) )
|
||||
#define _ASSERTE( _x ) ( (VOID)0 )
|
||||
#define assert( _x ) ( (VOID)0 )
|
||||
#define DBG_ASSERT( _x ) ( (VOID)0 )
|
||||
#define DBG_REQUIRE( _x ) ((VOID)(_x))
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
template<typename T>
|
||||
class PER_CPU
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
static
|
||||
HRESULT
|
||||
Create(
|
||||
FunctionInitializer Initializer,
|
||||
__deref_out PER_CPU<T> ** ppInstance
|
||||
);
|
||||
|
||||
inline
|
||||
T *
|
||||
GetLocal(
|
||||
VOID
|
||||
);
|
||||
|
||||
template<typename FunctionForEach>
|
||||
inline
|
||||
VOID
|
||||
ForEach(
|
||||
FunctionForEach Function
|
||||
);
|
||||
|
||||
inline
|
||||
VOID
|
||||
Dispose(
|
||||
VOID
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
PER_CPU(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Don't perform any operation during constructor.
|
||||
// Constructor will never be called.
|
||||
//
|
||||
}
|
||||
|
||||
~PER_CPU(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Don't perform any operation during destructor.
|
||||
// Constructor will never be called.
|
||||
//
|
||||
}
|
||||
|
||||
template<typename FunctionInitializer>
|
||||
HRESULT
|
||||
Initialize(
|
||||
FunctionInitializer Initializer,
|
||||
DWORD NumberOfVariables,
|
||||
DWORD Alignment
|
||||
);
|
||||
|
||||
T *
|
||||
GetObject(
|
||||
DWORD Index
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
GetProcessorInformation(
|
||||
__out DWORD * pCacheLineSize,
|
||||
__out DWORD * pNumberOfProcessors
|
||||
);
|
||||
|
||||
//
|
||||
// Pointer to the begining of the inlined array.
|
||||
//
|
||||
PVOID m_pVariables;
|
||||
SIZE_T m_Alignment;
|
||||
SIZE_T m_VariablesCount;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
// static
|
||||
HRESULT
|
||||
PER_CPU<T>::Create(
|
||||
FunctionInitializer Initializer,
|
||||
__deref_out PER_CPU<T> ** ppInstance
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD CacheLineSize = 0;
|
||||
DWORD ObjectCacheLineSize = 0;
|
||||
DWORD NumberOfProcessors = 0;
|
||||
PER_CPU<T> * pInstance = NULL;
|
||||
|
||||
hr = GetProcessorInformation(&CacheLineSize,
|
||||
&NumberOfProcessors);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (sizeof(T) > CacheLineSize)
|
||||
{
|
||||
//
|
||||
// Round to the next multiple of the cache line size.
|
||||
//
|
||||
ObjectCacheLineSize = (sizeof(T) + CacheLineSize-1) & (CacheLineSize-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectCacheLineSize = CacheLineSize;
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the size of the PER_CPU<T> object, including the array.
|
||||
// The first cache line is for the member variables and the array
|
||||
// starts in the next cache line.
|
||||
//
|
||||
SIZE_T Size = CacheLineSize + NumberOfProcessors * ObjectCacheLineSize;
|
||||
|
||||
pInstance = (PER_CPU<T>*) _aligned_malloc(Size, CacheLineSize);
|
||||
if (pInstance == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
ZeroMemory(pInstance, Size);
|
||||
|
||||
//
|
||||
// The array start in the 2nd cache line.
|
||||
//
|
||||
pInstance->m_pVariables = reinterpret_cast<PBYTE>(pInstance) + CacheLineSize;
|
||||
|
||||
//
|
||||
// Pass a disposer for disposing initialized items in case of failure.
|
||||
//
|
||||
hr = pInstance->Initialize(Initializer,
|
||||
NumberOfProcessors,
|
||||
ObjectCacheLineSize);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*ppInstance = pInstance;
|
||||
pInstance = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
if (pInstance != NULL)
|
||||
{
|
||||
//
|
||||
// Free the instance without disposing it.
|
||||
//
|
||||
pInstance->Dispose();
|
||||
pInstance = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
T *
|
||||
PER_CPU<T>::GetLocal(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Use GetCurrentProcessorNumber (up to 64 logical processors) instead of
|
||||
// GetCurrentProcessorNumberEx (more than 64 logical processors) because
|
||||
// the number of processors are not densely packed per group.
|
||||
// The idea of distributing variables per CPU is to have
|
||||
// a scalability multiplier (could be NUMA node instead).
|
||||
//
|
||||
// Make sure the index don't go beyond the array size, if that happens,
|
||||
// there won't be even distribution, but still better
|
||||
// than one single variable.
|
||||
//
|
||||
return GetObject(GetCurrentProcessorNumber());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
T *
|
||||
PER_CPU<T>::GetObject(
|
||||
DWORD Index
|
||||
)
|
||||
{
|
||||
return reinterpret_cast<T*>(static_cast<PBYTE>(m_pVariables) + Index * m_Alignment);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionForEach>
|
||||
inline
|
||||
VOID
|
||||
PER_CPU<T>::ForEach(
|
||||
FunctionForEach Function
|
||||
)
|
||||
{
|
||||
for(DWORD Index = 0; Index < m_VariablesCount; ++Index)
|
||||
{
|
||||
T * pObject = GetObject(Index);
|
||||
Function(pObject);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
VOID
|
||||
PER_CPU<T>::Dispose(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
_aligned_free(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FunctionInitializer>
|
||||
inline
|
||||
HRESULT
|
||||
PER_CPU<T>::Initialize(
|
||||
FunctionInitializer Initializer,
|
||||
DWORD NumberOfVariables,
|
||||
DWORD Alignment
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initialize each object using the initializer function.
|
||||
If initialization for any object fails, it dispose the
|
||||
objects that were successfully initialized.
|
||||
|
||||
Arguments:
|
||||
|
||||
Initializer - Function for initialize one object.
|
||||
Signature: HRESULT Func(T*)
|
||||
Dispose - Function for disposing initialized objects in case of failure.
|
||||
Signature: void Func(T*)
|
||||
NumberOfVariables - The length of the array of variables.
|
||||
Alignment - Alignment to use for avoiding false sharing.
|
||||
|
||||
Return:
|
||||
|
||||
HRESULT - E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
DWORD Index = 0;
|
||||
|
||||
m_VariablesCount = NumberOfVariables;
|
||||
m_Alignment = Alignment;
|
||||
|
||||
for (; Index < m_VariablesCount; ++Index)
|
||||
{
|
||||
T * pObject = GetObject(Index);
|
||||
Initializer(pObject);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
// static
|
||||
HRESULT
|
||||
PER_CPU<T>::GetProcessorInformation(
|
||||
__out DWORD * pCacheLineSize,
|
||||
__out DWORD * pNumberOfProcessors
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Gets the CPU cache-line size for the current system.
|
||||
This information is used for avoiding CPU false sharing.
|
||||
|
||||
Arguments:
|
||||
|
||||
pCacheLineSize - The processor cache-line size.
|
||||
pNumberOfProcessors - Maximum number of processors per group.
|
||||
|
||||
Return:
|
||||
|
||||
HRESULT - E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
SYSTEM_INFO SystemInfo = { };
|
||||
|
||||
GetSystemInfo(&SystemInfo);
|
||||
*pNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
|
||||
*pCacheLineSize = SYSTEM_CACHE_ALIGNMENT_SIZE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//
|
||||
// Pre-calculated prime numbers (up to 10,049,369).
|
||||
//
|
||||
extern __declspec(selectany) const DWORD g_Primes [] = {
|
||||
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631,
|
||||
761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103,
|
||||
12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631,
|
||||
130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
|
||||
968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
|
||||
5999471, 7199369, 7849369, 8649369, 9249369, 10049369
|
||||
};
|
||||
|
||||
class PRIME
|
||||
{
|
||||
public:
|
||||
|
||||
static
|
||||
DWORD
|
||||
GetPrime(
|
||||
DWORD dwMinimum
|
||||
)
|
||||
{
|
||||
//
|
||||
// Try to use the precalculated numbers.
|
||||
//
|
||||
for ( DWORD Index = 0; Index < _countof( g_Primes ); Index++ )
|
||||
{
|
||||
DWORD dwCandidate = g_Primes[Index];
|
||||
if ( dwCandidate >= dwMinimum )
|
||||
{
|
||||
return dwCandidate;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do calculation.
|
||||
//
|
||||
for ( DWORD dwCandidate = dwMinimum | 1;
|
||||
dwCandidate < MAXDWORD;
|
||||
dwCandidate += 2 )
|
||||
{
|
||||
if ( IsPrime( dwCandidate ) )
|
||||
{
|
||||
return dwCandidate;
|
||||
}
|
||||
}
|
||||
return dwMinimum;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static
|
||||
BOOL
|
||||
IsPrime(
|
||||
DWORD dwCandidate
|
||||
)
|
||||
{
|
||||
if ((dwCandidate & 1) == 0)
|
||||
{
|
||||
return ( dwCandidate == 2 );
|
||||
}
|
||||
|
||||
DWORD dwMax = static_cast<DWORD>(sqrt(static_cast<double>(dwCandidate)));
|
||||
|
||||
for ( DWORD Index = 3; Index <= dwMax; Index += 2 )
|
||||
{
|
||||
if ( (dwCandidate % Index) == 0 )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PRIME() {}
|
||||
~PRIME() {}
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _REFTRACE_H_
|
||||
#define _REFTRACE_H_
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#include <tracelog.h>
|
||||
|
||||
|
||||
//
|
||||
// This is the number of stack backtrace values captured in each
|
||||
// trace log entry. This value is chosen to make the log entry
|
||||
// exactly twelve dwords long, making it a bit easier to interpret
|
||||
// from within the debugger without the debugger extension.
|
||||
//
|
||||
|
||||
#define REF_TRACE_LOG_STACK_DEPTH 9
|
||||
|
||||
// No-op value for the Context1,2,3 parameters of WriteRefTraceLogEx
|
||||
//#define REF_TRACE_EMPTY_CONTEXT ((PVOID) -1)
|
||||
#define REF_TRACE_EMPTY_CONTEXT NULL
|
||||
|
||||
|
||||
//
|
||||
// This defines the entry written to the trace log.
|
||||
//
|
||||
|
||||
typedef struct _REF_TRACE_LOG_ENTRY {
|
||||
|
||||
LONG NewRefCount;
|
||||
CONST VOID * Context;
|
||||
CONST VOID * Context1;
|
||||
CONST VOID * Context2;
|
||||
CONST VOID * Context3;
|
||||
DWORD Thread;
|
||||
PVOID Stack[REF_TRACE_LOG_STACK_DEPTH];
|
||||
|
||||
} REF_TRACE_LOG_ENTRY, *PREF_TRACE_LOG_ENTRY;
|
||||
|
||||
|
||||
//
|
||||
// Manipulators.
|
||||
//
|
||||
|
||||
PTRACE_LOG
|
||||
CreateRefTraceLog(
|
||||
IN LONG LogSize,
|
||||
IN LONG ExtraBytesInHeader
|
||||
);
|
||||
|
||||
VOID
|
||||
DestroyRefTraceLog(
|
||||
IN PTRACE_LOG Log
|
||||
);
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLog(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context
|
||||
);
|
||||
|
||||
LONG
|
||||
__cdecl
|
||||
WriteRefTraceLogEx(
|
||||
IN PTRACE_LOG Log,
|
||||
IN LONG NewRefCount,
|
||||
IN CONST VOID * Context,
|
||||
IN CONST VOID * Context1,
|
||||
IN CONST VOID * Context2,
|
||||
IN CONST VOID * Context3
|
||||
);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif // _REFTRACE_H_
|
||||
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (_WIN32_WINNT < 0x600)
|
||||
|
||||
//
|
||||
// XP implementation.
|
||||
//
|
||||
class CWSDRWLock
|
||||
{
|
||||
public:
|
||||
|
||||
CWSDRWLock()
|
||||
: m_bInited(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
~CWSDRWLock()
|
||||
{
|
||||
if (m_bInited)
|
||||
{
|
||||
DeleteCriticalSection(&m_rwLock.critsec);
|
||||
CloseHandle(m_rwLock.ReadersDoneEvent);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL QueryInited() const
|
||||
{
|
||||
return m_bInited;
|
||||
}
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (FALSE == m_bInited)
|
||||
{
|
||||
m_rwLock.fWriterWaiting = FALSE;
|
||||
m_rwLock.LockCount = 0;
|
||||
if ( !InitializeCriticalSectionAndSpinCount( &m_rwLock.critsec, 0 ))
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_rwLock.ReadersDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if( NULL == m_rwLock.ReadersDoneEvent )
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(dwError);
|
||||
DeleteCriticalSection(&m_rwLock.critsec);
|
||||
return hr;
|
||||
}
|
||||
m_bInited = TRUE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void SharedAcquire()
|
||||
{
|
||||
EnterCriticalSection(&m_rwLock.critsec);
|
||||
InterlockedIncrement(&m_rwLock.LockCount);
|
||||
LeaveCriticalSection(&m_rwLock.critsec);
|
||||
}
|
||||
|
||||
void SharedRelease()
|
||||
{
|
||||
ReleaseRWLock();
|
||||
}
|
||||
|
||||
void ExclusiveAcquire()
|
||||
{
|
||||
EnterCriticalSection( &m_rwLock.critsec );
|
||||
|
||||
m_rwLock.fWriterWaiting = TRUE;
|
||||
|
||||
// check if there are any readers active
|
||||
if ( InterlockedExchangeAdd( &m_rwLock.LockCount, 0 ) > 0 )
|
||||
{
|
||||
//
|
||||
// Wait for all the readers to get done..
|
||||
//
|
||||
WaitForSingleObject( m_rwLock.ReadersDoneEvent, INFINITE );
|
||||
}
|
||||
m_rwLock.LockCount = -1;
|
||||
}
|
||||
|
||||
void ExclusiveRelease()
|
||||
{
|
||||
ReleaseRWLock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_bInited;
|
||||
|
||||
typedef struct _RW_LOCK
|
||||
{
|
||||
BOOL fWriterWaiting; // Is a writer waiting on the lock?
|
||||
LONG LockCount;
|
||||
CRITICAL_SECTION critsec;
|
||||
HANDLE ReadersDoneEvent;
|
||||
} RW_LOCK, *PRW_LOCK;
|
||||
|
||||
RW_LOCK m_rwLock;
|
||||
|
||||
private:
|
||||
|
||||
void ReleaseRWLock()
|
||||
{
|
||||
LONG Count = InterlockedDecrement( &m_rwLock.LockCount );
|
||||
|
||||
if ( 0 <= Count )
|
||||
{
|
||||
// releasing a read lock
|
||||
if (( m_rwLock.fWriterWaiting ) && ( 0 == Count ))
|
||||
{
|
||||
SetEvent( m_rwLock.ReadersDoneEvent );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Releasing a write lock
|
||||
m_rwLock.LockCount = 0;
|
||||
m_rwLock.fWriterWaiting = FALSE;
|
||||
LeaveCriticalSection(&m_rwLock.critsec);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
//
|
||||
// Implementation for Windows Vista or greater.
|
||||
//
|
||||
class CWSDRWLock
|
||||
{
|
||||
public:
|
||||
|
||||
CWSDRWLock()
|
||||
{
|
||||
InitializeSRWLock(&m_rwLock);
|
||||
}
|
||||
|
||||
BOOL QueryInited()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT Init()
|
||||
{
|
||||
//
|
||||
// Method defined to keep compatibility with CWSDRWLock class for XP.
|
||||
//
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void SharedAcquire()
|
||||
{
|
||||
AcquireSRWLockShared(&m_rwLock);
|
||||
}
|
||||
|
||||
void SharedRelease()
|
||||
{
|
||||
ReleaseSRWLockShared(&m_rwLock);
|
||||
}
|
||||
|
||||
void ExclusiveAcquire()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_rwLock);
|
||||
}
|
||||
|
||||
void ExclusiveRelease()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_rwLock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
SRWLOCK m_rwLock;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Rename the lock class to a more clear name.
|
||||
//
|
||||
typedef CWSDRWLock READ_WRITE_LOCK;
|
||||
|
|
@ -0,0 +1,730 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef __STATIC_HASH__H_
|
||||
#define __STATIC_HASH__H_
|
||||
|
||||
#define STATIC_STRING_HASH_BUCKETS 131
|
||||
|
||||
//
|
||||
// SERVER_VARIABLE_HASH maps server variable string to routines to eval them
|
||||
//
|
||||
|
||||
struct STATIC_STRING_HASH_RECORD
|
||||
{
|
||||
CHAR * _pszName;
|
||||
STATIC_STRING_HASH_RECORD * _pNext;
|
||||
USHORT _cchName;
|
||||
};
|
||||
|
||||
struct STATIC_STRING_HASH_ITER
|
||||
{
|
||||
STATIC_STRING_HASH_RECORD *_pCursor;
|
||||
DWORD _dwBucket;
|
||||
BOOL _fRemove;
|
||||
};
|
||||
|
||||
class STATIC_STRING_HASH
|
||||
{
|
||||
public:
|
||||
|
||||
STATIC_STRING_HASH(
|
||||
BOOL fCaseSensitive = FALSE
|
||||
) : _fCaseSensitive( fCaseSensitive )
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
VOID
|
||||
Reset()
|
||||
{
|
||||
ZeroMemory( &_rgBuckets, sizeof( _rgBuckets ) );
|
||||
}
|
||||
|
||||
static
|
||||
PCSTR
|
||||
ExtractKey(
|
||||
__in const STATIC_STRING_HASH_RECORD * pRecord
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Get the key out of the record
|
||||
|
||||
Arguments:
|
||||
|
||||
record to fetch the key from
|
||||
|
||||
Return Value:
|
||||
|
||||
key
|
||||
|
||||
--*/
|
||||
{
|
||||
DBG_ASSERT( pRecord != NULL );
|
||||
return pRecord->_pszName;
|
||||
}
|
||||
|
||||
VOID
|
||||
InsertRecord(
|
||||
__in STATIC_STRING_HASH_RECORD * pRecord
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Insert record to hash table
|
||||
|
||||
Note: remember this is static hash table
|
||||
There is no synchronization on the table
|
||||
Exclusive acess must be assured by caller
|
||||
|
||||
Arguments:
|
||||
|
||||
record to fetch the key from
|
||||
|
||||
Return Value:
|
||||
|
||||
VOID
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD dwIndex;
|
||||
STATIC_STRING_HASH_RECORD* pCursor;
|
||||
|
||||
DBG_ASSERT( pRecord != NULL );
|
||||
DBG_ASSERT( pRecord->_pszName != NULL );
|
||||
|
||||
if(NULL == pRecord->_pszName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_fCaseSensitive)
|
||||
{
|
||||
dwIndex = HashString( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwIndex = HashStringNoCase( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
|
||||
pCursor = _rgBuckets[ dwIndex ];
|
||||
|
||||
pRecord->_pNext = pCursor;
|
||||
_rgBuckets[ dwIndex ] = pRecord;
|
||||
}
|
||||
|
||||
STATIC_STRING_HASH_RECORD *
|
||||
FindKey(
|
||||
__in PCSTR pszName,
|
||||
BOOL fRemove = FALSE
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Find key in the table (and remove it optionally)
|
||||
|
||||
Arguments:
|
||||
|
||||
key
|
||||
|
||||
Return Value:
|
||||
|
||||
record containing the key
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD dwIndex;
|
||||
STATIC_STRING_HASH_RECORD* pRecord;
|
||||
STATIC_STRING_HASH_RECORD* pLastRecord = NULL;
|
||||
|
||||
DBG_ASSERT( pszName != NULL );
|
||||
|
||||
if (_fCaseSensitive)
|
||||
{
|
||||
dwIndex = HashString( pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwIndex = HashStringNoCase( pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
if (_fCaseSensitive)
|
||||
{
|
||||
if ( strcmp( pszName, pRecord->_pszName ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( _stricmp( pszName, pRecord->_pszName ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pLastRecord = pRecord;
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
|
||||
if (fRemove &&
|
||||
pRecord != NULL)
|
||||
{
|
||||
if (pLastRecord != NULL)
|
||||
{
|
||||
pLastRecord->_pNext = pRecord->_pNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rgBuckets[dwIndex] = pRecord->_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
return pRecord;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CheckDistribution(
|
||||
IN DWORD dwConflictThreshold,
|
||||
IN BOOL fToDebugger
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Simple verification on conflicts within the table
|
||||
|
||||
Arguments:
|
||||
|
||||
dwConflictThreshold - max number of entries tolerated per bucket
|
||||
fToDebbuger - spew the entries exceeding threshold into debugger
|
||||
|
||||
Return Value:
|
||||
|
||||
FALSE it threshold was reached (means hash funcion may not be optimal)
|
||||
|
||||
--*/
|
||||
{
|
||||
BOOL fThresholdReached = FALSE;
|
||||
STATIC_STRING_HASH_RECORD* pRecord;
|
||||
for ( DWORD dwIndex = 0; dwIndex < STATIC_STRING_HASH_BUCKETS; dwIndex++)
|
||||
{
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
DWORD countInBucket = 0;
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
countInBucket++;
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
//
|
||||
// print out the list of multiple entries in bucket
|
||||
//
|
||||
if ( countInBucket > dwConflictThreshold && fToDebugger )
|
||||
{
|
||||
fThresholdReached = TRUE;
|
||||
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fThresholdReached;
|
||||
}
|
||||
|
||||
STATIC_STRING_HASH_RECORD *
|
||||
FindFirst(
|
||||
STATIC_STRING_HASH_ITER *pIterator,
|
||||
BOOL fRemove = FALSE
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begins a new hash item enumeration.
|
||||
|
||||
Arguments:
|
||||
|
||||
pIterator - Supplies the context for the enumeration.
|
||||
|
||||
fRemove - Supplies TRUE if the items should be removed
|
||||
from the hash as they are enumerated.
|
||||
|
||||
Return Value:
|
||||
|
||||
The first entry in the hash if successful, NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
pIterator->_dwBucket = 0;
|
||||
pIterator->_fRemove = fRemove;
|
||||
pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket);
|
||||
|
||||
if (pIterator->_fRemove && pIterator->_pCursor != NULL)
|
||||
{
|
||||
_rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
return pIterator->_pCursor;
|
||||
}
|
||||
|
||||
STATIC_STRING_HASH_RECORD *
|
||||
FindNext(
|
||||
STATIC_STRING_HASH_ITER *pIterator
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Continues a hash item enumeration.
|
||||
|
||||
Arguments:
|
||||
|
||||
pIterator - Supplies the context for the enumeration.
|
||||
|
||||
Return Value:
|
||||
|
||||
The next entry in the hash if successful, NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
if (pIterator->_pCursor != NULL)
|
||||
{
|
||||
if (pIterator->_fRemove)
|
||||
{
|
||||
pIterator->_pCursor = _rgBuckets[pIterator->_dwBucket];
|
||||
}
|
||||
else
|
||||
{
|
||||
pIterator->_pCursor = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
if (pIterator->_pCursor == NULL)
|
||||
{
|
||||
pIterator->_dwBucket++;
|
||||
pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket);
|
||||
}
|
||||
}
|
||||
|
||||
if (pIterator->_fRemove && pIterator->_pCursor != NULL)
|
||||
{
|
||||
_rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
return pIterator->_pCursor;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
STATIC_STRING_HASH_RECORD * _rgBuckets[ STATIC_STRING_HASH_BUCKETS ];
|
||||
|
||||
private:
|
||||
|
||||
BOOL _fCaseSensitive;
|
||||
|
||||
STATIC_STRING_HASH_RECORD *
|
||||
FindNextBucket(
|
||||
DWORD *pdwStartingBucket
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Scan for the next non-empty bucket.
|
||||
|
||||
Arguments:
|
||||
|
||||
pdwStartingBucket - Supplies a pointer to the starting
|
||||
bucket index. This value is updated with the index
|
||||
of the next non-empty bucket if successful.
|
||||
|
||||
Return Value:
|
||||
|
||||
The first entry in the next non-empty bucket if successful,
|
||||
NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD i;
|
||||
STATIC_STRING_HASH_RECORD *pScan = NULL;
|
||||
|
||||
for (i = *pdwStartingBucket ; i < STATIC_STRING_HASH_BUCKETS ; i++)
|
||||
{
|
||||
pScan = _rgBuckets[i];
|
||||
|
||||
if (pScan != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*pdwStartingBucket = i;
|
||||
return pScan;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct STATIC_WSTRING_HASH_RECORD
|
||||
{
|
||||
WCHAR * _pszName;
|
||||
STATIC_WSTRING_HASH_RECORD * _pNext;
|
||||
USHORT _cchName;
|
||||
};
|
||||
|
||||
|
||||
struct STATIC_WSTRING_HASH_ITER
|
||||
{
|
||||
STATIC_WSTRING_HASH_RECORD *_pCursor;
|
||||
DWORD _dwBucket;
|
||||
BOOL _fRemove;
|
||||
};
|
||||
|
||||
|
||||
class STATIC_WSTRING_HASH
|
||||
{
|
||||
public:
|
||||
STATIC_WSTRING_HASH(
|
||||
BOOL fCaseSensitive = FALSE
|
||||
) : _fCaseSensitive( fCaseSensitive )
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
VOID
|
||||
Reset()
|
||||
{
|
||||
ZeroMemory( &_rgBuckets, sizeof( _rgBuckets ) );
|
||||
}
|
||||
|
||||
static
|
||||
PCWSTR
|
||||
ExtractKey(
|
||||
__in const STATIC_WSTRING_HASH_RECORD * pRecord
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Get the key out of the record
|
||||
|
||||
Arguments:
|
||||
|
||||
record to fetch the key from
|
||||
|
||||
Return Value:
|
||||
|
||||
key
|
||||
|
||||
--*/
|
||||
{
|
||||
DBG_ASSERT( pRecord != NULL );
|
||||
return pRecord->_pszName;
|
||||
}
|
||||
|
||||
VOID
|
||||
InsertRecord(
|
||||
__in STATIC_WSTRING_HASH_RECORD * pRecord
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Insert record to hash table
|
||||
|
||||
Note: remember this is static hash table
|
||||
There is no synchronization on the table
|
||||
Exclusive acess must be assured by caller
|
||||
|
||||
Arguments:
|
||||
|
||||
record to fetch the key from
|
||||
|
||||
Return Value:
|
||||
|
||||
VOID
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD dwIndex;
|
||||
STATIC_WSTRING_HASH_RECORD* pCursor;
|
||||
|
||||
DBG_ASSERT( pRecord != NULL );
|
||||
DBG_ASSERT( pRecord->_pszName != NULL );
|
||||
|
||||
if (_fCaseSensitive)
|
||||
{
|
||||
dwIndex = HashString( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwIndex = HashStringNoCase( pRecord->_pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
|
||||
pCursor = _rgBuckets[ dwIndex ];
|
||||
|
||||
pRecord->_pNext = pCursor;
|
||||
_rgBuckets[ dwIndex ] = pRecord;
|
||||
}
|
||||
|
||||
STATIC_WSTRING_HASH_RECORD *
|
||||
FindKey(
|
||||
__in PCWSTR pszName,
|
||||
BOOL fRemove = FALSE
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Find key in the table (and remove it optionally)
|
||||
|
||||
Arguments:
|
||||
|
||||
key
|
||||
|
||||
Return Value:
|
||||
|
||||
record containing the key
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD dwIndex;
|
||||
STATIC_WSTRING_HASH_RECORD* pRecord;
|
||||
STATIC_WSTRING_HASH_RECORD* pLastRecord = NULL;
|
||||
|
||||
DBG_ASSERT( pszName != NULL );
|
||||
|
||||
if (_fCaseSensitive)
|
||||
{
|
||||
dwIndex = HashString( pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwIndex = HashStringNoCase( pszName ) % STATIC_STRING_HASH_BUCKETS;
|
||||
}
|
||||
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
if ( _fCaseSensitive )
|
||||
{
|
||||
if ( wcscmp( pszName, pRecord->_pszName ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( _wcsicmp( pszName, pRecord->_pszName ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pLastRecord = pRecord;
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
|
||||
if (fRemove &&
|
||||
pRecord != NULL)
|
||||
{
|
||||
if (pLastRecord != NULL)
|
||||
{
|
||||
pLastRecord->_pNext = pRecord->_pNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rgBuckets[dwIndex] = pRecord->_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
return pRecord;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CheckDistribution(
|
||||
IN DWORD dwConflictThreshold,
|
||||
IN BOOL fToDebugger
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Simple verification on conflicts within the table
|
||||
|
||||
Arguments:
|
||||
|
||||
dwConflictThreshold - max number of entries tolerated per bucket
|
||||
fToDebbuger - spew the entries exceeding threshold into debugger
|
||||
|
||||
Return Value:
|
||||
|
||||
FALSE it threshold was reached (means hash funcion may not be optimal)
|
||||
|
||||
--*/
|
||||
{
|
||||
BOOL fThresholdReached = FALSE;
|
||||
STATIC_WSTRING_HASH_RECORD* pRecord;
|
||||
for ( DWORD dwIndex = 0; dwIndex < STATIC_STRING_HASH_BUCKETS; dwIndex++)
|
||||
{
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
DWORD countInBucket = 0;
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
countInBucket++;
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
//
|
||||
// print out the list of multiple entries in bucket
|
||||
//
|
||||
if ( countInBucket > dwConflictThreshold && fToDebugger )
|
||||
{
|
||||
fThresholdReached = TRUE;
|
||||
|
||||
pRecord = _rgBuckets[ dwIndex ];
|
||||
while ( pRecord != NULL )
|
||||
{
|
||||
pRecord = pRecord->_pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fThresholdReached;
|
||||
}
|
||||
|
||||
STATIC_WSTRING_HASH_RECORD *
|
||||
FindFirst(
|
||||
STATIC_WSTRING_HASH_ITER *pIterator,
|
||||
BOOL fRemove = FALSE
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begins a new hash item enumeration.
|
||||
|
||||
Arguments:
|
||||
|
||||
pIterator - Supplies the context for the enumeration.
|
||||
|
||||
fRemove - Supplies TRUE if the items should be removed
|
||||
from the hash as they are enumerated.
|
||||
|
||||
Return Value:
|
||||
|
||||
The first entry in the hash if successful, NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
pIterator->_dwBucket = 0;
|
||||
pIterator->_fRemove = fRemove;
|
||||
pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket);
|
||||
|
||||
if (pIterator->_fRemove && pIterator->_pCursor != NULL)
|
||||
{
|
||||
_rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
return pIterator->_pCursor;
|
||||
}
|
||||
|
||||
STATIC_WSTRING_HASH_RECORD *
|
||||
FindNext(
|
||||
STATIC_WSTRING_HASH_ITER *pIterator
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Continues a hash item enumeration.
|
||||
|
||||
Arguments:
|
||||
|
||||
pIterator - Supplies the context for the enumeration.
|
||||
|
||||
Return Value:
|
||||
|
||||
The next entry in the hash if successful, NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
if (pIterator->_pCursor != NULL)
|
||||
{
|
||||
if (pIterator->_fRemove)
|
||||
{
|
||||
pIterator->_pCursor = _rgBuckets[pIterator->_dwBucket];
|
||||
}
|
||||
else
|
||||
{
|
||||
pIterator->_pCursor = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
if (pIterator->_pCursor == NULL)
|
||||
{
|
||||
pIterator->_dwBucket++;
|
||||
pIterator->_pCursor = FindNextBucket(&pIterator->_dwBucket);
|
||||
}
|
||||
}
|
||||
|
||||
if (pIterator->_fRemove && pIterator->_pCursor != NULL)
|
||||
{
|
||||
_rgBuckets[pIterator->_dwBucket] = pIterator->_pCursor->_pNext;
|
||||
}
|
||||
|
||||
return pIterator->_pCursor;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
STATIC_WSTRING_HASH_RECORD * _rgBuckets[ STATIC_STRING_HASH_BUCKETS ];
|
||||
|
||||
private:
|
||||
|
||||
BOOL _fCaseSensitive;
|
||||
|
||||
STATIC_WSTRING_HASH_RECORD *
|
||||
FindNextBucket(
|
||||
DWORD *pdwStartingBucket
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Scan for the next non-empty bucket.
|
||||
|
||||
Arguments:
|
||||
|
||||
pdwStartingBucket - Supplies a pointer to the starting
|
||||
bucket index. This value is updated with the index
|
||||
of the next non-empty bucket if successful.
|
||||
|
||||
Return Value:
|
||||
|
||||
The first entry in the next non-empty bucket if successful,
|
||||
NULL otherwise.
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD i;
|
||||
STATIC_WSTRING_HASH_RECORD *pScan = NULL;
|
||||
|
||||
for (i = *pdwStartingBucket ; i < STATIC_STRING_HASH_BUCKETS ; i++)
|
||||
{
|
||||
pScan = _rgBuckets[i];
|
||||
|
||||
if (pScan != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*pdwStartingBucket = i;
|
||||
return pScan;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //__STATIC_HASH__H_
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Use C++ standard 'nullptr'
|
||||
//
|
||||
|
||||
#ifdef NULL
|
||||
#undef NULL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef _NATIVE_NULLPTR_SUPPORTED
|
||||
#define NULL nullptr
|
||||
#else
|
||||
#define NULL 0
|
||||
#define nullptr 0
|
||||
#endif
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
//#define nullptr ((void *)0)
|
||||
#endif
|
||||
|
|
@ -0,0 +1,515 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include "macros.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
class STRA
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
STRA(
|
||||
VOID
|
||||
);
|
||||
|
||||
STRA(
|
||||
__inout_ecount(cchInit) CHAR* pbInit,
|
||||
__in DWORD cchInit
|
||||
);
|
||||
|
||||
BOOL
|
||||
IsEmpty(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCSTR pszRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRA * pstrRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRA & strRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
static
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCSTR pszLhs,
|
||||
__in PCSTR pszRhs,
|
||||
__in bool fIgnoreCase = false
|
||||
)
|
||||
{
|
||||
// Return FALSE if either or both strings are NULL.
|
||||
if (!pszLhs || !pszRhs) return FALSE;
|
||||
|
||||
if( fIgnoreCase )
|
||||
{
|
||||
return ( 0 == _stricmp( pszLhs, pszRhs ) );
|
||||
}
|
||||
|
||||
return ( 0 == strcmp( pszLhs, pszRhs ) );
|
||||
}
|
||||
|
||||
VOID
|
||||
Trim();
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRA * pStraPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRA & straPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in PCSTR pszPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRA * pStraSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRA & straSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in PCSTR pszSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in CHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in PCSTR pszValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
LastIndexOf(
|
||||
__in CHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCB(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QuerySizeCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QuerySize(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
__nullterminated
|
||||
__bcount(this->m_cchLen)
|
||||
CHAR *
|
||||
QueryStr(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
VOID
|
||||
Reset(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Resize(
|
||||
__in DWORD cchSize
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SyncWithBuffer(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in PCSTR pszCopy
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in_ecount(cbLen)
|
||||
PCSTR pszCopy,
|
||||
__in SIZE_T cbLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRA * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRA & strRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyW(
|
||||
__in PCWSTR pszCopyW
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyW(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszCopyW,
|
||||
__in SIZE_T cchLen,
|
||||
__in UINT CodePage = CP_UTF8,
|
||||
__in BOOL fFailIfNoTranslation = FALSE
|
||||
)
|
||||
{
|
||||
_ASSERTE( cchLen <= MAXDWORD );
|
||||
|
||||
return AuxAppendW(
|
||||
pszCopyW,
|
||||
static_cast<DWORD>(cchLen),
|
||||
0,
|
||||
CodePage,
|
||||
fFailIfNoTranslation
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
CopyWTruncate(
|
||||
__in PCWSTR pszCopyWTruncate
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWTruncate(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszCopyWTruncate,
|
||||
__in SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in PCSTR pszAppend
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in_ecount(cbLen)
|
||||
PCSTR pszAppend,
|
||||
__in SIZE_T cbLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRA * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRA & strRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendW(
|
||||
__in PCWSTR pszAppendW
|
||||
)
|
||||
{
|
||||
HRESULT hr;
|
||||
size_t cchLen;
|
||||
hr = StringCchLengthW( pszAppendW,
|
||||
STRSAFE_MAX_CCH,
|
||||
&cchLen );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
return AppendW( pszAppendW, cchLen );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AppendW(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszAppendW,
|
||||
__in SIZE_T cchLen,
|
||||
__in UINT CodePage = CP_UTF8,
|
||||
__in BOOL fFailIfNoTranslation = FALSE
|
||||
)
|
||||
{
|
||||
_ASSERTE( cchLen <= MAXDWORD );
|
||||
if ( cchLen == 0 )
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
return AuxAppendW(
|
||||
pszAppendW,
|
||||
static_cast<DWORD>(cchLen),
|
||||
QueryCB(),
|
||||
CodePage,
|
||||
fFailIfNoTranslation
|
||||
);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AppendWTruncate(
|
||||
__in PCWSTR pszAppendWTruncate
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendWTruncate(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszAppendWTruncate,
|
||||
__in SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyToBuffer(
|
||||
__out_bcount(*pcb) CHAR* pszBuffer,
|
||||
__inout DWORD * pcb
|
||||
) const;
|
||||
|
||||
HRESULT
|
||||
SetLen(
|
||||
__in DWORD cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeSnprintf(
|
||||
__in __format_string
|
||||
PCSTR pszFormatString,
|
||||
...
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeVsnprintf(
|
||||
__in __format_string
|
||||
PCSTR pszFormatString,
|
||||
va_list argsList
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Escape(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
EscapeUtf8(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
Unescape(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Unescaped(
|
||||
__in LPCWSTR cpchStr
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Unescaped(
|
||||
__in_ecount(cch)
|
||||
LPCWSTR cpchStr,
|
||||
__in DWORD cch
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Escaped(
|
||||
__in LPCWSTR cpchStr
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyWToUTF8Escaped(
|
||||
__in_ecount(cch)
|
||||
LPCWSTR cpchStr,
|
||||
__in DWORD cch
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Avoid C++ errors. This object should never go through a copy
|
||||
// constructor, unintended cast or assignment.
|
||||
//
|
||||
STRA( const STRA &);
|
||||
STRA & operator = (const STRA &);
|
||||
|
||||
HRESULT
|
||||
AuxAppend(
|
||||
__in_ecount(cbLen)
|
||||
LPCSTR pStr,
|
||||
__in DWORD cbLen,
|
||||
__in DWORD cbOffset
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppendW(
|
||||
__in_ecount(cchAppendW)
|
||||
PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset,
|
||||
__in UINT CodePage,
|
||||
__in BOOL fFailIfNoTranslation
|
||||
)
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
|
||||
if( CP_ACP == CodePage )
|
||||
{
|
||||
dwFlags = WC_NO_BEST_FIT_CHARS;
|
||||
}
|
||||
else if( fFailIfNoTranslation && CodePage == CP_UTF8 )
|
||||
{
|
||||
//
|
||||
// WC_ERR_INVALID_CHARS is only supported in Longhorn or greater.
|
||||
//
|
||||
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
|
||||
dwFlags |= WC_ERR_INVALID_CHARS;
|
||||
#else
|
||||
UNREFERENCED_PARAMETER(fFailIfNoTranslation);
|
||||
#endif
|
||||
}
|
||||
|
||||
return AuxAppendW( pszAppendW,
|
||||
cchAppendW,
|
||||
cbOffset,
|
||||
CodePage,
|
||||
fFailIfNoTranslation,
|
||||
dwFlags );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AuxAppendW(
|
||||
__in_ecount(cchAppendW)
|
||||
PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset,
|
||||
__in UINT CodePage,
|
||||
__in BOOL fFailIfNoTranslation,
|
||||
__in DWORD dwFlags
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppendWTruncate(
|
||||
__in_ecount(cchAppendW)
|
||||
__in PCWSTR pszAppendW,
|
||||
__in DWORD cchAppendW,
|
||||
__in DWORD cbOffset
|
||||
);
|
||||
|
||||
static
|
||||
int
|
||||
ConvertUnicodeToCodePage(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__inout BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen,
|
||||
__in UINT uCodePage
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ConvertUnicodeToMultiByte(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__in BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT
|
||||
ConvertUnicodeToUTF8(
|
||||
__in_ecount(dwStringLen)
|
||||
LPCWSTR pszSrcUnicodeString,
|
||||
__in BUFFER_T<CHAR,1> * pbufDstAnsiString,
|
||||
__in DWORD dwStringLen
|
||||
);
|
||||
|
||||
typedef bool (* PFN_F_SHOULD_ESCAPE)(BYTE ch);
|
||||
|
||||
HRESULT
|
||||
EscapeInternal(
|
||||
PFN_F_SHOULD_ESCAPE pfnFShouldEscape
|
||||
);
|
||||
|
||||
//
|
||||
// Buffer with an inline buffer of 1,
|
||||
// enough to hold null-terminating character.
|
||||
//
|
||||
BUFFER_T<CHAR,1> m_Buff;
|
||||
DWORD m_cchLen;
|
||||
};
|
||||
|
||||
inline
|
||||
HRESULT
|
||||
AppendToString(
|
||||
ULONGLONG Number,
|
||||
STRA & String
|
||||
)
|
||||
{
|
||||
// prefast complains Append requires input
|
||||
// to be null terminated, so zero initialize
|
||||
// and pass the size of the buffer minus one
|
||||
// to _ui64toa_s
|
||||
CHAR chNumber[32] = {0};
|
||||
if (_ui64toa_s(Number,
|
||||
chNumber,
|
||||
sizeof(chNumber) - sizeof(CHAR),
|
||||
10) != 0)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return String.Append(chNumber);
|
||||
}
|
||||
|
||||
template<DWORD size>
|
||||
CHAR* InitHelper(__out CHAR (&psz)[size])
|
||||
{
|
||||
psz[0] = '\0';
|
||||
return psz;
|
||||
}
|
||||
|
||||
//
|
||||
// Heap operation reduction macros
|
||||
//
|
||||
#define STACK_STRA(name, size) CHAR __ach##name[size];\
|
||||
STRA name(InitHelper(__ach##name), sizeof(__ach##name))
|
||||
|
||||
#define INLINE_STRA(name, size) CHAR __ach##name[size];\
|
||||
STRA name;
|
||||
|
||||
#define INLINE_STRA_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name))
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
class STRU
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
STRU(
|
||||
VOID
|
||||
);
|
||||
|
||||
STRU(
|
||||
__inout_ecount(cchInit) WCHAR* pbInit,
|
||||
__in DWORD cchInit
|
||||
);
|
||||
|
||||
BOOL
|
||||
IsEmpty(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRU * pstrRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
_ASSERTE( pstrRhs != NULL );
|
||||
return Equals( pstrRhs->QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in const STRU & strRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
return Equals( strRhs.QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCWSTR pszRhs,
|
||||
__in BOOL fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
_ASSERTE( NULL != pszRhs );
|
||||
if ( NULL == pszRhs )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
|
||||
|
||||
return ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
|
||||
QueryCCH(),
|
||||
pszRhs,
|
||||
-1,
|
||||
fIgnoreCase ) );
|
||||
#else
|
||||
|
||||
if( fIgnoreCase )
|
||||
{
|
||||
return ( 0 == _wcsicmp( QueryStr(), pszRhs ) );
|
||||
}
|
||||
return ( 0 == wcscmp( QueryStr(), pszRhs ) );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
BOOL
|
||||
Equals(
|
||||
__in PCWSTR pwszLhs,
|
||||
__in PCWSTR pwszRhs,
|
||||
__in bool fIgnoreCase = false
|
||||
)
|
||||
{
|
||||
// Return FALSE if either or both strings are NULL.
|
||||
if (!pwszLhs || !pwszRhs) return FALSE;
|
||||
|
||||
//
|
||||
// This method performs a ordinal string comparison when OS is Vista or
|
||||
// greater and a culture sensitive comparison if not (XP). This is
|
||||
// consistent with the existing Equals implementation (see above).
|
||||
//
|
||||
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
|
||||
|
||||
return ( CSTR_EQUAL == CompareStringOrdinal( pwszLhs,
|
||||
-1,
|
||||
pwszRhs,
|
||||
-1,
|
||||
fIgnoreCase ) );
|
||||
#else
|
||||
|
||||
if( fIgnoreCase )
|
||||
{
|
||||
return ( 0 == _wcsicmp( pwszLhs, pwszRhs ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( 0 == wcscmp( pwszLhs, pwszRhs ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID
|
||||
Trim();
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRU * pStruPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
_ASSERTE( pStruPrefix != NULL );
|
||||
return StartsWith( pStruPrefix->QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in const STRU & struPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
return StartsWith( struPrefix.QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
StartsWith(
|
||||
__in PCWSTR pwszPrefix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRU * pStruSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
_ASSERTE( pStruSuffix != NULL );
|
||||
return EndsWith( pStruSuffix->QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in const STRU & struSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const
|
||||
{
|
||||
return EndsWith( struSuffix.QueryStr(), fIgnoreCase );
|
||||
}
|
||||
|
||||
BOOL
|
||||
EndsWith(
|
||||
__in PCWSTR pwszSuffix,
|
||||
__in bool fIgnoreCase = FALSE
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in WCHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
IndexOf(
|
||||
__in PCWSTR pwszValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
INT
|
||||
LastIndexOf(
|
||||
__in WCHAR charValue,
|
||||
__in DWORD dwStartIndex = 0
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCB(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QueryCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
DWORD
|
||||
QuerySizeCCH(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
__nullterminated
|
||||
__ecount(this->m_cchLen)
|
||||
WCHAR*
|
||||
QueryStr(
|
||||
VOID
|
||||
) const;
|
||||
|
||||
VOID
|
||||
Reset(
|
||||
VOID
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Resize(
|
||||
DWORD cchSize
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SyncWithBuffer(
|
||||
VOID
|
||||
);
|
||||
|
||||
template<size_t size>
|
||||
HRESULT
|
||||
Copy(
|
||||
__in PCWSTR const (&rgpszStrings)[size]
|
||||
)
|
||||
//
|
||||
// Copies an array of strings declared as stack array. For example:
|
||||
//
|
||||
// LPCWSTR rgExample[] { L"one", L"two" };
|
||||
// hr = str.Copy( rgExample );
|
||||
//
|
||||
{
|
||||
Reset();
|
||||
|
||||
return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in PCWSTR pszCopy
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszCopy,
|
||||
SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRU * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Copy(
|
||||
__in const STRU & str
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyAndExpandEnvironmentStrings(
|
||||
__in PCWSTR pszSource
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyA(
|
||||
__in PCSTR pszCopyA
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyA(
|
||||
__in_bcount(cchLen)
|
||||
PCSTR pszCopyA,
|
||||
SIZE_T cchLen,
|
||||
UINT CodePage = CP_UTF8
|
||||
);
|
||||
|
||||
template<size_t size>
|
||||
HRESULT
|
||||
Append(
|
||||
__in PCWSTR const (&rgpszStrings)[size]
|
||||
)
|
||||
//
|
||||
// Appends an array of strings declared as stack array. For example:
|
||||
//
|
||||
// LPCWSTR rgExample[] { L"one", L"two" };
|
||||
// hr = str.Append( rgExample );
|
||||
//
|
||||
{
|
||||
return AuxAppend( rgpszStrings, _countof( rgpszStrings ) );
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in PCWSTR pszAppend
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in_ecount(cchLen)
|
||||
PCWSTR pszAppend,
|
||||
SIZE_T cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRU * pstrRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
Append(
|
||||
__in const STRU & strRhs
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendA(
|
||||
__in PCSTR pszAppendA
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AppendA(
|
||||
__in_bcount(cchLen)
|
||||
PCSTR pszAppendA,
|
||||
SIZE_T cchLen,
|
||||
UINT CodePage = CP_UTF8
|
||||
);
|
||||
|
||||
HRESULT
|
||||
CopyToBuffer(
|
||||
__out_bcount(*pcb) WCHAR* pszBuffer,
|
||||
PDWORD pcb
|
||||
) const;
|
||||
|
||||
HRESULT
|
||||
CopyToBufferA(
|
||||
__out_bcount(*pcb) CHAR* pszBuffer,
|
||||
__inout PDWORD pcb
|
||||
) const;
|
||||
|
||||
HRESULT
|
||||
SetLen(
|
||||
__in DWORD cchLen
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeSnwprintf(
|
||||
__in PCWSTR pwszFormatString,
|
||||
...
|
||||
);
|
||||
|
||||
HRESULT
|
||||
SafeVsnwprintf(
|
||||
__in PCWSTR pwszFormatString,
|
||||
va_list argsList
|
||||
);
|
||||
|
||||
static
|
||||
HRESULT ExpandEnvironmentVariables(
|
||||
__in PCWSTR pszString,
|
||||
__out STRU * pstrExpandedString
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Avoid C++ errors. This object should never go through a copy
|
||||
// constructor, unintended cast or assignment.
|
||||
//
|
||||
STRU( const STRU & );
|
||||
STRU & operator = ( const STRU & );
|
||||
|
||||
HRESULT
|
||||
AuxAppend(
|
||||
__in_ecount(cNumStrings)
|
||||
PCWSTR const rgpszStrings[],
|
||||
SIZE_T cNumStrings
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppend(
|
||||
__in_bcount(cbStr)
|
||||
const WCHAR* pStr,
|
||||
SIZE_T cbStr,
|
||||
DWORD cbOffset
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AuxAppendA(
|
||||
__in_bcount(cbStr)
|
||||
const CHAR* pStr,
|
||||
SIZE_T cbStr,
|
||||
DWORD cbOffset,
|
||||
UINT CodePage
|
||||
);
|
||||
|
||||
//
|
||||
// Buffer with an inline buffer of 1,
|
||||
// enough to hold null-terminating character.
|
||||
//
|
||||
BUFFER_T<WCHAR,1> m_Buff;
|
||||
DWORD m_cchLen;
|
||||
};
|
||||
|
||||
//
|
||||
// Helps to initialize an external buffer before
|
||||
// constructing the STRU object.
|
||||
//
|
||||
template<DWORD size>
|
||||
WCHAR* InitHelper(__out WCHAR (&psz)[size])
|
||||
{
|
||||
psz[0] = L'\0';
|
||||
return psz;
|
||||
}
|
||||
|
||||
//
|
||||
// Heap operation reduction macros
|
||||
//
|
||||
#define STACK_STRU(name, size) WCHAR __ach##name[size];\
|
||||
STRU name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
|
||||
|
||||
#define INLINE_STRU(name, size) WCHAR __ach##name[size];\
|
||||
STRU name;
|
||||
|
||||
#define INLINE_STRU_INIT(name) name(InitHelper(__ach##name), sizeof(__ach##name)/sizeof(*__ach##name))
|
||||
|
||||
|
||||
HRESULT
|
||||
MakePathCanonicalizationProof(
|
||||
IN PCWSTR pszName,
|
||||
OUT STRU * pstrPath
|
||||
);
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _STTIMER_H
|
||||
#define _STTIMER_H
|
||||
|
||||
class STTIMER
|
||||
{
|
||||
public:
|
||||
|
||||
STTIMER()
|
||||
: _pTimer( NULL )
|
||||
{
|
||||
fInCanel = FALSE;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STTIMER()
|
||||
{
|
||||
if ( _pTimer )
|
||||
{
|
||||
CancelTimer();
|
||||
|
||||
CloseThreadpoolTimer( _pTimer );
|
||||
|
||||
_pTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
InitializeTimer(
|
||||
PTP_TIMER_CALLBACK pfnCallback,
|
||||
VOID * pContext,
|
||||
DWORD dwInitialWait = 0,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
_pTimer = CreateThreadpoolTimer( pfnCallback,
|
||||
pContext,
|
||||
NULL );
|
||||
|
||||
if ( !_pTimer )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
if ( dwInitialWait )
|
||||
{
|
||||
SetTimer( dwInitialWait,
|
||||
dwPeriod );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetTimer(
|
||||
DWORD dwInitialWait,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
FILETIME ftInitialWait;
|
||||
|
||||
if ( dwInitialWait == 0 && dwPeriod == 0 )
|
||||
{
|
||||
//
|
||||
// Special case. We are preventing new callbacks
|
||||
// from being queued. Any existing callbacks in the
|
||||
// queue will still run.
|
||||
//
|
||||
// This effectively disables the timer. It can be
|
||||
// re-enabled by setting non-zero initial wait or
|
||||
// period values.
|
||||
//
|
||||
if (_pTimer != NULL)
|
||||
{
|
||||
SetThreadpoolTimer(_pTimer, NULL, 0, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
|
||||
|
||||
SetThreadpoolTimer( _pTimer,
|
||||
&ftInitialWait,
|
||||
dwPeriod,
|
||||
0 );
|
||||
}
|
||||
|
||||
VOID
|
||||
CancelTimer()
|
||||
{
|
||||
//
|
||||
// Disable the timer
|
||||
//
|
||||
if (fInCanel)
|
||||
return;
|
||||
|
||||
fInCanel = TRUE;
|
||||
SetTimer( 0 );
|
||||
|
||||
//
|
||||
// Wait until any callbacks queued prior to disabling
|
||||
// have completed.
|
||||
//
|
||||
if (_pTimer != NULL)
|
||||
WaitForThreadpoolTimerCallbacks( _pTimer, TRUE );
|
||||
|
||||
_pTimer = NULL;
|
||||
fInCanel = FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VOID
|
||||
InitializeRelativeFileTime(
|
||||
FILETIME * pft,
|
||||
DWORD dwMilliseconds
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
//
|
||||
// The pftDueTime parameter expects the time to be
|
||||
// expressed as the number of 100 nanosecond intervals
|
||||
// times -1.
|
||||
//
|
||||
// To convert from milliseconds, we'll multiply by
|
||||
// -10000
|
||||
//
|
||||
|
||||
li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
|
||||
|
||||
pft->dwHighDateTime = li.HighPart;
|
||||
pft->dwLowDateTime = li.LowPart;
|
||||
};
|
||||
|
||||
TP_TIMER * _pTimer;
|
||||
BOOL fInCanel;
|
||||
};
|
||||
|
||||
class STELAPSED
|
||||
{
|
||||
public:
|
||||
|
||||
STELAPSED()
|
||||
: _dwInitTime( 0 ),
|
||||
_dwInitTickCount( 0 ),
|
||||
_dwPerfCountsPerMillisecond( 0 ),
|
||||
_fUsingHighResolution( FALSE )
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
BOOL fResult;
|
||||
|
||||
_dwInitTickCount = GetTickCount64();
|
||||
|
||||
fResult = QueryPerformanceFrequency( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwPerfCountsPerMillisecond = li.QuadPart / 1000;
|
||||
|
||||
fResult = QueryPerformanceCounter( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
_fUsingHighResolution = TRUE;
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STELAPSED()
|
||||
{
|
||||
}
|
||||
|
||||
LONGLONG
|
||||
QueryElapsedTime()
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
|
||||
{
|
||||
DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
if ( dwCurrentTime < _dwInitTime )
|
||||
{
|
||||
//
|
||||
// It's theoretically possible that QueryPerformanceCounter
|
||||
// may return slightly different values on different CPUs.
|
||||
// In this case, we don't want to return an unexpected value
|
||||
// so we'll return zero. This is acceptable because
|
||||
// presumably such a case would only happen for a very short
|
||||
// time window.
|
||||
//
|
||||
// It would be possible to prevent this by ensuring processor
|
||||
// affinity for all calls to QueryPerformanceCounter, but that
|
||||
// would be undesirable in the general case because it could
|
||||
// introduce unnecessary context switches and potentially a
|
||||
// CPU bottleneck.
|
||||
//
|
||||
// Note that this issue also applies to callers doing rapid
|
||||
// calls to this function. If a caller wants to mitigate
|
||||
// that, they could enforce the affinitization, or they
|
||||
// could implement a similar sanity check when comparing
|
||||
// returned values from this function.
|
||||
//
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dwCurrentTime - _dwInitTime;
|
||||
}
|
||||
|
||||
return GetTickCount64() - _dwInitTickCount;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryUsingHighResolution()
|
||||
{
|
||||
return _fUsingHighResolution;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DWORD64 _dwInitTime;
|
||||
DWORD64 _dwInitTickCount;
|
||||
DWORD64 _dwPerfCountsPerMillisecond;
|
||||
BOOL _fUsingHighResolution;
|
||||
};
|
||||
|
||||
#endif // _STTIMER_H
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _TRACELOG_H_
|
||||
#define _TRACELOG_H_
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
typedef struct _TRACE_LOG {
|
||||
|
||||
//
|
||||
// Signature.
|
||||
//
|
||||
|
||||
LONG Signature;
|
||||
|
||||
//
|
||||
// The total number of entries available in the log.
|
||||
//
|
||||
|
||||
LONG LogSize;
|
||||
|
||||
//
|
||||
// The index of the next entry to use.
|
||||
//
|
||||
|
||||
LONG NextEntry;
|
||||
|
||||
//
|
||||
// The byte size of each entry.
|
||||
//
|
||||
|
||||
LONG EntrySize;
|
||||
|
||||
//
|
||||
// Pointer to the start of the circular buffer.
|
||||
//
|
||||
|
||||
PUCHAR LogBuffer;
|
||||
|
||||
//
|
||||
// The extra header bytes and actual log entries go here.
|
||||
//
|
||||
// BYTE ExtraHeaderBytes[ExtraBytesInHeader];
|
||||
// BYTE Entries[LogSize][EntrySize];
|
||||
//
|
||||
|
||||
} TRACE_LOG, *PTRACE_LOG;
|
||||
|
||||
|
||||
//
|
||||
// Log header signature.
|
||||
//
|
||||
|
||||
#define TRACE_LOG_SIGNATURE ((DWORD)'gOlT')
|
||||
#define TRACE_LOG_SIGNATURE_X ((DWORD)'golX')
|
||||
|
||||
|
||||
//
|
||||
// This macro maps a TRACE_LOG pointer to a pointer to the 'extra'
|
||||
// data associated with the log.
|
||||
//
|
||||
|
||||
#define TRACE_LOG_TO_EXTRA_DATA(log) (PVOID)( (log) + 1 )
|
||||
|
||||
|
||||
//
|
||||
// Manipulators.
|
||||
//
|
||||
|
||||
PTRACE_LOG
|
||||
CreateTraceLog(
|
||||
IN LONG LogSize,
|
||||
IN LONG ExtraBytesInHeader,
|
||||
IN LONG EntrySize
|
||||
);
|
||||
|
||||
VOID
|
||||
DestroyTraceLog(
|
||||
IN PTRACE_LOG Log
|
||||
);
|
||||
|
||||
LONG
|
||||
WriteTraceLog(
|
||||
IN PTRACE_LOG Log,
|
||||
IN PVOID Entry
|
||||
);
|
||||
|
||||
VOID
|
||||
ResetTraceLog(
|
||||
IN PTRACE_LOG Log
|
||||
);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif // _TRACELOG_H_
|
||||
|
||||
|
|
@ -0,0 +1,850 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crtdbg.h>
|
||||
#include "rwlock.h"
|
||||
#include "prime.h"
|
||||
|
||||
template <class _Record>
|
||||
class TREE_HASH_NODE
|
||||
{
|
||||
template <class _Record>
|
||||
friend class TREE_HASH_TABLE;
|
||||
|
||||
private:
|
||||
// Next node in the hash table look-aside
|
||||
TREE_HASH_NODE<_Record> *_pNext;
|
||||
|
||||
// links in the tree structure
|
||||
TREE_HASH_NODE * _pParentNode;
|
||||
TREE_HASH_NODE * _pFirstChild;
|
||||
TREE_HASH_NODE * _pNextSibling;
|
||||
|
||||
// actual record
|
||||
_Record * _pRecord;
|
||||
|
||||
// hash value
|
||||
PCWSTR _pszPath;
|
||||
DWORD _dwHash;
|
||||
};
|
||||
|
||||
template <class _Record>
|
||||
class TREE_HASH_TABLE
|
||||
{
|
||||
protected:
|
||||
typedef BOOL
|
||||
(PFN_DELETE_IF)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
typedef VOID
|
||||
(PFN_APPLY)(
|
||||
_Record * pRecord,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
public:
|
||||
TREE_HASH_TABLE(
|
||||
BOOL fCaseSensitive
|
||||
) : _ppBuckets( NULL ),
|
||||
_nBuckets( 0 ),
|
||||
_nItems( 0 ),
|
||||
_fCaseSensitive( fCaseSensitive )
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~TREE_HASH_TABLE();
|
||||
|
||||
virtual
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
virtual
|
||||
PCWSTR
|
||||
GetKey(
|
||||
_Record * pRecord
|
||||
) = 0;
|
||||
|
||||
DWORD
|
||||
Count()
|
||||
{
|
||||
return _nItems;
|
||||
}
|
||||
|
||||
virtual
|
||||
VOID
|
||||
Clear();
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD nBucketSize
|
||||
);
|
||||
|
||||
DWORD
|
||||
CalcHash(
|
||||
PCWSTR pszKey
|
||||
)
|
||||
{
|
||||
return _fCaseSensitive ? HashString(pszKey) : HashStringNoCase(pszKey);
|
||||
}
|
||||
|
||||
virtual
|
||||
VOID
|
||||
FindKey(
|
||||
PCWSTR pszKey,
|
||||
_Record ** ppRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
HRESULT
|
||||
InsertRecord(
|
||||
_Record * pRecord
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteKey(
|
||||
PCWSTR pszKey
|
||||
);
|
||||
|
||||
virtual
|
||||
VOID
|
||||
DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
VOID
|
||||
Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
BOOL
|
||||
FindNodeInternal(
|
||||
PCWSTR pszKey,
|
||||
DWORD dwHash,
|
||||
TREE_HASH_NODE<_Record> ** ppNode,
|
||||
TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer = NULL
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AddNodeInternal(
|
||||
PCWSTR pszPath,
|
||||
DWORD dwHash,
|
||||
_Record * pRecord,
|
||||
TREE_HASH_NODE<_Record> * pParentNode,
|
||||
TREE_HASH_NODE<_Record> ** ppNewNode
|
||||
);
|
||||
|
||||
HRESULT
|
||||
AllocateNode(
|
||||
PCWSTR pszPath,
|
||||
DWORD dwHash,
|
||||
_Record * pRecord,
|
||||
TREE_HASH_NODE<_Record> * pParentNode,
|
||||
TREE_HASH_NODE<_Record> ** ppNewNode
|
||||
);
|
||||
|
||||
VOID
|
||||
DeleteNode(
|
||||
TREE_HASH_NODE<_Record> * pNode
|
||||
)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
DereferenceRecord(pNode->_pRecord);
|
||||
pNode->_pRecord = NULL;
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
pNode);
|
||||
}
|
||||
|
||||
VOID
|
||||
DeleteNodeInternal(
|
||||
TREE_HASH_NODE<_Record> ** ppPreviousNodeNextPointer,
|
||||
TREE_HASH_NODE<_Record> * pNode
|
||||
);
|
||||
|
||||
VOID
|
||||
RehashTableIfNeeded(
|
||||
VOID
|
||||
);
|
||||
|
||||
TREE_HASH_NODE<_Record> ** _ppBuckets;
|
||||
DWORD _nBuckets;
|
||||
DWORD _nItems;
|
||||
BOOL _fCaseSensitive;
|
||||
CWSDRWLock _tableLock;
|
||||
};
|
||||
|
||||
template <class _Record>
|
||||
HRESULT
|
||||
TREE_HASH_TABLE<_Record>::AllocateNode(
|
||||
PCWSTR pszPath,
|
||||
DWORD dwHash,
|
||||
_Record * pRecord,
|
||||
TREE_HASH_NODE<_Record> * pParentNode,
|
||||
TREE_HASH_NODE<_Record> ** ppNewNode
|
||||
)
|
||||
{
|
||||
//
|
||||
// Allocate enough extra space for pszPath
|
||||
//
|
||||
DWORD cchPath = (DWORD) wcslen(pszPath);
|
||||
if (cchPath >= ((0xffffffff - sizeof(TREE_HASH_NODE<_Record>))/sizeof(WCHAR) - 1))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
TREE_HASH_NODE<_Record> *pNode = (TREE_HASH_NODE<_Record> *)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(TREE_HASH_NODE<_Record>) + (cchPath+1)*sizeof(WCHAR));
|
||||
if (pNode == NULL)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
memcpy(pNode+1, pszPath, (cchPath+1)*sizeof(WCHAR));
|
||||
pNode->_pszPath = (PCWSTR)(pNode+1);
|
||||
pNode->_dwHash = dwHash;
|
||||
pNode->_pNext = pNode->_pNextSibling = pNode->_pFirstChild = NULL;
|
||||
pNode->_pParentNode = pParentNode;
|
||||
pNode->_pRecord = pRecord;
|
||||
|
||||
*ppNewNode = pNode;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
HRESULT
|
||||
TREE_HASH_TABLE<_Record>::Initialize(
|
||||
DWORD nBuckets
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( nBuckets == 0 )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
hr = _tableLock.Init();
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
||||
goto Failed;
|
||||
}
|
||||
_nBuckets = nBuckets;
|
||||
|
||||
return S_OK;
|
||||
|
||||
Failed:
|
||||
|
||||
if (_ppBuckets)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
template <class _Record>
|
||||
TREE_HASH_TABLE<_Record>::~TREE_HASH_TABLE()
|
||||
{
|
||||
if (_ppBuckets == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ASSERTE(_nItems == 0);
|
||||
|
||||
HeapFree(GetProcessHeap(),
|
||||
0,
|
||||
_ppBuckets);
|
||||
_ppBuckets = NULL;
|
||||
_nBuckets = 0;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::Clear()
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pCurrent;
|
||||
TREE_HASH_NODE<_Record> *pNext;
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pCurrent = _ppBuckets[i];
|
||||
_ppBuckets[i] = NULL;
|
||||
while (pCurrent != NULL)
|
||||
{
|
||||
pNext = pCurrent->_pNext;
|
||||
DeleteNode(pCurrent);
|
||||
pCurrent = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_nItems = 0;
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
BOOL
|
||||
TREE_HASH_TABLE<_Record>::FindNodeInternal(
|
||||
PCWSTR pszKey,
|
||||
DWORD dwHash,
|
||||
TREE_HASH_NODE<_Record> ** ppNode,
|
||||
TREE_HASH_NODE<_Record> *** pppPreviousNodeNextPointer
|
||||
)
|
||||
/*++
|
||||
Return value indicates whether the item is found
|
||||
key, dwHash - key and hash for the node to find
|
||||
ppNode - on successful return, the node found, on failed return, the first
|
||||
node with hash value greater than the node to be found
|
||||
pppPreviousNodeNextPointer - the pointer to previous node's _pNext
|
||||
|
||||
This routine may be called under either read or write lock
|
||||
--*/
|
||||
{
|
||||
TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
BOOL fFound = FALSE;
|
||||
|
||||
ppPreviousNodeNextPointer = _ppBuckets + (dwHash % _nBuckets);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_dwHash == dwHash)
|
||||
{
|
||||
if (CompareStringOrdinal(pszKey,
|
||||
-1,
|
||||
pNode->_pszPath,
|
||||
-1,
|
||||
!_fCaseSensitive) == CSTR_EQUAL)
|
||||
{
|
||||
fFound = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pNode->_dwHash > dwHash)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ppPreviousNodeNextPointer = &(pNode->_pNext);
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
|
||||
*ppNode = pNode;
|
||||
if (pppPreviousNodeNextPointer != NULL)
|
||||
{
|
||||
*pppPreviousNodeNextPointer = ppPreviousNodeNextPointer;
|
||||
}
|
||||
return fFound;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::FindKey(
|
||||
PCWSTR pszKey,
|
||||
_Record ** ppRecord
|
||||
)
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
|
||||
*ppRecord = NULL;
|
||||
|
||||
DWORD dwHash = CalcHash(pszKey);
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
if (FindNodeInternal(pszKey, dwHash, &pNode) &&
|
||||
pNode->_pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pNode->_pRecord);
|
||||
*ppRecord = pNode->_pRecord;
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
HRESULT
|
||||
TREE_HASH_TABLE<_Record>::AddNodeInternal(
|
||||
PCWSTR pszPath,
|
||||
DWORD dwHash,
|
||||
_Record * pRecord,
|
||||
TREE_HASH_NODE<_Record> * pParentNode,
|
||||
TREE_HASH_NODE<_Record> ** ppNewNode
|
||||
)
|
||||
/*++
|
||||
Return value is HRESULT indicating sucess or failure
|
||||
pszPath, dwHash, pRecord - path, hash value and record to be inserted
|
||||
pParentNode - this will be the parent of the node being inserted
|
||||
ppNewNode - on successful return, the new node created and inserted
|
||||
|
||||
This function may be called under a read or write lock
|
||||
--*/
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pNewNode;
|
||||
TREE_HASH_NODE<_Record> *pNextNode;
|
||||
TREE_HASH_NODE<_Record> **ppNextPointer;
|
||||
HRESULT hr;
|
||||
|
||||
//
|
||||
// Ownership of pRecord is not transferred to pNewNode yet, so remember
|
||||
// to either set it to null before deleting pNewNode or add an extra
|
||||
// reference later - this is to make sure we do not do an extra ref/deref
|
||||
// which users may view as getting flushed out of the hash-table
|
||||
//
|
||||
hr = AllocateNode(pszPath,
|
||||
dwHash,
|
||||
pRecord,
|
||||
pParentNode,
|
||||
&pNewNode);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
//
|
||||
// Find the right place to add this node
|
||||
//
|
||||
|
||||
if (FindNodeInternal(pszPath, dwHash, &pNextNode, &ppNextPointer))
|
||||
{
|
||||
//
|
||||
// If node already there, record may still need updating
|
||||
//
|
||||
if (pRecord != NULL &&
|
||||
InterlockedCompareExchangePointer((PVOID *)&pNextNode->_pRecord,
|
||||
pRecord,
|
||||
NULL) == NULL)
|
||||
{
|
||||
ReferenceRecord(pRecord);
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
// ownership of pRecord has either passed to existing record or
|
||||
// not to anyone at all
|
||||
pNewNode->_pRecord = NULL;
|
||||
DeleteNode(pNewNode);
|
||||
*ppNewNode = pNextNode;
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// If another node got inserted in betwen, we will have to retry
|
||||
//
|
||||
pNewNode->_pNext = pNextNode;
|
||||
} while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
|
||||
pNewNode,
|
||||
pNextNode) != pNextNode);
|
||||
// pass ownership of pRecord now
|
||||
if (pRecord != NULL)
|
||||
{
|
||||
ReferenceRecord(pRecord);
|
||||
pRecord = NULL;
|
||||
}
|
||||
InterlockedIncrement((LONG *)&_nItems);
|
||||
|
||||
//
|
||||
// update the parent
|
||||
//
|
||||
if (pParentNode != NULL)
|
||||
{
|
||||
ppNextPointer = &pParentNode->_pFirstChild;
|
||||
do
|
||||
{
|
||||
pNextNode = *ppNextPointer;
|
||||
pNewNode->_pNextSibling = pNextNode;
|
||||
} while (InterlockedCompareExchangePointer((PVOID *)ppNextPointer,
|
||||
pNewNode,
|
||||
pNextNode) != pNextNode);
|
||||
}
|
||||
|
||||
*ppNewNode = pNewNode;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
HRESULT
|
||||
TREE_HASH_TABLE<_Record>::InsertRecord(
|
||||
_Record * pRecord
|
||||
)
|
||||
/*++
|
||||
This method inserts a node for this record and also empty nodes for paths
|
||||
in the heirarchy leading upto this path
|
||||
|
||||
The insert is done under only a read-lock - this is possible by keeping
|
||||
the hashes in a bucket in increasing order and using interlocked operations
|
||||
to actually insert the item in the hash-bucket lookaside list and the parent
|
||||
children list
|
||||
|
||||
Returns HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) if the record already exists.
|
||||
Never leak this error to the end user because "*file* already exists" may be confusing.
|
||||
--*/
|
||||
{
|
||||
PCWSTR pszKey = GetKey(pRecord);
|
||||
STACK_STRU( strPartialPath, 256);
|
||||
PWSTR pszPartialPath;
|
||||
DWORD dwHash;
|
||||
DWORD cchEnd;
|
||||
HRESULT hr;
|
||||
TREE_HASH_NODE<_Record> *pParentNode = NULL;
|
||||
|
||||
hr = strPartialPath.Copy(pszKey);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
pszPartialPath = strPartialPath.QueryStr();
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
//
|
||||
// First find the lowest parent node present
|
||||
//
|
||||
for (cchEnd = strPartialPath.QueryCCH() - 1; cchEnd > 0; cchEnd--)
|
||||
{
|
||||
if (pszPartialPath[cchEnd] == L'/' || pszPartialPath[cchEnd] == L'\\')
|
||||
{
|
||||
pszPartialPath[cchEnd] = L'\0';
|
||||
|
||||
dwHash = CalcHash(pszPartialPath);
|
||||
if (FindNodeInternal(pszPartialPath, dwHash, &pParentNode))
|
||||
{
|
||||
pszPartialPath[cchEnd] = pszKey[cchEnd];
|
||||
break;
|
||||
}
|
||||
pParentNode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now go ahead and add the rest of the tree (including our record)
|
||||
//
|
||||
for (; cchEnd <= strPartialPath.QueryCCH(); cchEnd++)
|
||||
{
|
||||
if (pszPartialPath[cchEnd] == L'\0')
|
||||
{
|
||||
dwHash = CalcHash(pszPartialPath);
|
||||
hr = AddNodeInternal(
|
||||
pszPartialPath,
|
||||
dwHash,
|
||||
(cchEnd == strPartialPath.QueryCCH()) ? pRecord : NULL,
|
||||
pParentNode,
|
||||
&pParentNode);
|
||||
if (FAILED(hr) &&
|
||||
hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pszPartialPath[cchEnd] = pszKey[cchEnd];
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
_tableLock.SharedRelease();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RehashTableIfNeeded();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::DeleteNodeInternal(
|
||||
TREE_HASH_NODE<_Record> ** ppNextPointer,
|
||||
TREE_HASH_NODE<_Record> * pNode
|
||||
)
|
||||
/*++
|
||||
pNode is the node to be deleted
|
||||
ppNextPointer is the pointer to the previous node's next pointer pointing
|
||||
to this node
|
||||
|
||||
This function should be called under write-lock
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// First remove this node from hash table
|
||||
//
|
||||
*ppNextPointer = pNode->_pNext;
|
||||
|
||||
//
|
||||
// Now fixup parent
|
||||
//
|
||||
if (pNode->_pParentNode != NULL)
|
||||
{
|
||||
ppNextPointer = &pNode->_pParentNode->_pFirstChild;
|
||||
while (*ppNextPointer != pNode)
|
||||
{
|
||||
ppNextPointer = &(*ppNextPointer)->_pNextSibling;
|
||||
}
|
||||
*ppNextPointer = pNode->_pNextSibling;
|
||||
}
|
||||
|
||||
//
|
||||
// Now remove all children recursively
|
||||
//
|
||||
TREE_HASH_NODE<_Record> *pChild = pNode->_pFirstChild;
|
||||
TREE_HASH_NODE<_Record> *pNextChild;
|
||||
while (pChild != NULL)
|
||||
{
|
||||
pNextChild = pChild->_pNextSibling;
|
||||
|
||||
ppNextPointer = _ppBuckets + (pChild->_dwHash % _nBuckets);
|
||||
while (*ppNextPointer != pChild)
|
||||
{
|
||||
ppNextPointer = &(*ppNextPointer)->_pNext;
|
||||
}
|
||||
pChild->_pParentNode = NULL;
|
||||
DeleteNodeInternal(ppNextPointer, pChild);
|
||||
|
||||
pChild = pNextChild;
|
||||
}
|
||||
|
||||
DeleteNode(pNode);
|
||||
_nItems--;
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::DeleteKey(
|
||||
PCWSTR pszKey
|
||||
)
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
|
||||
DWORD dwHash = CalcHash(pszKey);
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
if (FindNodeInternal(pszKey, dwHash, &pNode, &ppPreviousNodeNextPointer))
|
||||
{
|
||||
DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::DeleteIf(
|
||||
PFN_DELETE_IF pfnDeleteIf,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
TREE_HASH_NODE<_Record> **ppPreviousNodeNextPointer;
|
||||
BOOL fDelete;
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
ppPreviousNodeNextPointer = _ppBuckets + i;
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
while (pNode != NULL)
|
||||
{
|
||||
//
|
||||
// Non empty nodes deleted based on DeleteIf, empty nodes deleted
|
||||
// if they have no children
|
||||
//
|
||||
fDelete = FALSE;
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
if (pfnDeleteIf(pNode->_pRecord, pvContext))
|
||||
{
|
||||
fDelete = TRUE;
|
||||
}
|
||||
}
|
||||
else if (pNode->_pFirstChild == NULL)
|
||||
{
|
||||
fDelete = TRUE;
|
||||
}
|
||||
|
||||
if (fDelete)
|
||||
{
|
||||
if (pNode->_pFirstChild == NULL)
|
||||
{
|
||||
DeleteNodeInternal(ppPreviousNodeNextPointer, pNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
DereferenceRecord(pNode->_pRecord);
|
||||
pNode->_pRecord = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ppPreviousNodeNextPointer = &pNode->_pNext;
|
||||
}
|
||||
|
||||
pNode = *ppPreviousNodeNextPointer;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::Apply(
|
||||
PFN_APPLY pfnApply,
|
||||
PVOID pvContext
|
||||
)
|
||||
{
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
|
||||
_tableLock.SharedAcquire();
|
||||
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
if (pNode->_pRecord != NULL)
|
||||
{
|
||||
pfnApply(pNode->_pRecord, pvContext);
|
||||
}
|
||||
|
||||
pNode = pNode->_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
_tableLock.SharedRelease();
|
||||
}
|
||||
|
||||
template <class _Record>
|
||||
VOID
|
||||
TREE_HASH_TABLE<_Record>::RehashTableIfNeeded(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
TREE_HASH_NODE<_Record> **ppBuckets;
|
||||
DWORD nBuckets;
|
||||
TREE_HASH_NODE<_Record> *pNode;
|
||||
TREE_HASH_NODE<_Record> *pNextNode;
|
||||
TREE_HASH_NODE<_Record> **ppNextPointer;
|
||||
TREE_HASH_NODE<_Record> *pNewNextNode;
|
||||
DWORD nNewBuckets;
|
||||
|
||||
//
|
||||
// If number of items has become too many, we will double the hash table
|
||||
// size (we never reduce it however)
|
||||
//
|
||||
if (_nItems <= PRIME::GetPrime(2*_nBuckets))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_tableLock.ExclusiveAcquire();
|
||||
|
||||
nNewBuckets = PRIME::GetPrime(2*_nBuckets);
|
||||
|
||||
if (_nItems <= nNewBuckets)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
nBuckets = nNewBuckets;
|
||||
if (nBuckets >= 0xffffffff/sizeof(TREE_HASH_NODE<_Record> *))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
ppBuckets = (TREE_HASH_NODE<_Record> **)HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
nBuckets*sizeof(TREE_HASH_NODE<_Record> *));
|
||||
if (ppBuckets == NULL)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Take out nodes from the old hash table and insert in the new one, make
|
||||
// sure to keep the hashes in increasing order
|
||||
//
|
||||
for (DWORD i=0; i<_nBuckets; i++)
|
||||
{
|
||||
pNode = _ppBuckets[i];
|
||||
while (pNode != NULL)
|
||||
{
|
||||
pNextNode = pNode->_pNext;
|
||||
|
||||
ppNextPointer = ppBuckets + (pNode->_dwHash % nBuckets);
|
||||
pNewNextNode = *ppNextPointer;
|
||||
while (pNewNextNode != NULL &&
|
||||
pNewNextNode->_dwHash <= pNode->_dwHash)
|
||||
{
|
||||
ppNextPointer = &pNewNextNode->_pNext;
|
||||
pNewNextNode = pNewNextNode->_pNext;
|
||||
}
|
||||
pNode->_pNext = pNewNextNode;
|
||||
*ppNextPointer = pNode;
|
||||
|
||||
pNode = pNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, _ppBuckets);
|
||||
_ppBuckets = ppBuckets;
|
||||
_nBuckets = nBuckets;
|
||||
ppBuckets = NULL;
|
||||
|
||||
Finished:
|
||||
|
||||
_tableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Web.Utility
|
||||
{
|
||||
internal static class MySqlConnector
|
||||
{
|
||||
public static string[] HardCodedAssemblyVersions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=6.4.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=6.3.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=6.2.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=6.0.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=6.0.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=5.2.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
"MySql.Data, Version=5.2.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Security;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.Web.Management.PInvoke.AdvApi32
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct TOKEN_PRIVILEGES
|
||||
{
|
||||
public UInt32 PrivilegeCount;
|
||||
public long Luid;
|
||||
public UInt32 Attributes;
|
||||
}
|
||||
|
||||
internal enum TOKEN_INFORMATION_CLASS
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_USER structure that contains the user account of the token.
|
||||
/// </summary>
|
||||
TokenUser = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token.
|
||||
/// </summary>
|
||||
TokenGroups,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token.
|
||||
/// </summary>
|
||||
TokenPrivileges,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects.
|
||||
/// </summary>
|
||||
TokenOwner,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects.
|
||||
/// </summary>
|
||||
TokenPrimaryGroup,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects.
|
||||
/// </summary>
|
||||
TokenDefaultDacl,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information.
|
||||
/// </summary>
|
||||
TokenSource,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token.
|
||||
/// </summary>
|
||||
TokenType,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails.
|
||||
/// </summary>
|
||||
TokenImpersonationLevel,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics.
|
||||
/// </summary>
|
||||
TokenStatistics,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token.
|
||||
/// </summary>
|
||||
TokenRestrictedSids,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token.
|
||||
/// </summary>
|
||||
TokenSessionId,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token.
|
||||
/// </summary>
|
||||
TokenGroupsAndPrivileges,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
TokenSessionReference,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag.
|
||||
/// </summary>
|
||||
TokenSandBoxInert,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
TokenAuditPolicy,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_ORIGIN value.
|
||||
/// </summary>
|
||||
TokenOrigin,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token.
|
||||
/// </summary>
|
||||
TokenElevationType,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token.
|
||||
/// </summary>
|
||||
TokenLinkedToken,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated.
|
||||
/// </summary>
|
||||
TokenElevation,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that is nonzero if the token has ever been filtered.
|
||||
/// </summary>
|
||||
TokenHasRestrictions,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token.
|
||||
/// </summary>
|
||||
TokenAccessInformation,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token.
|
||||
/// </summary>
|
||||
TokenVirtualizationAllowed,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token.
|
||||
/// </summary>
|
||||
TokenVirtualizationEnabled,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.
|
||||
/// </summary>
|
||||
TokenIntegrityLevel,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set.
|
||||
/// </summary>
|
||||
TokenUIAccess,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy.
|
||||
/// </summary>
|
||||
TokenMandatoryPolicy,
|
||||
|
||||
/// <summary>
|
||||
/// The buffer receives the token's logon security identifier (SID).
|
||||
/// </summary>
|
||||
TokenLogonSid,
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value for this enumeration
|
||||
/// </summary>
|
||||
MaxTokenInfoClass
|
||||
}
|
||||
|
||||
internal enum TOKEN_ELEVATION_TYPE
|
||||
{
|
||||
TokenElevationTypeDefault = 1,
|
||||
TokenElevationTypeFull,
|
||||
TokenElevationTypeLimited
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum AccessTokenRights : uint
|
||||
{
|
||||
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
|
||||
STANDARD_RIGHTS_READ = 0x00020000,
|
||||
TOKEN_ASSIGN_PRIMARY = 0x0001,
|
||||
TOKEN_DUPLICATE = 0x0002,
|
||||
TOKEN_IMPERSONATE = 0x0004,
|
||||
TOKEN_QUERY = 0x0008,
|
||||
TOKEN_QUERY_SOURCE = 0x0010,
|
||||
TOKEN_ADJUST_PRIVILEGES = 0x0020,
|
||||
TOKEN_ADJUST_GROUPS = 0x0040,
|
||||
TOKEN_ADJUST_DEFAULT = 0x0080,
|
||||
TOKEN_ADJUST_SESSIONID = 0x0100,
|
||||
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY,
|
||||
TOKEN_ALL_ACCESS =
|
||||
STANDARD_RIGHTS_REQUIRED |
|
||||
TOKEN_ASSIGN_PRIMARY |
|
||||
TOKEN_DUPLICATE |
|
||||
TOKEN_IMPERSONATE |
|
||||
TOKEN_QUERY |
|
||||
TOKEN_QUERY_SOURCE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT |
|
||||
TOKEN_ADJUST_SESSIONID
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
private const String ADVAPI32 = "advapi32.dll";
|
||||
|
||||
// TODO: Should be moved into enums?
|
||||
internal const int READ_CONTROL = 0x00020000;
|
||||
internal const int SYNCHRONIZE = 0x00100000;
|
||||
internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
|
||||
internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
|
||||
|
||||
internal const int KEY_QUERY_VALUE = 0x0001;
|
||||
internal const int KEY_SET_VALUE = 0x0002;
|
||||
internal const int KEY_CREATE_SUB_KEY = 0x0004;
|
||||
internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
|
||||
internal const int KEY_NOTIFY = 0x0010;
|
||||
|
||||
internal const int KEY_READ = ((STANDARD_RIGHTS_READ |
|
||||
KEY_QUERY_VALUE |
|
||||
KEY_ENUMERATE_SUB_KEYS |
|
||||
KEY_NOTIFY)
|
||||
&
|
||||
(~SYNCHRONIZE));
|
||||
|
||||
internal const int KEY_WRITE = ((STANDARD_RIGHTS_WRITE |
|
||||
KEY_SET_VALUE |
|
||||
KEY_CREATE_SUB_KEY)
|
||||
&
|
||||
(~SYNCHRONIZE));
|
||||
|
||||
internal const int KEY_WOW64_64KEY = 0x0100;
|
||||
internal const int KEY_WOW64_32KEY = 0x0200;
|
||||
|
||||
internal const int ERROR_MORE_DATA = 0xEA;
|
||||
internal const int ERROR_ACCESS_DENIED = 0x5;
|
||||
|
||||
internal const int REG_OPTION_NON_VOLATILE = 0x0000; // (default) keys are persisted beyond reboot/unload
|
||||
internal const int REG_OPTION_VOLATILE = 0x0001; // All keys created by the function are volatile
|
||||
internal const int REG_OPTION_CREATE_LINK = 0x0002; // They key is a symbolic link
|
||||
internal const int REG_OPTION_BACKUP_RESTORE = 0x0004; // Use SE_BACKUP_NAME process special privileges
|
||||
internal const int REG_NONE = 0; // No value type
|
||||
internal const int REG_SZ = 1; // Unicode nul terminated string
|
||||
internal const int REG_EXPAND_SZ = 2; // Unicode nul terminated string
|
||||
internal const int REG_BINARY = 3; // Free form binary
|
||||
internal const int REG_DWORD = 4; // 32-bit number
|
||||
internal const int REG_DWORD_LITTLE_ENDIAN = 4; // 32-bit number (same as REG_DWORD)
|
||||
internal const int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
|
||||
internal const int REG_LINK = 6; // Symbolic Link (unicode)
|
||||
internal const int REG_MULTI_SZ = 7; // Multiple Unicode strings
|
||||
internal const int REG_RESOURCE_LIST = 8; // Resource list in the resource map
|
||||
internal const int REG_FULL_RESOURCE_DESCRIPTOR = 9; // Resource list in the hardware description
|
||||
internal const int REG_RESOURCE_REQUIREMENTS_LIST = 10;
|
||||
internal const int REG_QWORD = 11; // 64-bit number
|
||||
|
||||
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AdjustTokenPrivileges(
|
||||
SafeHandleZeroIsInvalid TokenHandle,
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
bool DisableAllPrivileges,
|
||||
ref TOKEN_PRIVILEGES NewState,
|
||||
int len,
|
||||
IntPtr prev,
|
||||
IntPtr relen);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetTokenInformation(
|
||||
SafeHandleZeroIsInvalid TokenHandle,
|
||||
TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||
HGlobalBuffer TokenInformation,
|
||||
int TokenInformationLength,
|
||||
out int ReturnLength);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool OpenProcessToken(
|
||||
SafeHandleZeroIsInvalid ProcessHandle,
|
||||
AccessTokenRights DesiredAccess,
|
||||
out SafeHandleZeroIsInvalid TokenHandle);
|
||||
|
||||
[DllImport("ADVAPI32.DLL"),
|
||||
SuppressUnmanagedCodeSecurity,
|
||||
ResourceExposure(ResourceScope.None),
|
||||
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
internal static extern int RegCloseKey(IntPtr hKey);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegOpenKeyEx(SafeRegistryHandle hKey, String lpSubKey,
|
||||
int ulOptions, int samDesired, out SafeRegistryHandle hkResult);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
|
||||
int[] lpReserved, ref int lpType, [Out] byte[] lpData,
|
||||
ref int lpcbData);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
|
||||
int[] lpReserved, ref int lpType, ref int lpData,
|
||||
ref int lpcbData);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
|
||||
int[] lpReserved, ref int lpType, ref long lpData,
|
||||
ref int lpcbData);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
|
||||
int[] lpReserved, ref int lpType, [Out] char[] lpData,
|
||||
ref int lpcbData);
|
||||
|
||||
[DllImport(ADVAPI32, CharSet = CharSet.Auto, BestFitMapping = false)]
|
||||
internal static extern int RegQueryValueEx(SafeRegistryHandle hKey, String lpValueName,
|
||||
int[] lpReserved, ref int lpType, StringBuilder lpData,
|
||||
ref int lpcbData);
|
||||
|
||||
public static void EnableShutdownPrivilege()
|
||||
{
|
||||
const int SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
|
||||
|
||||
bool retVal;
|
||||
|
||||
using (SafeHandleZeroIsInvalid hproc = Kernel32.NativeMethods.GetCurrentProcess())
|
||||
{
|
||||
TOKEN_PRIVILEGES tp;
|
||||
SafeHandleZeroIsInvalid htok;
|
||||
retVal = OpenProcessToken(hproc, AccessTokenRights.TOKEN_ADJUST_PRIVILEGES | AccessTokenRights.TOKEN_QUERY, out htok);
|
||||
if (!retVal)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
using (htok)
|
||||
{
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Luid = 0;
|
||||
tp.Attributes = SE_PRIVILEGE_ENABLED;
|
||||
retVal = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
|
||||
if (!retVal)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
|
||||
if (!retVal)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal sealed class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[SecurityCritical]
|
||||
internal SafeRegistryHandle()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle)
|
||||
: base(ownsHandle)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return (Microsoft.Web.Management.PInvoke.AdvApi32.NativeMethods.RegCloseKey(handle) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Any reference to Common.cs should also include Kernel32.cs because
|
||||
// SafeHandleZeroIsInvalid (from Common.cs) uses CloseHandle (from Kernel32.cs)
|
||||
namespace Microsoft.Web.Management.PInvoke
|
||||
{
|
||||
internal enum Win32ErrorCode
|
||||
{
|
||||
ERROR_FILE_NOT_FOUND = 2,
|
||||
ERROR_PATH_NOT_FOUND = 3,
|
||||
ERROR_ACCESS_DENIED = 5,
|
||||
ERROR_INVALID_HANDLE = 6,
|
||||
ERROR_INVALID_DRIVE = 15,
|
||||
ERROR_NO_MORE_FILES = 18,
|
||||
ERROR_NOT_READY = 21,
|
||||
ERROR_SHARING_VIOLATION = 32,
|
||||
ERROR_FILE_EXISTS = 80,
|
||||
ERROR_INVALID_PARAMETER = 87, // 0x57
|
||||
ERROR_INVALID_NAME = 123, // 0x7b
|
||||
ERROR_BAD_PATHNAME = 161,
|
||||
ERROR_ALREADY_EXISTS = 183,
|
||||
ERROR_FILENAME_EXCED_RANGE = 206,
|
||||
ERROR_OPERATION_ABORTED = 995,
|
||||
ELEMENT_NOT_FOUND = 0x490
|
||||
}
|
||||
|
||||
internal static class Extension
|
||||
{
|
||||
public static int AsHRESULT(Win32ErrorCode errorCode)
|
||||
{
|
||||
return (int)((uint)errorCode | 0x80070000);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SafeHandleZeroIsInvalid : SafeHandle
|
||||
{
|
||||
public SafeHandleZeroIsInvalid()
|
||||
: base(IntPtr.Zero, true)
|
||||
{
|
||||
}
|
||||
|
||||
public SafeHandleZeroIsInvalid(IntPtr newHandle)
|
||||
: base(IntPtr.Zero, true)
|
||||
{
|
||||
this.SetHandle(newHandle);
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.handle == IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return Kernel32.NativeMethods.CloseHandle(this.handle);
|
||||
}
|
||||
}
|
||||
|
||||
internal class HGlobalBuffer : SafeHandle
|
||||
{
|
||||
private int _size;
|
||||
|
||||
public HGlobalBuffer(int size)
|
||||
: base(IntPtr.Zero, true)
|
||||
{
|
||||
_size = size;
|
||||
this.handle = Marshal.AllocHGlobal(size);
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
if (!this.IsInvalid)
|
||||
{
|
||||
Marshal.FreeHGlobal(this.handle);
|
||||
this.handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.handle == IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public T GetCopyAs<T>()
|
||||
{
|
||||
return (T)Marshal.PtrToStructure(this.handle, typeof(T));
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly HGlobalBuffer NULL = new HGlobalBuffer(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Web.Utility.PInvoke.Fusion
|
||||
{
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")]
|
||||
internal interface IAssemblyName
|
||||
{
|
||||
[PreserveSig()]
|
||||
int SetProperty(
|
||||
int PropertyId,
|
||||
IntPtr pvProperty,
|
||||
int cbProperty);
|
||||
|
||||
[PreserveSig()]
|
||||
int GetProperty(
|
||||
int PropertyId,
|
||||
IntPtr pvProperty,
|
||||
ref int pcbProperty);
|
||||
|
||||
[PreserveSig()]
|
||||
int Finalize();
|
||||
|
||||
[PreserveSig()]
|
||||
int GetDisplayName(
|
||||
StringBuilder pDisplayName,
|
||||
ref int pccDisplayName,
|
||||
int displayFlags);
|
||||
|
||||
[PreserveSig()]
|
||||
int Reserved(ref Guid guid,
|
||||
Object obj1,
|
||||
Object obj2,
|
||||
String string1,
|
||||
Int64 llFlags,
|
||||
IntPtr pvReserved,
|
||||
int cbReserved,
|
||||
out IntPtr ppv);
|
||||
|
||||
[PreserveSig()]
|
||||
int GetName(
|
||||
ref int pccBuffer,
|
||||
StringBuilder pwzName);
|
||||
|
||||
[PreserveSig()]
|
||||
int GetVersion(
|
||||
out int versionHi,
|
||||
out int versionLow);
|
||||
[PreserveSig()]
|
||||
int IsEqual(
|
||||
IAssemblyName pAsmName,
|
||||
int cmpFlags);
|
||||
|
||||
[PreserveSig()]
|
||||
int Clone(out IAssemblyName pAsmName);
|
||||
}// IAssemblyName
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")]
|
||||
internal interface IAssemblyCache
|
||||
{
|
||||
[PreserveSig()]
|
||||
int UninstallAssembly(
|
||||
int flags,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
string assemblyName,
|
||||
IntPtr refData,
|
||||
out int disposition);
|
||||
|
||||
[PreserveSig()]
|
||||
int QueryAssemblyInfo(
|
||||
int flags,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
string assemblyName,
|
||||
ref AssemblyInfo assemblyInfo);
|
||||
[PreserveSig()]
|
||||
int Reserved(
|
||||
int flags,
|
||||
IntPtr pvReserved,
|
||||
out object ppAsmItem,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
string assemblyName);
|
||||
[PreserveSig()]
|
||||
int Reserved(out object ppAsmScavenger);
|
||||
|
||||
[PreserveSig()]
|
||||
int InstallAssembly(
|
||||
int flags,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
string assemblyFilePath,
|
||||
IntPtr refData);
|
||||
}// IAssemblyCache
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct AssemblyInfo
|
||||
{
|
||||
public int cbAssemblyInfo; // size of this structure for future expansion
|
||||
public int assemblyFlags;
|
||||
public long assemblySizeInKB;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string currentAssemblyPath;
|
||||
public int cchBuf; // size of path buf.
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum AssemblyCacheFlags
|
||||
{
|
||||
GAC = 2,
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("21b8916c-f28e-11d2-a473-00c04f8ef448")]
|
||||
internal interface IAssemblyEnum
|
||||
{
|
||||
[PreserveSig()]
|
||||
int GetNextAssembly(
|
||||
IntPtr pvReserved,
|
||||
out IAssemblyName ppName,
|
||||
int flags);
|
||||
|
||||
[PreserveSig()]
|
||||
int Reset();
|
||||
[PreserveSig()]
|
||||
int Clone(out IAssemblyEnum ppEnum);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum AssemblyNameDisplayFlags
|
||||
{
|
||||
VERSION = 0x01,
|
||||
CULTURE = 0x02,
|
||||
PUBLIC_KEY_TOKEN = 0x04,
|
||||
PROCESSORARCHITECTURE = 0x20,
|
||||
RETARGETABLE = 0x80,
|
||||
|
||||
// This enum might change in the future to include
|
||||
// more attributes.
|
||||
ALL =
|
||||
VERSION
|
||||
| CULTURE
|
||||
| PUBLIC_KEY_TOKEN
|
||||
| PROCESSORARCHITECTURE
|
||||
| RETARGETABLE
|
||||
}
|
||||
|
||||
internal enum CreateAssemblyNameObjectFlags
|
||||
{
|
||||
CANOF_DEFAULT = 0,
|
||||
CANOF_PARSE_DISPLAY_NAME = 1,
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("fusion.dll")]
|
||||
public static extern int CreateAssemblyCache(
|
||||
out IAssemblyCache ppAsmCache,
|
||||
int reserved);
|
||||
|
||||
[DllImport("fusion.dll")]
|
||||
public static extern int CreateAssemblyEnum(
|
||||
out IAssemblyEnum ppEnum,
|
||||
IntPtr pUnkReserved,
|
||||
IAssemblyName pName,
|
||||
AssemblyCacheFlags flags,
|
||||
IntPtr pvReserved);
|
||||
|
||||
[DllImport("fusion.dll")]
|
||||
public static extern int CreateAssemblyNameObject(
|
||||
out IAssemblyName ppAssemblyNameObj,
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
String szAssemblyName,
|
||||
CreateAssemblyNameObjectFlags flags,
|
||||
IntPtr pvReserved);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Any reference to Common.cs should also include Kernel32.cs because
|
||||
// SafeHandleZeroIsInvalid (from Common.cs) uses CloseHandle (from Kernel32.cs)
|
||||
namespace Microsoft.Web.Management.PInvoke.Kernel32
|
||||
{
|
||||
internal enum OSProductType : byte
|
||||
{
|
||||
VER_NT_WORKSTATION = 0x0000001,
|
||||
VER_NT_SERVER = 0x0000003,
|
||||
VER_NT_DOMAIN_CONTROLLER = 0x0000002,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct OSVERSIONINFOEX
|
||||
{
|
||||
public int dwOSVersionInfoSize;
|
||||
public int dwMajorVersion;
|
||||
public int dwMinorVersion;
|
||||
public int dwBuildNumber;
|
||||
public int dwPlatformId;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string szCSDVersion;
|
||||
public short wServicePackMajor;
|
||||
public short wServicePackMinor;
|
||||
public short wSuiteMask;
|
||||
public OSProductType wProductType;
|
||||
public byte wReserved;
|
||||
|
||||
public bool IsServer
|
||||
{
|
||||
get
|
||||
{
|
||||
return
|
||||
wProductType == OSProductType.VER_NT_SERVER ||
|
||||
wProductType == OSProductType.VER_NT_DOMAIN_CONTROLLER;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsClient
|
||||
{
|
||||
get
|
||||
{
|
||||
return
|
||||
wProductType == OSProductType.VER_NT_WORKSTATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
public static OSVERSIONINFOEX GetVersionEx()
|
||||
{
|
||||
OSVERSIONINFOEX osVersionInfo = new OSVERSIONINFOEX();
|
||||
osVersionInfo.dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX));
|
||||
if (!GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
return osVersionInfo;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool CloseHandle(IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "GetVersionEx returns more information")]
|
||||
private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true)]
|
||||
internal static extern SafeHandleZeroIsInvalid GetCurrentProcess();
|
||||
|
||||
// WARNING: Vista+ ONLY
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetProductInfo(uint dwOSMajorVersion, uint dwOSMinorVersion, uint dwSpMajorVersion, uint spMinorVersion, out uint pdwReturnedProductType);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool WritePrivateProfileString(string applicationName, string keyName, string stringValue, string fileName);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,768 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
|
||||
namespace Microsoft.Web.Management.PInvoke.MLang
|
||||
{
|
||||
internal enum HRESULT : uint
|
||||
{
|
||||
S_OK = 0x0,
|
||||
S_FALSE = 0x1,
|
||||
E_FAIL = 0x80004005,
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 4)]
|
||||
public struct __MIDL_IWinTypes_0009
|
||||
{
|
||||
// Fields
|
||||
[FieldOffset(0)]
|
||||
public int hInproc;
|
||||
[FieldOffset(0)]
|
||||
public int hRemote;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct _RemotableHandle
|
||||
{
|
||||
public int fContext;
|
||||
public __MIDL_IWinTypes_0009 u;
|
||||
}
|
||||
|
||||
[ComImport, CoClass(typeof(CMLangConvertCharsetClass)), Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F")]
|
||||
public interface CMLangConvertCharset : IMLangConvertCharset
|
||||
{
|
||||
}
|
||||
|
||||
[ComImport, TypeLibType((short)2), Guid("D66D6F99-CDAA-11D0-B822-00C04FC9B31F"), ClassInterface((short)0)]
|
||||
public class CMLangConvertCharsetClass : IMLangConvertCharset, CMLangConvertCharset
|
||||
{
|
||||
// Methods
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetDestinationCodePage(out uint puiDstCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetProperty(out uint pdwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetSourceCodePage(out uint puiSrcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty);
|
||||
}
|
||||
|
||||
[ComImport, Guid("C04D65CE-B70D-11D0-B188-00AA0038C969"), CoClass(typeof(CMLangStringClass))]
|
||||
public interface CMLangString : IMLangString
|
||||
{
|
||||
}
|
||||
|
||||
[ComImport, TypeLibType((short)2), Guid("C04D65CF-B70D-11D0-B188-00AA0038C969"), ClassInterface((short)0)]
|
||||
public class CMLangStringClass : IMLangString, CMLangString, IMLangStringWStr, IMLangStringAStr
|
||||
{
|
||||
// Methods
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, [Out, MarshalAs(UnmanagedType.LPStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetWStr([In] int lSrcPos, [In] int lSrcLen, [Out, MarshalAs(UnmanagedType.LPWStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int IMLangStringAStr_GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStr_GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStr_GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStr_SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStr_SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringAStr_Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int IMLangStringWStr_GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStr_GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStr_SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangStringWStr_Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [MarshalAs(UnmanagedType.LPStr)] out string ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [MarshalAs(UnmanagedType.LPWStr)] out string ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetWStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void UnlockAStr([In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void UnlockWStr([In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
}
|
||||
|
||||
[ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), CoClass(typeof(CMultiLanguageClass))]
|
||||
public interface CMultiLanguage : IMultiLanguage
|
||||
{
|
||||
}
|
||||
|
||||
[ComImport, TypeLibType(TypeLibTypeFlags.FCanCreate), ClassInterface(ClassInterfaceType.None), Guid("275C23E2-3747-11D0-9FEA-00AA003F8646")]
|
||||
public class CMultiLanguageClass : IMultiLanguage, CMultiLanguage, IMLangCodePages, IMLangFontLink, IMLangLineBreakConsole, IMultiLanguage2, IMLangFontLink2, IMultiLanguage3
|
||||
{
|
||||
// Methods
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] CMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CodePageToScriptID([In] uint uiCodePage, out byte pSid);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[PreserveSig]
|
||||
public virtual extern HRESULT DetectInputCodepage([In] MLDETECTCP dwFlag, [In] uint dwPrefWinCodePage, [In] ref byte pSrcStr, [In, Out] ref int pcSrcSize, ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectOutboundCodePage([In] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] uint cchWideChar, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern IEnumCodePage EnumCodePages([In] NativeMethods.MIMECONTF grfFlags);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumCodePages([In] uint grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageInfo([In] uint uiCodePage, out MIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out UNICODERANGE pUranges);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766Info([In] uint locale, out RFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out SCRIPFONTINFO pScriptFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink_CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink_CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink_GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink_GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMLangFontLink2_ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage2_IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_DetectInputCodepage([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In] ref sbyte pSrcStr, [In, Out] ref int pcSrcSize, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_EnumCodePages([In] NativeMethods.MIMECONTF grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_SetMimeDBSource([In] MIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IMultiLanguage3_ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetMimeDBSource([In] MIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
}
|
||||
|
||||
[ComImport, Guid("275C23E3-3747-11D0-9FEA-00AA003F8646"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IEnumCodePage
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[PreserveSig]
|
||||
HRESULT Next([In] uint celt, out MIMECPINFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("3DC39D1D-C030-11D0-B81B-00C04FC9B31F")]
|
||||
public interface IEnumRfc1766
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Next([In] uint celt, out RFC1766INFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
|
||||
[ComImport, Guid("AE5F1430-388B-11D2-8380-00C04F8F5DA1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IEnumScript
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Clone([MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnum);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Next([In] uint celt, out SCRIPTINFO rgelt, out uint pceltFetched);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Skip([In] uint celt);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("359F3443-BD4A-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D66D6F98-CDAA-11D0-B822-00C04FC9B31F")]
|
||||
public interface IMLangConvertCharset
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Initialize([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetSourceCodePage(out uint puiSrcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetDestinationCodePage(out uint puiDstCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetProperty(out uint pdwProperty);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversion([In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversionToUnicode([In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DoConversionFromUnicode([In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
}
|
||||
|
||||
[ComImport, Guid("359F3441-BD4A-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss]
|
||||
public interface IMLangFontLink : IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hSrcFont, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr phDestFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ResetFontMapping();
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DCCFC162-2B38-11D2-B7EC-00C04F8F5D9A"), ComConversionLoss]
|
||||
public interface IMLangFontLink2 : IMLangCodePages
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontCodePages([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont, out uint pdwCodePages);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReleaseFont([In, ComAliasName("MultiLanguage.wireHFONT")] ref _RemotableHandle hFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ResetFontMapping();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void MapFont([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In] uint dwCodePages, [In] ushort chSrc, [Out, ComAliasName("MultiLanguage.wireHFONT")] IntPtr pFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFontUnicodeRanges([In, ComAliasName("MultiLanguage.wireHDC")] ref _RemotableHandle hDC, [In, Out] ref uint puiRanges, out UNICODERANGE pUranges);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetScriptFontInfo([In] byte sid, [In] uint dwFlags, [In, Out] ref uint puiFonts, out SCRIPFONTINFO pScriptFont);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CodePageToScriptID([In] uint uiCodePage, out byte pSid);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("F5BE2EE1-BFD7-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangLineBreakConsole
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineML([In, MarshalAs(UnmanagedType.Interface)] CMLangString pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen, [In] int cMinColumns, [In] int cMaxColumns, out int plLineLen, out int plSkipLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineW([In] uint locale, [In] ref ushort pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void BreakLineA([In] uint locale, [In] uint uCodePage, [In] ref sbyte pszSrc, [In] int cchSrc, [In] int cMaxColumns, out int pcchLine, out int pcchSkip);
|
||||
}
|
||||
|
||||
[ComImport, Guid("C04D65CE-B70D-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Sync([In] int fNoAccess);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int GetLength();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("C04D65D2-B70D-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangStringAStr : IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetAStr([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetStrBufA([In] int lDestPos, [In] int lDestLen, [In] uint uCodePage, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufA pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetAStr([In] int lSrcPos, [In] int lSrcLen, [In] uint uCodePageIn, out uint puCodePageOut, [Out, MarshalAs(UnmanagedType.LPStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrBufA([In] int lSrcPos, [In] int lSrcMaxLen, out uint puDestCodePage, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufA ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockAStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] uint uCodePageIn, [In] int cchRequest, out uint puCodePageOut, [MarshalAs(UnmanagedType.LPStr)] out string ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockAStr([In, MarshalAs(UnmanagedType.LPStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
}
|
||||
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss, Guid("D24ACD23-BA72-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangStringBufA
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStatus(out int plFlags, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockBuf([In] ref sbyte pszBuf, [In] int cchOffset, [In] int cchWrite);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Delete([In] int cchOffset, [In] int cchDelete);
|
||||
}
|
||||
|
||||
[ComImport, ComConversionLoss, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D24ACD21-BA72-11D0-B188-00AA0038C969")]
|
||||
public interface IMLangStringBufW
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStatus(out int plFlags, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockBuf([In] int cchOffset, [In] int cchMaxLock, [Out] IntPtr ppszBuf, out int pcchBuf);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockBuf([In] ref ushort pszBuf, [In] int cchOffset, [In] int cchWrite);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Insert([In] int cchOffset, [In] int cchMaxInsert, out int pcchActual);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Delete([In] int cchOffset, [In] int cchDelete);
|
||||
}
|
||||
|
||||
[ComImport, Guid("C04D65D0-B70D-11D0-B188-00AA0038C969"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IMLangStringWStr : IMLangString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetWStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetWStr([In] int lSrcPos, [In] int lSrcLen, [Out, MarshalAs(UnmanagedType.LPWStr)] string pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [MarshalAs(UnmanagedType.LPWStr)] out string ppszDest, out int pcchDest, out int plDestLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnlockWStr([In, MarshalAs(UnmanagedType.LPWStr)] string pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
|
||||
}
|
||||
|
||||
[ComImport, Guid("275C23E1-3747-11D0-9FEA-00AA003F8646"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IMultiLanguage
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageInfo([In] uint uiCodePage, out MIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
IEnumCodePage EnumCodePages([In] NativeMethods.MIMECONTF grfFlags);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumRfc1766([MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766Info([In] uint locale, out RFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset);
|
||||
}
|
||||
|
||||
[ComImport, Guid("DCCFC164-2B38-11D2-B7EC-00C04F8F5D9A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IMultiLanguage2
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfCodePageInfo(out uint pcCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageInfo([In] uint uiCodePage, [In] ushort LangId, out MIMECPINFO pCodePageInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetFamilyCodePage([In] uint uiCodePage, out uint puiFamilyCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumCodePages([In] uint grfFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumCodePage ppEnumCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCharsetInfo([In, MarshalAs(UnmanagedType.BStr)] string Charset, out MIMECSETINFO pCharsetInfo);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsConvertible([In] uint dwSrcEncoding, [In] uint dwDstEncoding);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertString([In, Out] ref uint pdwMode, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In] ref byte pSrcStr, [In, Out] ref uint pcSrcSize, out byte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicode([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringReset();
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766FromLcid([In] uint locale, [MarshalAs(UnmanagedType.BStr)] out string pbstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetLcidFromRfc1766(out uint plocale, [In, MarshalAs(UnmanagedType.BStr)] string bstrRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumRfc1766([In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumRfc1766 ppEnumRfc1766);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetRfc1766Info([In] uint locale, [In] ushort LangId, out RFC1766INFO pRfc1766Info);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void CreateConvertCharset([In] uint uiSrcCodePage, [In] uint uiDstCodePage, [In] uint dwProperty, [MarshalAs(UnmanagedType.Interface)] out CMLangConvertCharset ppMLangConvertCharset);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringInIStream([In, Out] ref uint pdwMode, [In] uint dwFlag, [In] ref ushort lpFallBack, [In] uint dwSrcEncoding, [In] uint dwDstEncoding, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmOut);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringToUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref sbyte pSrcStr, [In, Out] ref uint pcSrcSize, out ushort pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ConvertStringFromUnicodeEx([In, Out] ref uint pdwMode, [In] uint dwEncoding, [In] ref ushort pSrcStr, [In, Out] ref uint pcSrcSize, out sbyte pDstStr, [In, Out] ref uint pcDstSize, [In] uint dwFlag, [In] ref ushort lpFallBack);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectCodepageInIStream([In] uint dwFlag, [In] uint dwPrefWinCodePage, [In, MarshalAs(UnmanagedType.Interface)] IStream pstmIn, out DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[PreserveSig]
|
||||
HRESULT DetectInputCodepage([In] MLDETECTCP dwFlag, [In] uint dwPrefWinCodePage, [In] ref byte pSrcStr, [In, Out] ref int pcSrcSize, [In, Out] ref DetectEncodingInfo lpEncoding, [In, Out] ref int pnScores);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePage([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCodePageDescription([In] uint uiCodePage, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] int cchWideChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void IsCodePageInstallable([In] uint uiCodePage);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetMimeDBSource([In] MIMECONTF dwSource);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetNumberOfScripts(out uint pnScripts);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void EnumScripts([In] uint dwFlags, [In] ushort LangId, [MarshalAs(UnmanagedType.Interface)] out IEnumScript ppEnumScript);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ValidateCodePageEx([In] uint uiCodePage, [In, ComAliasName("MultiLanguage.wireHWND")] ref _RemotableHandle hwnd, [In] uint dwfIODControl);
|
||||
}
|
||||
|
||||
[ComImport, Guid("4E5868AB-B157-4623-9ACC-6A1D9CAEBE04"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IMultiLanguage3 : IMultiLanguage2
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectOutboundCodePage([In] uint dwFlags, [In, MarshalAs(UnmanagedType.LPWStr)] string lpWideCharStr, [In] uint cchWideChar, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar);
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void DetectOutboundCodePageInIStream([In] uint dwFlags, [In, MarshalAs(UnmanagedType.Interface)] IStream pStrIn, [In] ref uint puiPreferredCodePages, [In] uint nPreferredCodePages, out uint puiDetectedCodePages, [In, Out] ref uint pnDetectedCodePages, [In, MarshalAs(UnmanagedType.LPWStr)] string lpSpecialChar);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct DetectEncodingInfo
|
||||
{
|
||||
public uint nLangID;
|
||||
public uint nCodePage;
|
||||
public int nDocPercent;
|
||||
public int nConfidence;
|
||||
}
|
||||
|
||||
public enum MIMECONTF
|
||||
{
|
||||
MIMECONTF_BROWSER = 2,
|
||||
MIMECONTF_EXPORT = 0x400,
|
||||
MIMECONTF_IMPORT = 8,
|
||||
MIMECONTF_MAILNEWS = 1,
|
||||
MIMECONTF_MIME_IE4 = 0x10000000,
|
||||
MIMECONTF_MIME_LATEST = 0x20000000,
|
||||
MIMECONTF_MIME_REGISTRY = 0x40000000,
|
||||
MIMECONTF_MINIMAL = 4,
|
||||
MIMECONTF_PRIVCONVERTER = 0x10000,
|
||||
MIMECONTF_SAVABLE_BROWSER = 0x200,
|
||||
MIMECONTF_SAVABLE_MAILNEWS = 0x100,
|
||||
MIMECONTF_VALID = 0x20000,
|
||||
MIMECONTF_VALID_NLS = 0x40000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
|
||||
public struct MIMECPINFO
|
||||
{
|
||||
public uint dwFlags;
|
||||
public uint uiCodePage;
|
||||
public uint uiFamilyCodePage;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
|
||||
public string wszDescription;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
|
||||
public string wszWebCharset;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
|
||||
public string wszHeaderCharset;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
|
||||
public string wszBodyCharset;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
||||
public string wszFixedWidthFont;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
||||
public string wszProportionalFont;
|
||||
public byte bGDICharset;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct MIMECSETINFO
|
||||
{
|
||||
public uint uiCodePage;
|
||||
public uint uiInternetEncoding;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
|
||||
public ushort[] wszCharset;
|
||||
}
|
||||
|
||||
public enum MLSTR_FLAGS
|
||||
{
|
||||
MLSTR_READ = 1,
|
||||
MLSTR_WRITE = 2
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct RFC1766INFO
|
||||
{
|
||||
public uint lcid;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public ushort[] wszRfc1766;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszLocaleName;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct SCRIPFONTINFO
|
||||
{
|
||||
public long scripts;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszFont;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct SCRIPTINFO
|
||||
{
|
||||
public byte ScriptId;
|
||||
public uint uiCodePage;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x30)]
|
||||
public ushort[] wszDescription;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszFixedWidthFont;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public ushort[] wszProportionalFont;
|
||||
}
|
||||
|
||||
public enum MLDETECTCP
|
||||
{
|
||||
MLDETECTCP_NONE = 0,
|
||||
MLDETECTCP_7BIT = 1,
|
||||
MLDETECTCP_8BIT = 2,
|
||||
MLDETECTCP_DBCS = 4,
|
||||
MLDETECTCP_HTML = 8,
|
||||
MLDETECTCP_NUMBER = 16
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
public struct STATSTG
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pwcsName;
|
||||
public uint type;
|
||||
public ulong cbSize;
|
||||
public System.Runtime.InteropServices.ComTypes.FILETIME mtime;
|
||||
public System.Runtime.InteropServices.ComTypes.FILETIME ctime;
|
||||
public System.Runtime.InteropServices.ComTypes.FILETIME atime;
|
||||
public uint grfMode;
|
||||
public uint grfLocksSupported;
|
||||
public Guid clsid;
|
||||
public uint grfStateBits;
|
||||
public uint reserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct UNICODERANGE
|
||||
{
|
||||
public ushort wcFrom;
|
||||
public ushort wcTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Web.Management.PInvoke.User32
|
||||
{
|
||||
internal enum WindowMessage
|
||||
{
|
||||
PBS_SMOOTH = 0x1,
|
||||
PBS_MARQUEE = 0x8,
|
||||
WM_SETREDRAW = 0xB,
|
||||
PBM_SETMARQUEE = 0x400 + 10,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum ExitWindows : uint
|
||||
{
|
||||
//
|
||||
// ONE of the following five:
|
||||
//
|
||||
LogOff = 0x00,
|
||||
ShutDown = 0x01,
|
||||
Reboot = 0x02,
|
||||
PowerOff = 0x08,
|
||||
RestartApps = 0x40,
|
||||
|
||||
//
|
||||
// plus AT MOST ONE of the following two:
|
||||
//
|
||||
Force = 0x04,
|
||||
ForceIfHung = 0x10,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum ShutdownReason : uint
|
||||
{
|
||||
MajorApplication = 0x00040000,
|
||||
MajorHardware = 0x00010000,
|
||||
MajorLegacyApi = 0x00070000,
|
||||
MajorOperatingSystem = 0x00020000,
|
||||
MajorOther = 0x00000000,
|
||||
MajorPower = 0x00060000,
|
||||
MajorSoftware = 0x00030000,
|
||||
MajorSystem = 0x00050000,
|
||||
|
||||
MinorBlueScreen = 0x0000000F,
|
||||
MinorCordUnplugged = 0x0000000b,
|
||||
MinorDisk = 0x00000007,
|
||||
MinorEnvironment = 0x0000000c,
|
||||
MinorHardwareDriver = 0x0000000d,
|
||||
MinorHotfix = 0x00000011,
|
||||
MinorHung = 0x00000005,
|
||||
MinorInstallation = 0x00000002,
|
||||
MinorMaintenance = 0x00000001,
|
||||
MinorMMC = 0x00000019,
|
||||
MinorNetworkConnectivity = 0x00000014,
|
||||
MinorNetworkCard = 0x00000009,
|
||||
MinorOther = 0x00000000,
|
||||
MinorOtherDriver = 0x0000000e,
|
||||
MinorPowerSupply = 0x0000000a,
|
||||
MinorProcessor = 0x00000008,
|
||||
MinorReconfig = 0x00000004,
|
||||
MinorSecurity = 0x00000013,
|
||||
MinorSecurityFix = 0x00000012,
|
||||
MinorSecurityFixUninstall = 0x00000018,
|
||||
MinorServicePack = 0x00000010,
|
||||
MinorServicePackUninstall = 0x00000016,
|
||||
MinorTermSrv = 0x00000020,
|
||||
MinorUnstable = 0x00000006,
|
||||
MinorUpgrade = 0x00000003,
|
||||
MinorWMI = 0x00000015,
|
||||
|
||||
FlagUserDefined = 0x40000000,
|
||||
FlagPlanned = 0x80000000
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("User32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SendMessage(IntPtr hWnd, WindowMessage msg, int wParam, int lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Web.Management.PInvoke.UxTheme
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("UxTheme.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
|
||||
public extern static void SetWindowTheme(IntPtr hWnd, string textSubAppName, string textSubIdList);
|
||||
|
||||
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, PreserveSig = true)]
|
||||
private static extern int GetCurrentThemeName(StringBuilder pszThemeFileName, int dwMaxNameChars, StringBuilder pszColorBuff, int dwMaxColorChars, StringBuilder pszSizeBuff, int cchMaxSizeChars);
|
||||
|
||||
public static bool TryGetCurrentThemeName(out string themeName, out string color, out string size)
|
||||
{
|
||||
StringBuilder nameBuilder = new StringBuilder(512);
|
||||
StringBuilder colorBuilder = new StringBuilder(512);
|
||||
StringBuilder sizeBuilder = new StringBuilder(512);
|
||||
int hr = GetCurrentThemeName(nameBuilder, nameBuilder.Capacity, colorBuilder, colorBuilder.Capacity, sizeBuilder, sizeBuilder.Capacity);
|
||||
if (hr == 0)
|
||||
{
|
||||
themeName = nameBuilder.ToString();
|
||||
color = colorBuilder.ToString();
|
||||
size = sizeBuilder.ToString();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
themeName = null;
|
||||
color = null;
|
||||
size = null;
|
||||
if (hr != Extension.AsHRESULT(Win32ErrorCode.ELEMENT_NOT_FOUND))
|
||||
{
|
||||
Debug.Fail("GetCurrentThemeName returned: " + hr.ToString());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- UNCOMMENT FOR PSEUDOLOC
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);PSEUDOLOCALIZER_ENABLED</DefineConstants>
|
||||
</PropertyGroup>
|
||||
-->
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,456 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
namespace Microsoft.Web.Utility
|
||||
{
|
||||
#if PSEUDOLOCALIZER_ENABLED || DEBUG
|
||||
|
||||
/// <summary>
|
||||
/// Class that pseudo-localizes resources from a RESX file by intercepting calls to the managed wrapper class.
|
||||
/// </summary>
|
||||
internal static class PseudoLocalizer
|
||||
{
|
||||
private static bool _shouldPseudoLocalize;
|
||||
private static double _plocPaddingLengthRatio;
|
||||
|
||||
static PseudoLocalizer()
|
||||
{
|
||||
_shouldPseudoLocalize = false;
|
||||
int plocLengthPaddingPercentage = 50;
|
||||
#if DEBUG
|
||||
string plocValue = Environment.GetEnvironmentVariable("PSEUDOLOCALIZE");
|
||||
if (!string.IsNullOrEmpty(plocValue))
|
||||
{
|
||||
_shouldPseudoLocalize = true;
|
||||
int.TryParse(plocValue, out plocLengthPaddingPercentage);
|
||||
if (plocLengthPaddingPercentage < 10)
|
||||
{
|
||||
plocLengthPaddingPercentage = 50;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
_plocPaddingLengthRatio = plocLengthPaddingPercentage * 0.01;
|
||||
if (_plocPaddingLengthRatio < 0.1)
|
||||
{
|
||||
DebugTrace("ploc should be at least 10% padded");
|
||||
}
|
||||
|
||||
#if PSEUDOLOCALIZER_ENABLED
|
||||
_shouldPseudoLocalize = true;
|
||||
#endif // PSEUDOLOCALIZER_ENABLED
|
||||
}
|
||||
|
||||
public static bool ShouldPseudoLocalize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _shouldPseudoLocalize;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to use this method instead of tracing/debugging directly otherwise
|
||||
// the application will not be able to disable asserts from the exe.config file.
|
||||
// this is because this code is run very early on in the app before the
|
||||
// default trace listener has had a chance to initialize its settings
|
||||
// correctly
|
||||
private static void DebugTrace(string format, params object[] args)
|
||||
{
|
||||
////only uncomment these lines when actually debugging something
|
||||
////otherwise the application wont be able to toggle the assert ui
|
||||
////if (args == null || args.Length == 0)
|
||||
////{
|
||||
//// Debug.WriteLine(format);
|
||||
////}
|
||||
////else
|
||||
////{
|
||||
//// Debug.WriteLine(format, args);
|
||||
////}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables pseudo-localization on any type that is of the form {AssemblyName}.Resources
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <returns>true if succeeded, false if failed.</returns>
|
||||
public static bool TryEnableAssembly(Assembly assembly)
|
||||
{
|
||||
bool retVal = false;
|
||||
if (assembly != null)
|
||||
{
|
||||
AssemblyName assemblyName = assembly.GetName();
|
||||
string resourceTypeName = assemblyName.Name + ".Resources";
|
||||
try
|
||||
{
|
||||
Type resourceType = assembly.GetType(resourceTypeName, false);
|
||||
if (resourceType != null)
|
||||
{
|
||||
Enable(resourceType);
|
||||
retVal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugTrace("PLOC: no type {0} found in the assembly {1}",
|
||||
resourceTypeName,
|
||||
assembly.FullName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugTrace(ex.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugTrace("assembly should not be null");
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables pseudo-localization for the specified RESX managed wrapper class.
|
||||
/// </summary>
|
||||
/// <param name="resourcesType">Type of the RESX managed wrapper class.</param>
|
||||
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "ResourceManager", Justification = "Name of property.")]
|
||||
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "resourceMan", Justification = "Name of field.")]
|
||||
public static void Enable(Type resourcesType)
|
||||
{
|
||||
if (null == resourcesType)
|
||||
{
|
||||
throw new ArgumentNullException("resourcesType");
|
||||
}
|
||||
|
||||
// Get the ResourceManager property
|
||||
var resourceManagerProperty = resourcesType.GetProperty("ResourceManager", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (null == resourceManagerProperty)
|
||||
{
|
||||
throw new NotSupportedException("RESX managed wrapper class does not contain the expected internal/public static ResourceManager property.");
|
||||
}
|
||||
|
||||
// Get the ResourceManager value (ensures the resourceMan field gets initialized)
|
||||
var resourceManagerValue = resourceManagerProperty.GetValue(null, null) as ResourceManager;
|
||||
if (null == resourceManagerValue)
|
||||
{
|
||||
throw new NotSupportedException("RESX managed wrapper class returned null for the ResourceManager property getter.");
|
||||
}
|
||||
|
||||
// Get the resourceMan field
|
||||
var resourceManField = resourcesType.GetField("resourceMan", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
if (null == resourceManField)
|
||||
{
|
||||
throw new NotSupportedException("RESX managed wrapper class does not contain the expected private static resourceMan field.");
|
||||
}
|
||||
|
||||
// Create a substitute ResourceManager to do the pseudo-localization
|
||||
var resourceManSubstitute = new PseudoLocalizerResourceManager(
|
||||
_plocPaddingLengthRatio,
|
||||
resourceManagerValue.BaseName,
|
||||
resourcesType.Assembly);
|
||||
|
||||
// Replace the resourceMan field value
|
||||
resourceManField.SetValue(null, resourceManSubstitute);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Pseudo-localization for all assemblies that get loaded from the current
|
||||
/// host. Within the assemblie, only types that are of the form {AssemblyName}.Resources
|
||||
/// will get pseudo-localization enabled.
|
||||
/// </summary>
|
||||
public static void EnableAutoPseudoLocalizationFromHostExecutable()
|
||||
{
|
||||
if (ShouldPseudoLocalize)
|
||||
{
|
||||
//set up pseudo-localization for ourselves
|
||||
TryEnableAssembly(Assembly.GetExecutingAssembly());
|
||||
|
||||
//set up pseudo-localization for anything that gets loaded later
|
||||
AppDomain.CurrentDomain.AssemblyLoad +=
|
||||
new AssemblyLoadEventHandler(OnCurrentDomainAssemblyLoad);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PseudoLocalizeString(string str)
|
||||
{
|
||||
return PseudoLocalizerResourceManager.PseudoLocalizeString(
|
||||
_plocPaddingLengthRatio,
|
||||
str);
|
||||
}
|
||||
|
||||
private static void OnCurrentDomainAssemblyLoad(object sender,
|
||||
AssemblyLoadEventArgs args)
|
||||
{
|
||||
Assembly assembly = args.LoadedAssembly;
|
||||
bool isThisMyAssembly;
|
||||
if (!assembly.GlobalAssemblyCache)
|
||||
{
|
||||
isThisMyAssembly = true;
|
||||
}
|
||||
else if (assembly.FullName.StartsWith("Microsoft.Web",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
isThisMyAssembly = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isThisMyAssembly = false;
|
||||
}
|
||||
|
||||
if (isThisMyAssembly)
|
||||
{
|
||||
TryEnableAssembly(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class that overrides default ResourceManager behavior by pseudo-localizing its content.
|
||||
/// </summary>
|
||||
private class PseudoLocalizerResourceManager : ResourceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores a Dictionary for character translations.
|
||||
/// </summary>
|
||||
private static Dictionary<char, char> _translations = CreateTranslationsMap();
|
||||
|
||||
private static Dictionary<char, char> CreateTranslationsMap()
|
||||
{
|
||||
// Map standard "English" characters to similar-looking counterparts from other languages
|
||||
Dictionary<char, char> translations = new Dictionary<char, char>
|
||||
{
|
||||
{ 'a', 'ä' },
|
||||
{ 'b', 'ƃ' },
|
||||
{ 'c', 'č' },
|
||||
{ 'd', 'ƌ' },
|
||||
{ 'e', 'ë' },
|
||||
{ 'f', 'ƒ' },
|
||||
{ 'g', 'ğ' },
|
||||
{ 'h', 'ħ' },
|
||||
{ 'i', 'ï' },
|
||||
{ 'j', 'ĵ' },
|
||||
{ 'k', 'ƙ' },
|
||||
{ 'l', 'ł' },
|
||||
{ 'm', 'ɱ' },
|
||||
{ 'n', 'ň' },
|
||||
{ 'o', 'ö' },
|
||||
{ 'p', 'þ' },
|
||||
{ 'q', 'ɋ' },
|
||||
{ 'r', 'ř' },
|
||||
{ 's', 'š' },
|
||||
{ 't', 'ŧ' },
|
||||
{ 'u', 'ü' },
|
||||
{ 'v', 'ṽ' },
|
||||
{ 'w', 'ŵ' },
|
||||
{ 'x', 'ӿ' },
|
||||
{ 'y', 'ŷ' },
|
||||
{ 'z', 'ž' },
|
||||
{ 'A', 'Ä' },
|
||||
{ 'B', 'Ɓ' },
|
||||
{ 'C', 'Č' },
|
||||
{ 'D', 'Đ' },
|
||||
{ 'E', 'Ë' },
|
||||
{ 'F', 'Ƒ' },
|
||||
{ 'G', 'Ğ' },
|
||||
{ 'H', 'Ħ' },
|
||||
{ 'I', 'Ï' },
|
||||
{ 'J', 'Ĵ' },
|
||||
{ 'K', 'Ҟ' },
|
||||
{ 'L', 'Ł' },
|
||||
{ 'M', 'Ӎ' },
|
||||
{ 'N', 'Ň' },
|
||||
{ 'O', 'Ö' },
|
||||
{ 'P', 'Ҏ' },
|
||||
{ 'Q', 'Ǫ' },
|
||||
{ 'R', 'Ř' },
|
||||
{ 'S', 'Š' },
|
||||
{ 'T', 'Ŧ' },
|
||||
{ 'U', 'Ü' },
|
||||
{ 'V', 'Ṽ' },
|
||||
{ 'W', 'Ŵ' },
|
||||
{ 'X', 'Ӿ' },
|
||||
{ 'Y', 'Ŷ' },
|
||||
{ 'Z', 'Ž' },
|
||||
};
|
||||
|
||||
return translations;
|
||||
}
|
||||
|
||||
private double _paddingLengthRatio;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PseudoLocalizerResourceManager class.
|
||||
/// </summary>
|
||||
/// <param name="baseName">The root name of the resource file without its extension but including any fully qualified namespace name.</param>
|
||||
/// <param name="assembly">The main assembly for the resources.</param>
|
||||
public PseudoLocalizerResourceManager(double paddingLengthRatio,
|
||||
string baseName,
|
||||
Assembly assembly)
|
||||
: base(baseName, assembly)
|
||||
{
|
||||
_paddingLengthRatio = paddingLengthRatio;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the specified String resource.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the resource to get.</param>
|
||||
/// <returns>The value of the resource localized for the caller's current culture settings.</returns>
|
||||
public override string GetString(string name)
|
||||
{
|
||||
return PseudoLocalizeString(base.GetString(name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the String resource localized for the specified culture.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the resource to get.</param>
|
||||
/// <param name="culture">The CultureInfo object that represents the culture for which the resource is localized.</param>
|
||||
/// <returns>The value of the resource localized for the specified culture.</returns>
|
||||
public override string GetString(string name, CultureInfo culture)
|
||||
{
|
||||
return PseudoLocalizeString(base.GetString(name, culture));
|
||||
}
|
||||
|
||||
private string PseudoLocalizeString(string str)
|
||||
{
|
||||
return PseudoLocalizeString(_paddingLengthRatio, str);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pseudo-localizes a string.
|
||||
/// </summary>
|
||||
/// <param name="str">Input string.</param>
|
||||
/// <returns>Pseudo-localized string.</returns>
|
||||
internal static string PseudoLocalizeString(double paddingLengthRatio, string str)
|
||||
{
|
||||
const string minprefix = "[";
|
||||
const string minsuffix = "]";
|
||||
|
||||
// Create a new string with the "translated" values of each character
|
||||
var translatedChars = new char[str.Length];
|
||||
if (IsXamlString(str))
|
||||
{
|
||||
DoCaseTranslation(str, translatedChars);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoFunkyCharacterTranslation(str, translatedChars);
|
||||
}
|
||||
|
||||
string mungedString = new string(translatedChars);
|
||||
|
||||
int padLengthPerSide = GetPaddingLengthPerSide(
|
||||
str.Length,
|
||||
paddingLengthRatio,
|
||||
minprefix.Length + minsuffix.Length);
|
||||
|
||||
string extraPadding = new string('=', padLengthPerSide);
|
||||
string finalString = string.Concat(minprefix, extraPadding, mungedString, extraPadding, minsuffix);
|
||||
|
||||
return finalString;
|
||||
}
|
||||
|
||||
private static int GetPaddingLengthPerSide(int originalStringLength, double paddingRatio, int minPadLength)
|
||||
{
|
||||
int padLengthPerSide;
|
||||
double exactTotalPadding = (originalStringLength * paddingRatio);
|
||||
padLengthPerSide = (int)(exactTotalPadding + 1) / 2;
|
||||
if (padLengthPerSide < 1)
|
||||
{
|
||||
padLengthPerSide = 1;
|
||||
}
|
||||
|
||||
return padLengthPerSide;
|
||||
}
|
||||
|
||||
private static void DoCaseTranslation(string str, char[] translatedChars)
|
||||
{
|
||||
bool inXamlTag = false;
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
var c = str[i];
|
||||
|
||||
if (inXamlTag)
|
||||
{
|
||||
translatedChars[i] = c;
|
||||
if (c == '>')
|
||||
{
|
||||
inXamlTag = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
translatedChars[i] = (i % 2) == 0 ? char.ToUpper(c) : char.ToLower(c);
|
||||
if (c == '<' && str.IndexOf('>', i) > -1)
|
||||
{
|
||||
inXamlTag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoFunkyCharacterTranslation(string str, char[] translatedChars)
|
||||
{
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
var c = str[i];
|
||||
translatedChars[i] = _translations.ContainsKey(c) ? _translations[c] : c;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsXamlString(string str)
|
||||
{
|
||||
// check if this string has a '<' followed by a '>' and assume it's a xaml string if so
|
||||
int lessThanIndex = str.IndexOf('<');
|
||||
if (lessThanIndex > -1)
|
||||
{
|
||||
if (str.IndexOf('>', lessThanIndex) > -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Dummy class needed to keep the public interface be identical in debug and retail builds
|
||||
/// </summary>
|
||||
internal static class PseudoLocalizer
|
||||
{
|
||||
public static bool ShouldPseudoLocalize
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryEnableAssembly(Assembly assembly)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Enable(Type resourcesType)
|
||||
{
|
||||
}
|
||||
|
||||
public static void EnableAutoPseudoLocalizationFromHostExecutable()
|
||||
{
|
||||
}
|
||||
|
||||
public static string PseudoLocalizeString(string str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.WebMatrix.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// This AuthenticationModule implements basic authentication but uses UTF8 Encoding to support international characters.
|
||||
/// Unfortunately the System.Net implementation uses the Default encoding which breaks with them.
|
||||
/// </summary>
|
||||
internal class AuthenticationModule : IAuthenticationModule
|
||||
{
|
||||
private const string AuthenticationTypeName = "Basic";
|
||||
private static AuthenticationModule _module = null;
|
||||
private static object _lock = new object();
|
||||
|
||||
public static void InstantiateIfNeeded()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_module == null)
|
||||
{
|
||||
_module = new AuthenticationModule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AuthenticationModule()
|
||||
{
|
||||
AuthenticationManager.Unregister(AuthenticationTypeName);
|
||||
AuthenticationManager.Register(this);
|
||||
}
|
||||
|
||||
string IAuthenticationModule.AuthenticationType
|
||||
{
|
||||
get
|
||||
{
|
||||
return AuthenticationTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
bool IAuthenticationModule.CanPreAuthenticate
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Authorization IAuthenticationModule.Authenticate(string challenge, WebRequest request, ICredentials credentials)
|
||||
{
|
||||
HttpWebRequest httpWebRequest = request as HttpWebRequest;
|
||||
if (httpWebRequest == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify that the challenge is a Basic Challenge
|
||||
if (challenge == null || !challenge.StartsWith(AuthenticationTypeName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Authenticate(httpWebRequest, credentials);
|
||||
}
|
||||
|
||||
Authorization IAuthenticationModule.PreAuthenticate(WebRequest request, ICredentials credentials)
|
||||
{
|
||||
HttpWebRequest httpWebRequest = request as HttpWebRequest;
|
||||
|
||||
if (httpWebRequest == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Authenticate(httpWebRequest, credentials);
|
||||
}
|
||||
|
||||
private Authorization Authenticate(HttpWebRequest httpWebRequest, ICredentials credentials)
|
||||
{
|
||||
if (credentials == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the username and password from the credentials
|
||||
NetworkCredential nc = credentials.GetCredential(httpWebRequest.RequestUri, AuthenticationTypeName);
|
||||
if (nc == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ICredentialPolicy policy = AuthenticationManager.CredentialPolicy;
|
||||
if (policy != null && !policy.ShouldSendCredential(httpWebRequest.RequestUri, httpWebRequest, nc, this))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string domain = nc.Domain;
|
||||
|
||||
string basicTicket = (!String.IsNullOrEmpty(domain) ? (domain + "\\") : "") + nc.UserName + ":" + nc.Password;
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(basicTicket);
|
||||
|
||||
string header = AuthenticationTypeName + " " + Convert.ToBase64String(bytes);
|
||||
return new Authorization(header, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.WebMatrix.Utility
|
||||
{
|
||||
internal class ExceptionHelper
|
||||
{
|
||||
private const int PublicKeyTokenLength = 8;
|
||||
|
||||
/// <summary>
|
||||
/// This will return a list of assemblies that are present in the call stack for
|
||||
/// the input exception. The list CAN have duplicates.
|
||||
/// </summary>
|
||||
/// <param name="exception"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Assembly> GetAssembliesInCallStack(Exception exception)
|
||||
{
|
||||
// an AggregateException might have multiple inner exceptions, so we handle it specially
|
||||
AggregateException aggregateException = exception as AggregateException;
|
||||
if (exception == null)
|
||||
{
|
||||
return Enumerable.Empty<Assembly>();
|
||||
}
|
||||
else if (aggregateException == null)
|
||||
{
|
||||
return GetAssembliesInSingleException(exception).Concat(GetAssembliesInCallStack(exception.InnerException));
|
||||
}
|
||||
else
|
||||
{
|
||||
return aggregateException.Flatten().InnerExceptions.SelectMany(ex => GetAssembliesInCallStack(ex));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Assembly> GetAssembliesInSingleException(Exception exception)
|
||||
{
|
||||
// some exceptions (like AggregateException) don't have an associated stacktrace
|
||||
if (exception != null && exception.StackTrace != null)
|
||||
{
|
||||
StackTrace stackTrace = new StackTrace(exception, false);
|
||||
foreach (StackFrame frame in stackTrace.GetFrames())
|
||||
{
|
||||
// DeclaringType can be null for lambdas created by Reflection.Emit
|
||||
Type declaringType = frame.GetMethod().DeclaringType;
|
||||
if (declaringType != null)
|
||||
{
|
||||
Assembly currentAssembly = declaringType.Assembly;
|
||||
Debug.Assert(currentAssembly != null, "currentAssembly must not be null");
|
||||
if (currentAssembly != null)
|
||||
{
|
||||
yield return currentAssembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Assembly> RemoveAssembliesThatAreIntheGAC(IEnumerable<Assembly> input)
|
||||
{
|
||||
foreach (Assembly assembly in input)
|
||||
{
|
||||
if (!assembly.GlobalAssemblyCache)
|
||||
{
|
||||
yield return assembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<Assembly> RemoveAssembliesThatAreSignedWithToken(IEnumerable<Assembly> input, byte[] publicKeyToken)
|
||||
{
|
||||
Debug.Assert(publicKeyToken.Length == PublicKeyTokenLength, "public key tokens should be 8 bytes");
|
||||
foreach (Assembly assembly in input)
|
||||
{
|
||||
byte[] currentToken = assembly.GetName().GetPublicKeyToken();
|
||||
bool shouldReturn;
|
||||
if (currentToken.Length == 0)
|
||||
{
|
||||
// unsigned assembly
|
||||
shouldReturn = true;
|
||||
}
|
||||
else if (AreTokensTheSame(currentToken, publicKeyToken))
|
||||
{
|
||||
// tokens are the same skip the assembly
|
||||
shouldReturn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// didnt match anything, return it
|
||||
shouldReturn = true;
|
||||
}
|
||||
|
||||
if (shouldReturn)
|
||||
{
|
||||
yield return assembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool AreTokensTheSame(byte[] token1, byte[] token2)
|
||||
{
|
||||
Debug.Assert(
|
||||
token1.Length == PublicKeyTokenLength &&
|
||||
token2.Length == PublicKeyTokenLength,
|
||||
"public key tokens should be 8 bytes");
|
||||
|
||||
for (int i = 0; i < PublicKeyTokenLength; i++)
|
||||
{
|
||||
if (token1[i] != token2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Web.Utility
|
||||
{
|
||||
// need to include <oob>\common\Managed\NativeMethods\Fusion.cs in your project to use this class
|
||||
internal static class GACManagedAccess
|
||||
{
|
||||
public static List<string> GetAssemblyList(string assemblyName)
|
||||
{
|
||||
return GetAssemblyList(assemblyName, true);
|
||||
}
|
||||
|
||||
public static List<string> GetAssemblyList(string assemblyName, bool getPhysicalPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
throw new ArgumentNullException("assemblyName");
|
||||
}
|
||||
|
||||
List<string> assemblyList = new List<string>();
|
||||
using (GacAssembly gacAssembly = new GacAssembly(assemblyName))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (gacAssembly.GetNextAssembly())
|
||||
{
|
||||
if (getPhysicalPath)
|
||||
{
|
||||
using (GACAssemblyCache gacAssemblyCache = new GACAssemblyCache(assemblyName, gacAssembly.FullAssemblyName))
|
||||
{
|
||||
assemblyList.Add(gacAssemblyCache.AssemblyPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assemblyList.Add(gacAssembly.FullAssemblyName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return assemblyList;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GacAssembly : IDisposable
|
||||
{
|
||||
internal GacAssembly(string assemblyName)
|
||||
{
|
||||
_assemblyName = assemblyName;
|
||||
int hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyNameObject(
|
||||
out _fusionName,
|
||||
_assemblyName,
|
||||
PInvoke.Fusion.CreateAssemblyNameObjectFlags.CANOF_PARSE_DISPLAY_NAME,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hResult >= 0)
|
||||
{
|
||||
hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyEnum(
|
||||
out _assemblyEnum,
|
||||
IntPtr.Zero,
|
||||
_fusionName,
|
||||
PInvoke.Fusion.AssemblyCacheFlags.GAC,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (hResult < 0 || _assemblyEnum == null)
|
||||
{
|
||||
throw Marshal.GetExceptionForHR(hResult);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool GetNextAssembly()
|
||||
{
|
||||
int hResult = _assemblyEnum.GetNextAssembly((IntPtr)0, out _fusionName, 0);
|
||||
|
||||
if (hResult < 0 || _fusionName == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal string FullAssemblyName
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sDisplayName = new StringBuilder(1024);
|
||||
int iLen = 1024;
|
||||
|
||||
int hrLocal = _fusionName.GetDisplayName(
|
||||
sDisplayName,
|
||||
ref iLen,
|
||||
(int)PInvoke.Fusion.AssemblyNameDisplayFlags.ALL);
|
||||
|
||||
if (hrLocal < 0)
|
||||
{
|
||||
throw Marshal.GetExceptionForHR(hrLocal);
|
||||
}
|
||||
|
||||
return sDisplayName.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
internal PInvoke.Fusion.IAssemblyName FusionName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fusionName;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PInvoke.Fusion.IAssemblyName tempName = _fusionName;
|
||||
if (tempName != null)
|
||||
{
|
||||
_fusionName = null;
|
||||
Marshal.ReleaseComObject(tempName);
|
||||
}
|
||||
|
||||
PInvoke.Fusion.IAssemblyEnum tempEnum = _assemblyEnum;
|
||||
if (tempEnum != null)
|
||||
{
|
||||
_assemblyEnum = null;
|
||||
Marshal.ReleaseComObject(tempEnum);
|
||||
}
|
||||
}
|
||||
|
||||
private string _assemblyName;
|
||||
private PInvoke.Fusion.IAssemblyEnum _assemblyEnum;
|
||||
private PInvoke.Fusion.IAssemblyName _fusionName;
|
||||
}
|
||||
|
||||
internal class GACAssemblyCache : IDisposable
|
||||
{
|
||||
internal GACAssemblyCache(string assemblyName, string fullAssemblyName)
|
||||
{
|
||||
PInvoke.Fusion.AssemblyInfo aInfo = new PInvoke.Fusion.AssemblyInfo();
|
||||
aInfo.cchBuf = 1024;
|
||||
aInfo.currentAssemblyPath = new string('\0', aInfo.cchBuf);
|
||||
|
||||
int hResult = PInvoke.Fusion.NativeMethods.CreateAssemblyCache(out _assemblyCache, 0);
|
||||
|
||||
if (hResult == 0)
|
||||
{
|
||||
hResult = _assemblyCache.QueryAssemblyInfo(0, fullAssemblyName, ref aInfo);
|
||||
}
|
||||
|
||||
if (hResult != 0)
|
||||
{
|
||||
Marshal.GetExceptionForHR(hResult);
|
||||
}
|
||||
|
||||
_assemblyPath = aInfo.currentAssemblyPath;
|
||||
}
|
||||
|
||||
internal string AssemblyPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _assemblyPath;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PInvoke.Fusion.IAssemblyCache temp = _assemblyCache;
|
||||
if (temp != null)
|
||||
{
|
||||
_assemblyCache = null;
|
||||
Marshal.ReleaseComObject(temp);
|
||||
}
|
||||
}
|
||||
|
||||
private string _assemblyPath;
|
||||
private PInvoke.Fusion.IAssemblyCache _assemblyCache;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Collections;
|
||||
using System.Net;
|
||||
|
||||
namespace Microsoft.Web.Utility
|
||||
{
|
||||
internal static class WebUtility
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="We want to count any error as host doesn't exist")]
|
||||
public static bool IsLocalMachine(string serverName, bool useDns)
|
||||
{
|
||||
if (String.Equals(serverName, Environment.MachineName, StringComparison.CurrentCultureIgnoreCase) ||
|
||||
String.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||
String.Equals(serverName, "127.0.0.1") ||
|
||||
String.Equals(serverName, "::1"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (useDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArrayList serverAddressesList = new ArrayList();
|
||||
ArrayList currentMachineAddressesList = new ArrayList();
|
||||
|
||||
IPAddress ownAddress = IPAddress.Parse("127.0.0.1");
|
||||
|
||||
// All the IP addresses of the hostname specified by the user
|
||||
IPAddress[] serverAddress = Dns.GetHostAddresses(serverName);
|
||||
serverAddressesList.AddRange(serverAddress);
|
||||
|
||||
/// All the IP addresses of the current machine
|
||||
IPAddress[] currentMachineAddress = Dns.GetHostAddresses(Environment.MachineName);
|
||||
currentMachineAddressesList.AddRange(currentMachineAddress);
|
||||
|
||||
// The address 127.0.0.1 also refers to the current machine
|
||||
currentMachineAddressesList.Add(ownAddress);
|
||||
|
||||
// If any of the addresses for the current machine is the same
|
||||
// as the address for the hostname specified by the user
|
||||
// then use a local connection
|
||||
foreach (IPAddress address in currentMachineAddressesList)
|
||||
{
|
||||
if (serverAddressesList.Contains(address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If the Dns class throws an exception the host propbably does not
|
||||
// exist so we return false
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Microsoft IIS Common
|
||||
--------------------------------
|
||||
|
||||
The repository contains common resources shared by IIS Out-Of-Band (OOB) products.
|
||||
|
||||
### Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#define RC_VERSION_INTERNAL_NAME "Common.UnitTests\0"
|
||||
#define RC_VERSION_ORIGINAL_FILE_NAME "Common.UnitTests.dll\0"
|
||||
#define RC_VERSION_FILE_DESCRIPTION "Common.UnitTests0"
|
||||
#include <bldver.rc>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "dbgutil.h"
|
||||
#include <stdio.h>
|
||||
|
||||
DECLARE_DEBUG_PRINT_OBJECT( "test" );
|
||||
|
||||
VOID PrintLevel( DWORD level )
|
||||
{
|
||||
DWORD old = DEBUG_FLAGS_VAR;
|
||||
DEBUG_FLAGS_VAR = level;
|
||||
|
||||
DBGPRINTF(( DBG_CONTEXT, "Some Data %d\n", 47 ));
|
||||
DBGINFO(( DBG_CONTEXT, "Some Info %s\n", "info" ));
|
||||
DBGWARN(( DBG_CONTEXT, "Some Info %s\n", "warning" ));
|
||||
DBGERROR(( DBG_CONTEXT, "Some Info %s\n", "error" ));
|
||||
|
||||
DEBUG_FLAGS_VAR = old;
|
||||
}
|
||||
|
||||
|
||||
#pragma managed
|
||||
|
||||
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
public ref class DebugUtilitiesTests
|
||||
{
|
||||
public:
|
||||
|
||||
[ClassInitialize]
|
||||
static void InitializeDebugObjects(TestContext)
|
||||
{
|
||||
CREATE_DEBUG_PRINT_OBJECT;
|
||||
|
||||
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestDbgError()
|
||||
{
|
||||
PrintLevel( DEBUG_FLAGS_ERROR );
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestPrintAny()
|
||||
{
|
||||
PrintLevel( DEBUG_FLAGS_ANY );
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestPrintError()
|
||||
{
|
||||
DBGERROR_HR( E_FAIL );
|
||||
DBGERROR_STATUS( 47 );
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestPrintWarn()
|
||||
{
|
||||
PrintLevel( DEBUG_FLAGS_WARN );
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestPrintInfo()
|
||||
{
|
||||
PrintLevel( DEBUG_FLAGS_INFO );
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "hashtable.h"
|
||||
#include "hashfn.h"
|
||||
#include "my_hash.h"
|
||||
|
||||
VOID
|
||||
CountHash(
|
||||
MY_OBJ * , //pRecord,
|
||||
PVOID pVoid
|
||||
)
|
||||
{
|
||||
DWORD * pActualCount = (DWORD*) pVoid;
|
||||
++(*pActualCount);
|
||||
}
|
||||
|
||||
|
||||
#pragma managed
|
||||
|
||||
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
public ref class HashTableTests
|
||||
{
|
||||
public:
|
||||
|
||||
[TestMethod]
|
||||
void AddTwoRecordsTest()
|
||||
{
|
||||
MY_HASH hash;
|
||||
HRESULT hr;
|
||||
hr = hash.Initialize(32);
|
||||
|
||||
Assert::AreEqual(S_OK, hr, L"Invalid hash table initialization");
|
||||
|
||||
MY_OBJ one(L"one");
|
||||
hr = hash.InsertRecord(&one);
|
||||
Assert::AreEqual(S_OK, hr, L"Cannot add element 'one'");
|
||||
|
||||
MY_OBJ two(L"two");
|
||||
hr = hash.InsertRecord(&two);
|
||||
Assert::AreEqual(S_OK, hr, L"Cannot add element 'two'");
|
||||
|
||||
DWORD ActualCount = 0;
|
||||
hash.Apply(CountHash, &ActualCount);
|
||||
Assert::AreEqual((DWORD)2, ActualCount, L"ActualCount != 2");
|
||||
|
||||
hash.Clear();
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "hybrid_array.h"
|
||||
|
||||
//
|
||||
// Cannot support mixed native/managed code for BUFFER class
|
||||
// because of alignment. We need to run the test as native.
|
||||
//
|
||||
#include <mstest.h>
|
||||
|
||||
|
||||
void HybridArrayTest()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<void *, 32> arrPointers;
|
||||
Assert::AreEqual<SIZE_T>(32, arrPointers.QueryCapacity(), L"Invalid initial length");
|
||||
}
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<int, 2> arrIntegers;
|
||||
int SourceArray[] = {1, 2, 3, 4};
|
||||
hr = arrIntegers.Copy( SourceArray );
|
||||
Assert::AreEqual(S_OK, hr, L"Copy failed.");
|
||||
Assert::AreEqual(_countof(SourceArray), arrIntegers.QueryCapacity());
|
||||
}
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<int, 2> arrIntegers;
|
||||
int* pOriginal = arrIntegers.QueryArray();
|
||||
int SourceArray[] = {1, 2, 3, 4};
|
||||
hr = arrIntegers.Copy( SourceArray );
|
||||
int* pNew = arrIntegers.QueryArray();
|
||||
Assert::AreEqual(S_OK, hr, L"Copy failed.");
|
||||
Assert::AreEqual(_countof(SourceArray), arrIntegers.QueryCapacity(), L"Size should be like source");
|
||||
Assert::AreNotEqual((__int64)pNew, (__int64)pOriginal, L"Pointer should be different");
|
||||
|
||||
Assert::AreEqual(1, arrIntegers[0], L"Index 0 failed.");
|
||||
Assert::AreEqual(2, arrIntegers.QueryItem(1), L"Index 1 failed.");
|
||||
Assert::AreEqual(3, arrIntegers.QueryItem(2), L"Index 2 failed.");
|
||||
Assert::AreEqual(4, arrIntegers[3], L"Index 3 failed.");
|
||||
}
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<int, 2> arrIntegers;
|
||||
hr = arrIntegers.EnsureCapacity(100, false);
|
||||
Assert::AreEqual(S_OK, hr, L"Copy failed.");
|
||||
Assert::AreEqual<SIZE_T>(100, arrIntegers.QueryCapacity());
|
||||
}
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<int, 2> arrIntegers;
|
||||
arrIntegers[0] = 123;
|
||||
arrIntegers[1] = 999;
|
||||
hr = arrIntegers.EnsureCapacity(100, true /*copy previous*/);
|
||||
Assert::AreEqual(S_OK, hr, L"Copy failed.");
|
||||
Assert::AreEqual<SIZE_T>(100, arrIntegers.QueryCapacity());
|
||||
Assert::AreEqual(123, arrIntegers[0], L"Index resize 0 failed.");
|
||||
Assert::AreEqual(999, arrIntegers[1], L"Index resize 1 failed.");
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
HYBRID_ARRAY<int, 2> arrIntegers;
|
||||
arrIntegers[0] = 123;
|
||||
arrIntegers[1] = 999;
|
||||
hr = arrIntegers.EnsureCapacity(100, true /*copy previous*/, true /*trivial assign*/);
|
||||
Assert::AreEqual(S_OK, hr, L"Copy failed.");
|
||||
Assert::AreEqual<SIZE_T>(100, arrIntegers.QueryCapacity());
|
||||
Assert::AreEqual(123, arrIntegers[0], L"Index resize trivial 0 failed.");
|
||||
Assert::AreEqual(999, arrIntegers[1], L"Index resize trivial 1 failed.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma managed
|
||||
|
||||
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
public ref class ArrayTests
|
||||
{
|
||||
public:
|
||||
|
||||
[TestMethod]
|
||||
void HybridArrayTest()
|
||||
{
|
||||
::HybridArrayTest();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
class MY_OBJ
|
||||
{
|
||||
public:
|
||||
MY_OBJ(PCWSTR pstr)
|
||||
: _pstr(pstr)
|
||||
{}
|
||||
|
||||
PCWSTR GetString()
|
||||
{
|
||||
return _pstr;
|
||||
}
|
||||
|
||||
private:
|
||||
PCWSTR _pstr;
|
||||
};
|
||||
|
||||
class MY_HASH : public HASH_TABLE<MY_OBJ,PCWSTR>
|
||||
{
|
||||
public:
|
||||
VOID
|
||||
ReferenceRecord(
|
||||
MY_OBJ * //pRecord
|
||||
)
|
||||
{}
|
||||
|
||||
VOID
|
||||
DereferenceRecord(
|
||||
MY_OBJ * //pRecord
|
||||
)
|
||||
{}
|
||||
|
||||
PCWSTR
|
||||
ExtractKey(
|
||||
MY_OBJ * pRecord
|
||||
)
|
||||
{
|
||||
return pRecord->GetString();
|
||||
}
|
||||
|
||||
DWORD
|
||||
CalcKeyHash(
|
||||
PCWSTR key
|
||||
)
|
||||
{
|
||||
return HashString(key);
|
||||
}
|
||||
|
||||
BOOL
|
||||
EqualKeys(
|
||||
PCWSTR key1,
|
||||
PCWSTR key2
|
||||
)
|
||||
{
|
||||
return (wcscmp(key1, key2) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
void TestHash();
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
// Native-only by default
|
||||
#pragma unmanaged
|
||||
#include <windows.h>
|
||||
|
|
@ -0,0 +1,680 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "buffer.h"
|
||||
#include "stringu.h"
|
||||
#include "stringa.h"
|
||||
|
||||
//
|
||||
// Cannot support mixed native/managed code for BUFFER class
|
||||
// because of alignment. We need to run the test as native.
|
||||
//
|
||||
#include <mstest.h>
|
||||
|
||||
void TestBuffer()
|
||||
{
|
||||
//
|
||||
// 104 == 8 byte size rounded, why is this needed?
|
||||
//
|
||||
STACK_BUFFER( bufStack, 104 );
|
||||
BUFFER bufReg;
|
||||
BUFFER* pBuf = new BUFFER;
|
||||
|
||||
//
|
||||
// QueryPtr
|
||||
//
|
||||
Assert::IsNotNull( bufStack.QueryPtr( ) );
|
||||
Assert::IsNotNull( bufReg.QueryPtr( ) );
|
||||
Assert::IsNotNull( pBuf->QueryPtr( ) );
|
||||
|
||||
//
|
||||
// QuerySize
|
||||
//
|
||||
Assert::IsTrue( 104 == bufStack.QuerySize( ) );
|
||||
Assert::IsTrue( INLINED_BUFFER_LEN == bufReg.QuerySize( ) );
|
||||
Assert::IsTrue( INLINED_BUFFER_LEN == pBuf->QuerySize( ) );
|
||||
|
||||
//
|
||||
// Resize
|
||||
//
|
||||
Assert::IsTrue( bufStack.Resize( 64 ) );
|
||||
Assert::IsTrue( bufReg.Resize( 128) );
|
||||
Assert::IsTrue( pBuf->Resize( 256 ) );
|
||||
|
||||
//
|
||||
// Resize again
|
||||
//
|
||||
Assert::IsTrue( bufStack.Resize( 512, true ) );
|
||||
Assert::IsTrue( bufReg.Resize( 512, true ) );
|
||||
Assert::IsTrue( pBuf->Resize( 512, true ) );
|
||||
|
||||
//
|
||||
// Resize again
|
||||
//
|
||||
Assert::IsTrue( bufStack.Resize( 1024, false ) );
|
||||
Assert::IsTrue( bufReg.Resize( 1024, false ) );
|
||||
Assert::IsTrue( pBuf->Resize( 1024, false ) );
|
||||
|
||||
//
|
||||
// write to mem
|
||||
//
|
||||
ZeroMemory( bufStack.QueryPtr( ), bufStack.QuerySize( ) );
|
||||
ZeroMemory( bufReg.QueryPtr( ), bufReg.QuerySize( ) );
|
||||
ZeroMemory( pBuf->QueryPtr( ), pBuf->QuerySize( ) );
|
||||
|
||||
delete pBuf;
|
||||
}
|
||||
|
||||
void TestStraOverrun()
|
||||
{
|
||||
STACK_STRA( straStack, 3 );
|
||||
wchar_t Input[] = {0x65f6, 0x0};
|
||||
HRESULT hr;
|
||||
|
||||
hr = straStack.CopyW(Input);
|
||||
Assert::IsTrue( SUCCEEDED(hr) );
|
||||
Assert::AreEqual( 3, straStack.QueryCCH(), L"Invalid string length." );
|
||||
Assert::AreEqual( 4, straStack.QuerySizeCCH(), L"Invalid buffer length." );
|
||||
}
|
||||
|
||||
#define LOWER_A_THING L"ä"
|
||||
#define UPPER_A_THING L"Ä"
|
||||
|
||||
void TestStru()
|
||||
{
|
||||
STACK_STRU( struStack, 104 );
|
||||
STRU struReg;
|
||||
wchar_t buf[100];
|
||||
DWORD cbBuf = sizeof( buf );
|
||||
|
||||
//
|
||||
// IsEmpty
|
||||
//
|
||||
Assert::IsTrue( struStack.IsEmpty( ) );
|
||||
Assert::IsTrue( L'\0' == struStack.QueryStr()[0] );
|
||||
Assert::IsTrue( struReg.IsEmpty( ) );
|
||||
|
||||
//
|
||||
// Copy psz
|
||||
// CopyA psz
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy( L"hello" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struReg.CopyA( "hello" ) ) );
|
||||
|
||||
//
|
||||
// Equal
|
||||
//
|
||||
Assert::IsTrue( struStack.Equals( L"hello" ) );
|
||||
Assert::IsTrue( !struStack.Equals( L"goodbye" ) );
|
||||
Assert::IsTrue( !struStack.Equals( L"" ) );
|
||||
|
||||
STRU strHELLO;
|
||||
Assert::IsTrue( SUCCEEDED( strHELLO.Copy( L"HELLO" ) ) );
|
||||
|
||||
Assert::IsTrue( struStack.Equals( &struReg ) );
|
||||
Assert::IsTrue( struStack.Equals( struReg ) );
|
||||
|
||||
Assert::IsTrue( !struStack.Equals( &strHELLO ) );
|
||||
Assert::IsTrue( !struStack.Equals( strHELLO ) );
|
||||
|
||||
Assert::IsTrue( struStack.Equals( &strHELLO, TRUE ) );
|
||||
Assert::IsTrue( struStack.Equals( strHELLO, TRUE ) );
|
||||
|
||||
Assert::IsTrue( struStack.Equals( L"helLO", TRUE ) );
|
||||
|
||||
|
||||
Assert::IsTrue( STRU::Equals( L"Hello", L"Hello" ) );
|
||||
Assert::IsTrue( STRU::Equals( L"Hello", L"Hello", FALSE ) );
|
||||
Assert::IsTrue( STRU::Equals( L"Hello", L"Hello", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRU::Equals( L"hello", L"Hello" ) );
|
||||
Assert::IsFalse( STRU::Equals( L"hello", L"Hello", FALSE ) );
|
||||
Assert::IsTrue( STRU::Equals( L"hello", L"Hello", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRU::Equals( L"hello", L"goodbye" ) );
|
||||
Assert::IsFalse( STRU::Equals( L"hello", L"goodbye", FALSE ) );
|
||||
Assert::IsFalse( STRU::Equals( L"hello", L"goodbye", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRU::Equals( (PCWSTR)NULL, (PCWSTR)NULL ) );
|
||||
Assert::IsFalse( STRU::Equals( L"hello", (PCWSTR)NULL ) );
|
||||
Assert::IsFalse( STRU::Equals( (PCWSTR)NULL, L"hello" ) );
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Query*
|
||||
//
|
||||
Assert::IsTrue( 5 * sizeof( wchar_t ) == struStack.QueryCB( ) );
|
||||
Assert::IsTrue( 5 == struStack.QueryCCH( ) );
|
||||
Assert::IsTrue( 6 <= struStack.QuerySizeCCH( ) );
|
||||
Assert::IsTrue( L'h' == *( struStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// Resize
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struReg.Resize( 7 ) ) );
|
||||
Assert::IsTrue( 7 == struReg.QuerySizeCCH( ) );
|
||||
|
||||
//
|
||||
// SyncWithBuffer
|
||||
//
|
||||
*(struStack.QueryStr() + 5) = L'\0';
|
||||
Assert::AreEqual(S_OK, struStack.SyncWithBuffer( ));
|
||||
Assert::IsTrue( 5 == struStack.QueryCCH( ) );
|
||||
|
||||
//
|
||||
// Reset
|
||||
//
|
||||
struStack.Reset( );
|
||||
Assert::IsTrue( 0 == wcslen( struStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// Append*
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Append( L"hell" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Append( L"o", 1 ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Append( &struReg ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struStack.AppendA( "hell" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struStack.AppendA( "0", 1, CP_ACP ) ) );
|
||||
Assert::IsTrue( 15 == wcslen( struStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// CopyToBuffer
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.CopyToBuffer( buf, &cbBuf ) ) );
|
||||
Assert::IsTrue( 15 == wcslen( buf ) );
|
||||
Assert::IsTrue( 16 * sizeof( wchar_t ) == cbBuf );
|
||||
|
||||
//
|
||||
// Trim
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L" \n\tHello World! \n\t ") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L"Hello World!"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L" Test test") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L"Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L"Test test ") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L"Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L" Test test ") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L"Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L" ") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L""));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L" ") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L""));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L"") ) );
|
||||
struStack.Trim();
|
||||
Assert::IsTrue( struStack.Equals(L""));
|
||||
|
||||
//
|
||||
// StartsWith
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L"Just the facts, please.") ) );
|
||||
Assert::IsTrue( struStack.StartsWith(L"Just the facts, please.") );
|
||||
Assert::IsTrue( struStack.StartsWith(L"Just") );
|
||||
Assert::IsTrue( struStack.StartsWith(L"Just the") );
|
||||
Assert::IsTrue( !struStack.StartsWith(L"just the") );
|
||||
Assert::IsTrue( struStack.StartsWith(L"just The", TRUE) );
|
||||
Assert::IsTrue( !struStack.StartsWith((LPCWSTR) NULL, TRUE) );
|
||||
Assert::IsTrue( !struStack.StartsWith(L"Just the facts, please...") );
|
||||
|
||||
//
|
||||
// EndsWith
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L"The beginning of the end of the beginning.") ) );
|
||||
Assert::IsTrue( struStack.EndsWith(L"The beginning of the end of the beginning.") );
|
||||
Assert::IsTrue( struStack.EndsWith(L".") );
|
||||
Assert::IsTrue( struStack.EndsWith(L"of the beginning.") );
|
||||
Assert::IsTrue( !struStack.EndsWith(L"Beginning.") );
|
||||
Assert::IsTrue( struStack.EndsWith(L"Beginning.", TRUE) );
|
||||
Assert::IsTrue( struStack.EndsWith(L"tHe BeGiNnIng.", TRUE) );
|
||||
Assert::IsTrue( !struStack.EndsWith((LPCWSTR) NULL, TRUE) );
|
||||
Assert::IsTrue( !struStack.EndsWith(L" The beginning of the end of the beginning.") );
|
||||
|
||||
//
|
||||
// IndexOf
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy(L"01234567890") ) );
|
||||
Assert::IsTrue( 0 == struStack.IndexOf( L'0' ) );
|
||||
Assert::IsTrue( 1 == struStack.IndexOf( L'1' ) );
|
||||
Assert::IsTrue( 2 == struStack.IndexOf( L'2', 1 ) );
|
||||
Assert::IsTrue( 10 == struStack.IndexOf( L'0', 1 ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( L'A' ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( L'0', 20 ) );
|
||||
|
||||
Assert::IsTrue( 0 == struStack.IndexOf( L"0123" ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( L"0123", 1 ) );
|
||||
Assert::IsTrue( 0 == struStack.IndexOf( L"01234567890" ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( L"012345678901" ) );
|
||||
Assert::IsTrue( 1 == struStack.IndexOf( L"1234" ) );
|
||||
Assert::IsTrue( 1 == struStack.IndexOf( L"1234", 1 ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( (PCWSTR)NULL ) );
|
||||
Assert::IsTrue( 0 == struStack.IndexOf( L"" ) );
|
||||
Assert::IsTrue( -1 == struStack.IndexOf( L"", 20 ) );
|
||||
|
||||
//
|
||||
// LastIndexOf
|
||||
//
|
||||
Assert::IsTrue( 10 == struStack.LastIndexOf( L'0' ) );
|
||||
Assert::IsTrue( 1 == struStack.LastIndexOf( L'1' ) );
|
||||
Assert::IsTrue( 2 == struStack.LastIndexOf( L'2', 1 ) );
|
||||
Assert::IsTrue( 10 == struStack.LastIndexOf( L'0', 1 ) );
|
||||
Assert::IsTrue( -1 == struStack.LastIndexOf( L'A' ) );
|
||||
Assert::IsTrue( -1 == struStack.LastIndexOf( L'0', 20 ) );
|
||||
|
||||
//
|
||||
// SetLen
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.SetLen( 2 ) ) );
|
||||
Assert::IsTrue( 2 == struStack.QueryCCH( ) );
|
||||
|
||||
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
|
||||
|
||||
//
|
||||
// OS-locale case-insensitive compare
|
||||
// Note how the two case-insensitive comparisons have different expected results
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( struStack.Copy( LOWER_A_THING ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( struReg.Copy( UPPER_A_THING ) ) );
|
||||
Assert::IsTrue( !struStack.Equals( &struReg ) );
|
||||
Assert::IsTrue( struStack.Equals( &struReg, TRUE ) );
|
||||
Assert::IsTrue( 0 != _wcsicmp( LOWER_A_THING, UPPER_A_THING ) );
|
||||
|
||||
#endif
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( struReg.SafeSnwprintf( L"%s%d", L"Hello", 10 ) ) );
|
||||
|
||||
//
|
||||
// Fail since there is no null-terminating char.
|
||||
//
|
||||
struStack.Reset();
|
||||
struStack.Resize(200);
|
||||
memset(struStack.QueryStr(), 'x', 200 * sizeof(WCHAR));
|
||||
Assert::AreNotEqual(S_OK, struStack.SyncWithBuffer());
|
||||
}
|
||||
|
||||
void TestStra()
|
||||
{
|
||||
STACK_STRA( straStack, 104 );
|
||||
STRA straReg;
|
||||
char buf[100];
|
||||
DWORD cbBuf = sizeof( buf );
|
||||
|
||||
//
|
||||
// IsEmpty
|
||||
//
|
||||
Assert::IsTrue( straStack.IsEmpty( ) );
|
||||
Assert::IsTrue( '\0' == straStack.QueryStr()[0] );
|
||||
Assert::IsTrue( straReg.IsEmpty( ) );
|
||||
|
||||
//
|
||||
// Copy psz
|
||||
// CopyW psz
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy( "hello" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( straReg.CopyW( L"hello" ) ) );
|
||||
|
||||
//
|
||||
// Equal
|
||||
//
|
||||
Assert::IsTrue( straStack.Equals( "hello" ) );
|
||||
Assert::IsTrue( straStack.Equals( &straReg ) );
|
||||
Assert::IsTrue( straStack.Equals( "helLO", TRUE ) );
|
||||
|
||||
|
||||
Assert::IsTrue( STRA::Equals( "Hello", "Hello" ) );
|
||||
Assert::IsTrue( STRA::Equals( "Hello", "Hello", FALSE ) );
|
||||
Assert::IsTrue( STRA::Equals( "Hello", "Hello", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRA::Equals( "hello", "Hello" ) );
|
||||
Assert::IsFalse( STRA::Equals( "hello", "Hello", FALSE ) );
|
||||
Assert::IsTrue( STRA::Equals( "hello", "Hello", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRA::Equals( "hello", "goodbye" ) );
|
||||
Assert::IsFalse( STRA::Equals( "hello", "goodbye", FALSE ) );
|
||||
Assert::IsFalse( STRA::Equals( "hello", "goodbye", TRUE ) );
|
||||
|
||||
Assert::IsFalse( STRA::Equals( (PCSTR)NULL, (PCSTR)NULL ) );
|
||||
Assert::IsFalse( STRA::Equals( "hello", (PCSTR)NULL ) );
|
||||
Assert::IsFalse( STRA::Equals( (PCSTR)NULL, "hello" ) );
|
||||
|
||||
//
|
||||
// Query*
|
||||
//
|
||||
Assert::IsTrue( 5 * sizeof( char ) == straStack.QueryCB( ) );
|
||||
Assert::IsTrue( 5 == straStack.QueryCCH( ) );
|
||||
Assert::IsTrue( 6 <= straStack.QuerySizeCCH( ) );
|
||||
Assert::IsTrue( 'h' == *( straStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// Resize
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straReg.Resize( 7 ) ) );
|
||||
Assert::IsTrue( 7 == straReg.QuerySizeCCH( ) );
|
||||
|
||||
//
|
||||
// SyncWithBuffer
|
||||
//
|
||||
*(straStack.QueryStr() + 5) = L'\0';
|
||||
Assert::AreEqual(S_OK, straStack.SyncWithBuffer( ));
|
||||
Assert::IsTrue( 5 == straStack.QueryCCH( ) );
|
||||
|
||||
//
|
||||
// Reset
|
||||
//
|
||||
straStack.Reset( );
|
||||
Assert::IsTrue( 0 == strlen( straStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// Append*
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Append( "hell" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Append( "o", 1 ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Append( &straReg ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( straStack.AppendW( L"hell" ) ) );
|
||||
Assert::IsTrue( SUCCEEDED( straStack.AppendW( L"0", 1, CP_ACP ) ) );
|
||||
Assert::IsTrue( 15 == strlen( straStack.QueryStr( ) ) );
|
||||
|
||||
//
|
||||
// CopyToBuffer
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.CopyToBuffer( buf, &cbBuf ) ) );
|
||||
Assert::IsTrue( 15 == strlen( buf ) );
|
||||
Assert::IsTrue( 16 * sizeof( char ) == cbBuf );
|
||||
|
||||
//
|
||||
// Trim
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy(" \n\tHello World! \n\t ") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals("Hello World!"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy(" Test test") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals("Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy("Test test ") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals("Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy(" Test test ") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals("Test test"));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy(" ") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals(""));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy(" ") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals(""));
|
||||
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy("") ) );
|
||||
straStack.Trim();
|
||||
Assert::IsTrue( straStack.Equals(""));
|
||||
|
||||
//
|
||||
// StartsWith
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy("Just the facts, please.") ) );
|
||||
Assert::IsTrue( straStack.StartsWith("Just the facts, please.") );
|
||||
Assert::IsTrue( straStack.StartsWith("Just") );
|
||||
Assert::IsTrue( straStack.StartsWith("Just the") );
|
||||
Assert::IsTrue( !straStack.StartsWith("just the") );
|
||||
Assert::IsTrue( straStack.StartsWith("just The", TRUE) );
|
||||
Assert::IsTrue( !straStack.StartsWith((LPCSTR) NULL, TRUE) );
|
||||
Assert::IsTrue( !straStack.StartsWith("Just the facts, please...") );
|
||||
|
||||
//
|
||||
// EndsWith
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy("The beginning of the end of the beginning.") ) );
|
||||
Assert::IsTrue( straStack.EndsWith("The beginning of the end of the beginning.") );
|
||||
Assert::IsTrue( straStack.EndsWith(".") );
|
||||
Assert::IsTrue( straStack.EndsWith("of the beginning.") );
|
||||
Assert::IsTrue( !straStack.EndsWith("Beginning.") );
|
||||
Assert::IsTrue( straStack.EndsWith("Beginning.", TRUE) );
|
||||
Assert::IsTrue( straStack.EndsWith("tHe BeGiNnIng.", TRUE) );
|
||||
Assert::IsTrue( !straStack.EndsWith((LPCSTR) NULL, TRUE) );
|
||||
Assert::IsTrue( !straStack.EndsWith(" The beginning of the end of the beginning.") );
|
||||
|
||||
//
|
||||
// IndexOf
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.Copy("01234567890") ) );
|
||||
Assert::IsTrue( 0 == straStack.IndexOf( '0' ) );
|
||||
Assert::IsTrue( 1 == straStack.IndexOf( '1' ) );
|
||||
Assert::IsTrue( 2 == straStack.IndexOf( '2', 1 ) );
|
||||
Assert::IsTrue( 10 == straStack.IndexOf( '0', 1 ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( 'A' ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( '0', 20 ) );
|
||||
|
||||
Assert::IsTrue( 0 == straStack.IndexOf( "0123" ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( "0123", 1 ) );
|
||||
Assert::IsTrue( 0 == straStack.IndexOf( "01234567890" ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( "012345678901" ) );
|
||||
Assert::IsTrue( 1 == straStack.IndexOf( "1234" ) );
|
||||
Assert::IsTrue( 1 == straStack.IndexOf( "1234", 1 ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( (PCSTR)NULL ) );
|
||||
Assert::IsTrue( 0 == straStack.IndexOf( "" ) );
|
||||
Assert::IsTrue( -1 == straStack.IndexOf( "", 20 ) );
|
||||
|
||||
//
|
||||
// LastIndexOf
|
||||
//
|
||||
Assert::IsTrue( 10 == straStack.LastIndexOf( '0' ) );
|
||||
Assert::IsTrue( 1 == straStack.LastIndexOf( '1' ) );
|
||||
Assert::IsTrue( 2 == straStack.LastIndexOf( '2', 1 ) );
|
||||
Assert::IsTrue( 10 == straStack.LastIndexOf( '0', 1 ) );
|
||||
Assert::IsTrue( -1 == straStack.LastIndexOf( 'A' ) );
|
||||
Assert::IsTrue( -1 == straStack.LastIndexOf( '0', 20 ) );
|
||||
|
||||
//
|
||||
// SetLen
|
||||
//
|
||||
Assert::IsTrue( SUCCEEDED( straStack.SetLen( 2 ) ) );
|
||||
Assert::IsTrue( 2 == straStack.QueryCCH( ) );
|
||||
|
||||
|
||||
//
|
||||
// Convert.
|
||||
//
|
||||
{
|
||||
STRA str;
|
||||
wchar_t psz[] = {0x41, L'Ã', 0x0};
|
||||
char pszA[] = {0x41, 'Ã', 0x0};
|
||||
Assert::IsTrue( SUCCEEDED(str.CopyW((LPCWSTR)psz, 2, CP_ACP )) );
|
||||
Assert::IsTrue( 0 == strcmp( pszA, str.QueryStr() ) );
|
||||
}
|
||||
//
|
||||
// Empty
|
||||
//
|
||||
{
|
||||
STRA str;
|
||||
wchar_t psz[] = {0x0};
|
||||
char pszA[] = {0x0};
|
||||
Assert::IsTrue( SUCCEEDED(str.CopyW((LPCWSTR)psz, 0, CP_ACP )) );
|
||||
Assert::IsTrue( 0 == strcmp( pszA, str.QueryStr() ) );
|
||||
}
|
||||
|
||||
//
|
||||
// Fail since there is no null-terminating char.
|
||||
//
|
||||
straStack.Reset();
|
||||
straStack.Resize(200);
|
||||
memset(straStack.QueryStr(), 'x', 200);
|
||||
Assert::AreNotEqual(S_OK, straStack.SyncWithBuffer());
|
||||
}
|
||||
|
||||
VOID
|
||||
AsciiAssert(char * str1, char * str2, size_t length)
|
||||
{
|
||||
for ( size_t index = 0; index < length; ++index )
|
||||
{
|
||||
Assert::AreEqual(str1[index], str2[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TestStraUnicode()
|
||||
{
|
||||
STRA str;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
//
|
||||
// Tool used to convert unicode to UTF-8 code points and hexadecimal code points:
|
||||
// http://rishida.net/scripts/uniview/conversion.php
|
||||
//
|
||||
|
||||
//
|
||||
// Input values to play with.
|
||||
//
|
||||
|
||||
// Real unicode string.
|
||||
LPCWSTR InputRealUnicode = L"?q=世加";
|
||||
|
||||
// This is the same value than InputRealUnicode, but represented as an array.
|
||||
wchar_t InputRealUnicodeArray[] =
|
||||
{
|
||||
0x3F, // ?
|
||||
0x71, // q
|
||||
0x3D, // =
|
||||
0x4E16, // 世
|
||||
0x52A0, // 加
|
||||
0x00 // L'\0'
|
||||
};
|
||||
|
||||
wchar_t InputAscii[] =
|
||||
{
|
||||
0x3F, // ?
|
||||
0x71, // q
|
||||
0x3D, // =
|
||||
0x7F, // 127
|
||||
0x00 // L'\0'
|
||||
};
|
||||
|
||||
// Fake unicode
|
||||
// UTF-8 code units in 'wchar_t' chars instead of 'char' chars.
|
||||
// This is how WinHttp returns the query string.
|
||||
wchar_t InputFakeUnicode[] =
|
||||
{
|
||||
0x3F, // ?
|
||||
0x71, // q
|
||||
0x3D, // =
|
||||
0xE4, // 1st code unit for '世'
|
||||
0xB8, // 2nd code unit for '世'
|
||||
0x96, // 3rd code unit for '世'
|
||||
0xE5, // 1st code unit for '加'
|
||||
0x8A, // 2nd code unit for '加'
|
||||
0xA0, // 3rd code unit for '加'
|
||||
0x00 // L'\0'
|
||||
};
|
||||
|
||||
//
|
||||
// Expected values after translation.
|
||||
//
|
||||
|
||||
unsigned char ExpectedAsciiCodeUnits[] =
|
||||
{
|
||||
0x3F, // ?
|
||||
0x71, // q
|
||||
0x3D, // =
|
||||
0xE4, // 1st code unit for '世'
|
||||
0xB8, // 2nd code unit for '世'
|
||||
0x96, // 3rd code unit for '世'
|
||||
0xE5, // 1st code unit for '加'
|
||||
0x8A, // 2nd code unit for '加'
|
||||
0xA0, // 3rd code unit for '加'
|
||||
0x00 // L'\0'
|
||||
};
|
||||
|
||||
char ExpectedAscii[] =
|
||||
{
|
||||
0x3F, // ?
|
||||
0x71, // q
|
||||
0x3D, // =
|
||||
0x7F, // 127
|
||||
0x00 // L'\0'
|
||||
};
|
||||
|
||||
//
|
||||
// Act and Assert.
|
||||
//
|
||||
|
||||
hr = str.CopyW(InputRealUnicode);
|
||||
Assert::AreEqual(S_OK, hr);
|
||||
Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid real unicode query string length.");
|
||||
AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() );
|
||||
|
||||
hr = str.CopyW(InputRealUnicodeArray);
|
||||
Assert::AreEqual(S_OK, hr);
|
||||
Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid real unicode query string length.");
|
||||
AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() );
|
||||
|
||||
hr = str.CopyWTruncate(InputFakeUnicode);
|
||||
Assert::AreEqual(S_OK, hr);
|
||||
Assert::AreEqual(9UL, str.QueryCCH(), L"Invalid truncated fake unicode query string length.");
|
||||
AsciiAssert( (char*)ExpectedAsciiCodeUnits, str.QueryStr(), str.QueryCCH() );
|
||||
|
||||
hr = str.CopyWTruncate(InputAscii);
|
||||
Assert::AreEqual(S_OK, hr);
|
||||
Assert::AreEqual(4UL, str.QueryCCH(), L"Invalid truncated ASCII query string length.");
|
||||
AsciiAssert( ExpectedAscii, str.QueryStr(), str.QueryCCH() );
|
||||
|
||||
hr = str.CopyW(InputAscii);
|
||||
Assert::AreEqual(S_OK, hr);
|
||||
Assert::AreEqual(4UL, str.QueryCCH(), L"Invalid CopyW ASCII query string length.");
|
||||
AsciiAssert( ExpectedAscii, str.QueryStr(), str.QueryCCH() );
|
||||
|
||||
}
|
||||
|
||||
#pragma managed
|
||||
|
||||
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
|
||||
|
||||
[TestClass]
|
||||
public ref class StringTests
|
||||
{
|
||||
public:
|
||||
|
||||
[TestMethod]
|
||||
void BufferTest()
|
||||
{
|
||||
::TestBuffer();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void StruTest()
|
||||
{
|
||||
::TestStru();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void StraTest()
|
||||
{
|
||||
::TestStra();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void TestStraOverrun()
|
||||
{
|
||||
::TestStraOverrun();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
void StraUnicodeTest()
|
||||
{
|
||||
::TestStraUnicode();
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<CppNugetVersion>14.11.25547</CppNugetVersion>
|
||||
<CppNugetPath Condition="$(CppNugetPath) == '' AND Exists('$(UserProfile)\.nuget\packages\visualcpptools.community.vs2017layout\$(CppNugetVersion)\build\native\VisualCppTools.Community.VS2017Layout.props')">$(UserProfile)\.nuget\packages\visualcpptools.community.vs2017layout\$(CppNugetVersion)\build\native\VisualCppTools.Community.VS2017Layout.props</CppNugetPath>
|
||||
<CppNugetPath Condition="$(CppNugetPath) == ''">$(UserProfile)\.nuget\GlobalPackages\visualcpptools.community.vs2017layout.$(CppNugetVersion)\build\native\VisualCppTools.Community.VS2017Layout.props</CppNugetPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(CppNugetPath)" Condition="Exists('$(CppNugetPath)') AND '$(UseCppToolChainFromNuGet)' != 'false' " />
|
||||
|
||||
<Target Name="EnsureNugetCompilerBuildImports" BeforeTargets="PrepareForBuild" Condition=" '$(UseCppToolChainFromNuGet)' != 'false' ">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(CppNugetPath)')" Text="$([System.String]::Format('$(ErrorText)', '$(CppNugetPath)'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<ItemGroup Condition="'@(BuildOutputFiles)' == ''">
|
||||
<BuildOutputFiles Include="$(OutDir)\$(TargetName)$(TargetExt)"/>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildOutputCopyPath Condition="$(BuildOutputCopyPath) == ''">$(Configuration)\$(PlatformShortname)\</BuildOutputCopyPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CopyOutputsToRoot" AfterTargets="Build">
|
||||
<Copy
|
||||
SourceFiles="@(BuildOutputFiles)"
|
||||
DestinationFolder="$(SolutionDir)bin\$(BuildOutputCopyPath)"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- Provide exports to submodule hosts -->
|
||||
|
||||
<PropertyGroup>
|
||||
<IIS-Common Condition="$(IIS-Common) == ''">$(MSBuildThisFileDirectory)..\</IIS-Common>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<Import Project="$(MSBuildThisFileDirectory)settings\common.props" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)settings\release.props" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)settings\debug.props" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)compiler.props" />
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
Use a common version of the Windows SDK
|
||||
-->
|
||||
|
||||
<!-- Define platform shortnames for use in paths without having to rely on cpp props -->
|
||||
<PropertyGroup>
|
||||
<PlatformShortname Condition="'$(PlatformShortname)' == '' AND '$(Platform)' == 'x64'">x64</PlatformShortname>
|
||||
<PlatformShortname Condition="'$(PlatformShortname)' == '' AND ('$(Platform.ToLower())' == 'win32' OR '$(Platform)' == 'x86')">x86</PlatformShortname>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- General properties -->
|
||||
|
||||
<PropertyGroup>
|
||||
<IisOobWinSdkVersion Condition="'$(IisOobWinSdkVersion)' == ''">10.0.15063.0</IisOobWinSdkVersion>
|
||||
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">$(IisOobWinSdkVersion)</WindowsTargetPlatformVersion>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<OutDir>bin\$(Configuration)\$(PlatformShortname)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\$(PlatformShortname)\</IntDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Use common compilation settings
|
||||
-->
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!--
|
||||
Use common preprocessor definitions
|
||||
-->
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- Common debug configuration for IIS OOB binaries -->
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Default runtime is static multithreaded debug -->
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<StringPooling>true</StringPooling>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<EnableCOMDATFolding>false</EnableCOMDATFolding>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalOptions>/JMC-</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
FunctionLevelLinking (/Gy) Enables function-level linking.
|
||||
StringPooling (/GF) Enables string pooling.
|
||||
-->
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<StringPooling>true</StringPooling>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!--
|
||||
LinkIncremental (/INCREMENTAL:NO) build does not contain padding or thunks
|
||||
-->
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Optimization - Full (/Ox) Uses maximum optimization
|
||||
FavorSizeOrSpeed - Size (/Ot) Favors fast code
|
||||
RuntimeTypeInfo (GR-) Disables run-time type information (RTTI)
|
||||
IntrinsicFunctions (/Oi) Requests the compiler to use intrinsic functions
|
||||
|
||||
OptimizeReferences (/OPT:REF) eliminates functions and data that are never referenced
|
||||
EnableCOMDATFolding (/OPT:ICF perform identical COMDAT folding
|
||||
LinkTimeCodeGeneration (/LCTG) perform whole-program optimization
|
||||
-->
|
||||
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>Full</Optimization>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- Add extension point for hosting as a submodule -->
|
||||
|
||||
<Import Condition="'$(SolutionDir)' != '' AND '$(SolutionDir)build\' != '$(MSBuildThisFileDirectory)' AND Exists('$(SolutionDir)build\submodule.props')" Project="$(SolutionDir)build\submodule.props" />
|
||||
|
||||
<!-- Import this modules properties if not yet declared -->
|
||||
|
||||
<Import Condition="$(IIS-Common) == ''" Project="$(MSBuildThisFileDirectory)exports.props" />
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- Allow versions as msbuild arguments -->
|
||||
|
||||
<PropertyGroup>
|
||||
<PRODUCT_MAJOR Condition="$(PRODUCT_MAJOR) == ''">7</PRODUCT_MAJOR>
|
||||
<PRODUCT_MINOR Condition="$(PRODUCT_MINOR) == ''">1</PRODUCT_MINOR>
|
||||
<!-- Auto bump the build version based on current date -->
|
||||
<!-- format:MMMDD, MMM indicates the total number of months since Dep 2016), DD indicates the number of days in current month-->
|
||||
<VersionDateMonths>$([MSBuild]::Multiply(12,$([MSBuild]::Subtract($([System.DateTime]::Now.Year), 2016))))</VersionDateMonths>
|
||||
<VersionDateTotalMonths>$([MSBuild]::Add( $([MSBuild]::Subtract($([System.DateTime]::Now.Month), 10)), $(VersionDateMonths))) </VersionDateTotalMonths>
|
||||
<VersionDateDays>$([System.DateTime]::Now.ToString("dd"))</VersionDateDays>
|
||||
<VersionBuildMajor>$([System.String]::Concat($([System.Int32]::Parse('$(VersionDateTotalMonths)').ToString("D3")), $(VersionDateDays)))</VersionBuildMajor>
|
||||
<BUILD_MAJOR Condition="$(BUILD_MAJOR) == ''">$(VersionBuildMajor)</BUILD_MAJOR>
|
||||
<BUILD_MINOR Condition="$(BUILD_MINOR) == ''">$([System.DateTime]::Now.ToString("HHmm"))</BUILD_MINOR>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/DPRODUCT_MAJOR=$(PRODUCT_MAJOR) %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/DPRODUCT_MINOR=$(PRODUCT_MINOR) %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/DBUILD_MAJOR=$(BUILD_MAJOR) %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<ClCompile>
|
||||
<AdditionalOptions>/DBUILD_MINOR=$(BUILD_MINOR) %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ResourceCompilePreprocessorDefinitions Condition="$(PRODUCT_MAJOR) != ''">PRODUCT_MAJOR=$(PRODUCT_MAJOR);$(ResourceCompilePreprocessorDefinitions)</ResourceCompilePreprocessorDefinitions>
|
||||
<ResourceCompilePreprocessorDefinitions Condition="$(PRODUCT_MINOR) != ''">PRODUCT_MINOR=$(PRODUCT_MINOR);$(ResourceCompilePreprocessorDefinitions)</ResourceCompilePreprocessorDefinitions>
|
||||
<ResourceCompilePreprocessorDefinitions Condition="$(BUILD_MAJOR) != ''">BUILD_MAJOR=$(BUILD_MAJOR);$(ResourceCompilePreprocessorDefinitions)</ResourceCompilePreprocessorDefinitions>
|
||||
<ResourceCompilePreprocessorDefinitions Condition="$(BUILD_MINOR) != ''">BUILD_MINOR=$(BUILD_MINOR);$(ResourceCompilePreprocessorDefinitions)</ResourceCompilePreprocessorDefinitions>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(ProjectDir)..\build\submodule.props" Condition="Exists('$(ProjectDir)..\build\submodule.props')" />
|
||||
<Import Project="$(ProjectDir)..\build\versions.props" Condition="Exists('$(ProjectDir)..\build\versions.props')" />
|
||||
<Import Project="$(ProjectDir)..\build\settings.props" Condition="Exists('$(ProjectDir)..\build\settings.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B54A8F61-60DE-4AD9-87CA-D102F230678E}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Lib</RootNamespace>
|
||||
<ProjectName>CommonLib</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>$(ProjectDir)..\include;$(IncludePath)</IncludePath>
|
||||
<TargetName>iiscommon</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="acache.cxx" />
|
||||
<ClCompile Include="ahutil.cpp" />
|
||||
<ClCompile Include="base64.cxx" />
|
||||
<ClCompile Include="datetime.cxx" />
|
||||
<ClCompile Include="multisz.cxx" />
|
||||
<ClCompile Include="multisza.cxx" />
|
||||
<ClCompile Include="normalize.cxx" />
|
||||
<ClCompile Include="stringa.cpp" />
|
||||
<ClCompile Include="stringu.cpp" />
|
||||
<ClCompile Include="ulparse.cxx" />
|
||||
<ClCompile Include="util.cxx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="precomp.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureImportsExist" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project is trying to import a missing file: {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\submodule.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\submodule.props'))" />
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\versions.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\versions.props'))" />
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\settings.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\settings.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
LONG ALLOC_CACHE_HANDLER::sm_nFillPattern = 0xACA50000;
|
||||
HANDLE ALLOC_CACHE_HANDLER::sm_hHeap;
|
||||
|
||||
//
|
||||
// This class is used to implement the free list. We cast the free'd
|
||||
// memory block to a FREE_LIST_HEADER*. The signature is used to guard against
|
||||
// double deletion. We also fill memory with a pattern.
|
||||
//
|
||||
class FREE_LIST_HEADER
|
||||
{
|
||||
public:
|
||||
SLIST_ENTRY ListEntry;
|
||||
DWORD dwSignature;
|
||||
|
||||
enum
|
||||
{
|
||||
FREE_SIGNATURE = (('A') | ('C' << 8) | ('a' << 16) | (('$' << 24) | 0x80)),
|
||||
};
|
||||
};
|
||||
|
||||
ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
) : m_nThreshold(0),
|
||||
m_cbSize(0),
|
||||
m_pFreeLists(NULL),
|
||||
m_nTotal(0)
|
||||
{
|
||||
}
|
||||
|
||||
ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
if (m_pFreeLists != NULL)
|
||||
{
|
||||
CleanupLookaside();
|
||||
m_pFreeLists->Dispose();
|
||||
m_pFreeLists = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
ALLOC_CACHE_HANDLER::Initialize(
|
||||
DWORD cbSize,
|
||||
LONG nThreshold
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
m_nThreshold = nThreshold;
|
||||
if ( m_nThreshold > 0xffff)
|
||||
{
|
||||
//
|
||||
// This will be compared against QueryDepthSList return value (USHORT).
|
||||
//
|
||||
m_nThreshold = 0xffff;
|
||||
}
|
||||
|
||||
if ( IsPageheapEnabled() )
|
||||
{
|
||||
//
|
||||
// Disable acache.
|
||||
//
|
||||
m_nThreshold = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure the block is big enough to hold a FREE_LIST_HEADER.
|
||||
//
|
||||
m_cbSize = cbSize;
|
||||
m_cbSize = max(m_cbSize, sizeof(FREE_LIST_HEADER));
|
||||
|
||||
//
|
||||
// Round up the block size to a multiple of the size of a LONG (for
|
||||
// the fill pattern in Free()).
|
||||
//
|
||||
m_cbSize = (m_cbSize + sizeof(LONG) - 1) & ~(sizeof(LONG) - 1);
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Init = [] (SLIST_HEADER* pHead)
|
||||
{
|
||||
InitializeSListHead(pHead);
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
void operator()(SLIST_HEADER* pHead)
|
||||
{
|
||||
InitializeSListHead(pHead);
|
||||
}
|
||||
} Init;
|
||||
#endif
|
||||
|
||||
hr = PER_CPU<SLIST_HEADER>::Create(Init,
|
||||
&m_pFreeLists );
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_nFillPattern = InterlockedIncrement(&sm_nFillPattern);
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// static
|
||||
HRESULT
|
||||
ALLOC_CACHE_HANDLER::StaticInitialize(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//
|
||||
// Since the memory allocated is fixed size,
|
||||
// a heap is not really needed, allocations can be done
|
||||
// using VirtualAllocEx[Numa]. For now use Windows Heap.
|
||||
//
|
||||
// Be aware that creating one private heap consumes more
|
||||
// virtual address space for the worker process.
|
||||
//
|
||||
sm_hHeap = GetProcessHeap();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::StaticTerminate(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
sm_hHeap = NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::CleanupLookaside(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
Description:
|
||||
This function cleans up the lookaside list by removing storage space.
|
||||
|
||||
Arguments:
|
||||
None.
|
||||
|
||||
Returns:
|
||||
None
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Free up all the entries in the list.
|
||||
// Don't use InterlockedFlushSList, in order to work
|
||||
// memory must be 16 bytes aligned and currently it is 64.
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Predicate = [=] (SLIST_HEADER * pListHeader)
|
||||
{
|
||||
PSLIST_ENTRY pl;
|
||||
LONG NodesToDelete = QueryDepthSList( pListHeader );
|
||||
|
||||
pl = InterlockedPopEntrySList( pListHeader );
|
||||
while ( pl != NULL && --NodesToDelete >= 0 )
|
||||
{
|
||||
InterlockedDecrement( &m_nTotal);
|
||||
|
||||
::HeapFree( sm_hHeap, 0, pl );
|
||||
|
||||
pl = InterlockedPopEntrySList(pListHeader);
|
||||
}
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
explicit Functor(ALLOC_CACHE_HANDLER * pThis) : _pThis(pThis)
|
||||
{
|
||||
}
|
||||
void operator()(SLIST_HEADER * pListHeader)
|
||||
{
|
||||
PSLIST_ENTRY pl;
|
||||
LONG NodesToDelete = QueryDepthSList( pListHeader );
|
||||
|
||||
pl = InterlockedPopEntrySList( pListHeader );
|
||||
while ( pl != NULL && --NodesToDelete >= 0 )
|
||||
{
|
||||
InterlockedDecrement( &_pThis->m_nTotal);
|
||||
|
||||
::HeapFree( sm_hHeap, 0, pl );
|
||||
|
||||
pl = InterlockedPopEntrySList(pListHeader);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ALLOC_CACHE_HANDLER * _pThis;
|
||||
} Predicate(this);
|
||||
#endif
|
||||
|
||||
m_pFreeLists ->ForEach(Predicate);
|
||||
}
|
||||
|
||||
LPVOID
|
||||
ALLOC_CACHE_HANDLER::Alloc(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
LPVOID pMemory = NULL;
|
||||
|
||||
if ( m_nThreshold > 0 )
|
||||
{
|
||||
SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
|
||||
pMemory = (LPVOID) InterlockedPopEntrySList(pListHeader); // get the real object
|
||||
|
||||
if (pMemory != NULL)
|
||||
{
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
//
|
||||
// If the signature is wrong then somebody's been scribbling
|
||||
// on memory that they've freed.
|
||||
//
|
||||
DBG_ASSERT(pfl->dwSignature == FREE_LIST_HEADER::FREE_SIGNATURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ( pMemory == NULL )
|
||||
{
|
||||
//
|
||||
// No free entry. Need to alloc a new object.
|
||||
//
|
||||
pMemory = (LPVOID) ::HeapAlloc( sm_hHeap,
|
||||
0,
|
||||
m_cbSize );
|
||||
|
||||
if ( pMemory != NULL )
|
||||
{
|
||||
//
|
||||
// Update counters.
|
||||
//
|
||||
m_nTotal++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pMemory == NULL )
|
||||
{
|
||||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||
}
|
||||
else
|
||||
{
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
pfl->dwSignature = 0; // clear; just in case caller never overwrites
|
||||
}
|
||||
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
VOID
|
||||
ALLOC_CACHE_HANDLER::Free(
|
||||
__in LPVOID pMemory
|
||||
)
|
||||
{
|
||||
//
|
||||
// Assume that this is allocated using the Alloc() function.
|
||||
//
|
||||
DBG_ASSERT(NULL != pMemory);
|
||||
|
||||
//
|
||||
// Use a signature to check against double deletions.
|
||||
//
|
||||
FREE_LIST_HEADER* pfl = (FREE_LIST_HEADER*) pMemory;
|
||||
DBG_ASSERT(pfl->dwSignature != FREE_LIST_HEADER::FREE_SIGNATURE);
|
||||
|
||||
//
|
||||
// Start filling the space beyond the portion overlaid by the initial
|
||||
// FREE_LIST_HEADER. Fill at most 6 DWORDS.
|
||||
//
|
||||
LONG* pl = (LONG*) (pfl+1);
|
||||
|
||||
for (LONG cb = (LONG)min(6 * sizeof(LONG),m_cbSize) - sizeof(FREE_LIST_HEADER);
|
||||
cb > 0;
|
||||
cb -= sizeof(LONG))
|
||||
{
|
||||
*pl++ = m_nFillPattern;
|
||||
}
|
||||
|
||||
//
|
||||
// Now, set the signature.
|
||||
//
|
||||
pfl->dwSignature = FREE_LIST_HEADER::FREE_SIGNATURE;
|
||||
|
||||
//
|
||||
// Store the items in the alloc cache.
|
||||
//
|
||||
SLIST_HEADER * pListHeader = m_pFreeLists ->GetLocal();
|
||||
|
||||
if ( QueryDepthSList(pListHeader) >= m_nThreshold )
|
||||
{
|
||||
//
|
||||
// Threshold for free entries is exceeded. Free the object to
|
||||
// process pool.
|
||||
//
|
||||
::HeapFree( sm_hHeap, 0, pMemory );
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Store the given pointer in the single linear list
|
||||
//
|
||||
InterlockedPushEntrySList(pListHeader, &pfl->ListEntry);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD
|
||||
ALLOC_CACHE_HANDLER::QueryDepthForAllSLists(
|
||||
VOID
|
||||
)
|
||||
/*++
|
||||
|
||||
Description:
|
||||
|
||||
Aggregates the total count of elements in all lists.
|
||||
|
||||
Arguments:
|
||||
|
||||
None.
|
||||
|
||||
Return Value:
|
||||
|
||||
Total count (snapshot).
|
||||
|
||||
--*/
|
||||
{
|
||||
DWORD Count = 0;
|
||||
|
||||
if (m_pFreeLists != NULL)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1600 // VC10
|
||||
auto Predicate = [&Count] (SLIST_HEADER * pListHeader)
|
||||
{
|
||||
Count += QueryDepthSList(pListHeader);
|
||||
};
|
||||
#else
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
explicit Functor(DWORD& Count) : _Count(Count)
|
||||
{
|
||||
}
|
||||
void operator()(SLIST_HEADER * pListHeader)
|
||||
{
|
||||
_Count += QueryDepthSList(pListHeader);
|
||||
}
|
||||
private:
|
||||
DWORD& _Count;
|
||||
} Predicate(Count);
|
||||
#endif
|
||||
//
|
||||
// [&Count] means that the method can modify local variable Count.
|
||||
//
|
||||
m_pFreeLists ->ForEach(Predicate);
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL
|
||||
ALLOC_CACHE_HANDLER::IsPageheapEnabled(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOL fRet = FALSE;
|
||||
BOOL fLockedHeap = FALSE;
|
||||
HMODULE hModule = NULL;
|
||||
HANDLE hHeap = NULL;
|
||||
PROCESS_HEAP_ENTRY heapEntry = {0};
|
||||
|
||||
//
|
||||
// If verifier.dll is loaded - we are running under app verifier == pageheap is enabled
|
||||
//
|
||||
hModule = GetModuleHandle( L"verifier.dll" );
|
||||
if ( hModule != NULL )
|
||||
{
|
||||
hModule = NULL;
|
||||
fRet = TRUE;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a heap for calling heapwalk
|
||||
// otherwise HeapWalk turns off lookasides for a useful heap
|
||||
//
|
||||
hHeap = ::HeapCreate( 0, 0, 0 );
|
||||
if ( hHeap == NULL )
|
||||
{
|
||||
fRet = FALSE;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
fRet = ::HeapLock( hHeap );
|
||||
if ( !fRet )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
fLockedHeap = TRUE;
|
||||
|
||||
//
|
||||
// If HeapWalk is unsupported -> then running page heap
|
||||
//
|
||||
fRet = ::HeapWalk( hHeap, &heapEntry );
|
||||
if ( !fRet )
|
||||
{
|
||||
if ( GetLastError() == ERROR_INVALID_FUNCTION )
|
||||
{
|
||||
fRet = TRUE;
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
fRet = FALSE;
|
||||
|
||||
Finished:
|
||||
|
||||
if ( fLockedHeap )
|
||||
{
|
||||
fLockedHeap = FALSE;
|
||||
DBG_REQUIRE( ::HeapUnlock( hHeap ) );
|
||||
}
|
||||
|
||||
if ( hHeap )
|
||||
{
|
||||
DBG_REQUIRE( ::HeapDestroy( hHeap ) );
|
||||
hHeap = NULL;
|
||||
}
|
||||
|
||||
return fRet;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,482 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt(cchEncodedStringSize) PWSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pDecodedBuffer (IN) - buffer to encode.
|
||||
cbDecodedBufferSize (IN) - size of buffer to encode.
|
||||
cchEncodedStringSize (IN) - size of the buffer for the encoded string.
|
||||
pszEncodedString (OUT) = the encoded string.
|
||||
pcchEncoded (OUT) - size in characters of the encoded string.
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
static WCHAR rgchEncodeTable[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
DWORD ib;
|
||||
DWORD ich;
|
||||
DWORD cchEncoded;
|
||||
BYTE b0, b1, b2;
|
||||
BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer;
|
||||
|
||||
// Calculate encoded string size.
|
||||
cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
|
||||
|
||||
if (NULL != pcchEncoded) {
|
||||
*pcchEncoded = cchEncoded;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize < cchEncoded) {
|
||||
// Given buffer is too small to hold encoded string.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Encode data byte triplets into four-byte clusters.
|
||||
ib = ich = 0;
|
||||
while (ib < cbDecodedBufferSize) {
|
||||
b0 = pbDecodedBuffer[ib++];
|
||||
b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
|
||||
//
|
||||
// The checks below for buffer overflow seems redundant to me.
|
||||
// But it's the only way I can find to keep OACR quiet so it
|
||||
// will have to do.
|
||||
//
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad the last cluster as necessary to indicate the number of data bytes
|
||||
// it represents.
|
||||
switch (cbDecodedBufferSize % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
pszEncodedString[ich - 2] = '=';
|
||||
__fallthrough;
|
||||
case 2:
|
||||
pszEncodedString[ich - 1] = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
// Null-terminate the encoded string.
|
||||
pszEncodedString[ich++] = '\0';
|
||||
|
||||
DBG_ASSERT(ich == cchEncoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCWSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszEncodedString (IN) - base64-encoded string to decode.
|
||||
cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
|
||||
pbDecodeBuffer (OUT) - holds the decoded data.
|
||||
pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
|
||||
STATUS_BUFFER_TOO_SMALL).
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
E_INVALIDARG
|
||||
|
||||
--*/
|
||||
{
|
||||
#define NA (255)
|
||||
#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
|
||||
|
||||
static BYTE rgbDecodeTable[128] = {
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63
|
||||
NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95
|
||||
NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127
|
||||
};
|
||||
|
||||
DWORD cbDecoded;
|
||||
DWORD cchEncodedSize;
|
||||
DWORD ich;
|
||||
DWORD ib;
|
||||
BYTE b0, b1, b2, b3;
|
||||
BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer;
|
||||
|
||||
cchEncodedSize = (DWORD)wcslen(pszEncodedString);
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = 0;
|
||||
}
|
||||
|
||||
if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
|
||||
// Input string is not sized correctly to be base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Calculate decoded buffer size.
|
||||
cbDecoded = (cchEncodedSize + 3) / 4 * 3;
|
||||
if (pszEncodedString[cchEncodedSize-1] == '=') {
|
||||
if (pszEncodedString[cchEncodedSize-2] == '=') {
|
||||
// Only one data byte is encoded in the last cluster.
|
||||
cbDecoded -= 2;
|
||||
}
|
||||
else {
|
||||
// Only two data bytes are encoded in the last cluster.
|
||||
cbDecoded -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = cbDecoded;
|
||||
}
|
||||
|
||||
if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cbDecoded > cbDecodeBufferSize) {
|
||||
// Supplied buffer is too small.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Decode each four-byte cluster into the corresponding three data bytes.
|
||||
ich = ib = 0;
|
||||
while (ich < cchEncodedSize) {
|
||||
b0 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b1 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b2 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b3 = DECODE(pszEncodedString[ich]); ich++;
|
||||
|
||||
if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
|
||||
// Contents of input string are not base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b2 << 6) | b3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG_ASSERT(ib == cbDecoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Encode(
|
||||
__in_bcount(cbDecodedBufferSize) VOID * pDecodedBuffer,
|
||||
IN DWORD cbDecodedBufferSize,
|
||||
__out_ecount_opt(cchEncodedStringSize) PSTR pszEncodedString,
|
||||
IN DWORD cchEncodedStringSize,
|
||||
__out_opt DWORD * pcchEncoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pDecodedBuffer (IN) - buffer to encode.
|
||||
cbDecodedBufferSize (IN) - size of buffer to encode.
|
||||
cchEncodedStringSize (IN) - size of the buffer for the encoded string.
|
||||
pszEncodedString (OUT) = the encoded string.
|
||||
pcchEncoded (OUT) - size in characters of the encoded string.
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
|
||||
--*/
|
||||
{
|
||||
static CHAR rgchEncodeTable[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
DWORD ib;
|
||||
DWORD ich;
|
||||
DWORD cchEncoded;
|
||||
BYTE b0, b1, b2;
|
||||
BYTE * pbDecodedBuffer = (BYTE *) pDecodedBuffer;
|
||||
|
||||
// Calculate encoded string size.
|
||||
cchEncoded = 1 + (cbDecodedBufferSize + 2) / 3 * 4;
|
||||
|
||||
if (NULL != pcchEncoded) {
|
||||
*pcchEncoded = cchEncoded;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize == 0 && pszEncodedString == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cchEncodedStringSize < cchEncoded) {
|
||||
// Given buffer is too small to hold encoded string.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Encode data byte triplets into four-byte clusters.
|
||||
ib = ich = 0;
|
||||
while (ib < cbDecodedBufferSize) {
|
||||
b0 = pbDecodedBuffer[ib++];
|
||||
b1 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
b2 = (ib < cbDecodedBufferSize) ? pbDecodedBuffer[ib++] : 0;
|
||||
|
||||
//
|
||||
// The checks below for buffer overflow seems redundant to me.
|
||||
// But it's the only way I can find to keep OACR quiet so it
|
||||
// will have to do.
|
||||
//
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b0 >> 2];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
pszEncodedString[ich++] = rgchEncodeTable[b2 & 0x3f];
|
||||
if ( ich >= cchEncodedStringSize )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad the last cluster as necessary to indicate the number of data bytes
|
||||
// it represents.
|
||||
switch (cbDecodedBufferSize % 3) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
pszEncodedString[ich - 2] = '=';
|
||||
__fallthrough;
|
||||
case 2:
|
||||
pszEncodedString[ich - 1] = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
// Null-terminate the encoded string.
|
||||
pszEncodedString[ich++] = '\0';
|
||||
|
||||
DBG_ASSERT(ich == cchEncoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DWORD
|
||||
Base64Decode(
|
||||
__in PCSTR pszEncodedString,
|
||||
__out_opt VOID * pDecodeBuffer,
|
||||
__in DWORD cbDecodeBufferSize,
|
||||
__out_opt DWORD * pcbDecoded
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Decode a base64-encoded string.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszEncodedString (IN) - base64-encoded string to decode.
|
||||
cbDecodeBufferSize (IN) - size in bytes of the decode buffer.
|
||||
pbDecodeBuffer (OUT) - holds the decoded data.
|
||||
pcbDecoded (OUT) - number of data bytes in the decoded data (if success or
|
||||
STATUS_BUFFER_TOO_SMALL).
|
||||
|
||||
Return Values:
|
||||
|
||||
0 - success.
|
||||
E_OUTOFMEMORY
|
||||
E_INVALIDARG
|
||||
|
||||
--*/
|
||||
{
|
||||
#define NA (255)
|
||||
#define DECODE(x) (((ULONG)(x) < sizeof(rgbDecodeTable)) ? rgbDecodeTable[x] : NA)
|
||||
|
||||
static BYTE rgbDecodeTable[128] = {
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 0-15
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, // 16-31
|
||||
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 62, NA, NA, NA, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NA, NA, NA, 0, NA, NA, // 48-63
|
||||
NA, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NA, NA, NA, NA, NA, // 80-95
|
||||
NA, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NA, NA, NA, NA, NA, // 112-127
|
||||
};
|
||||
|
||||
DWORD cbDecoded;
|
||||
DWORD cchEncodedSize;
|
||||
DWORD ich;
|
||||
DWORD ib;
|
||||
BYTE b0, b1, b2, b3;
|
||||
BYTE * pbDecodeBuffer = (BYTE *) pDecodeBuffer;
|
||||
|
||||
cchEncodedSize = (DWORD)strlen(pszEncodedString);
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = 0;
|
||||
}
|
||||
|
||||
if ((0 == cchEncodedSize) || (0 != (cchEncodedSize % 4))) {
|
||||
// Input string is not sized correctly to be base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Calculate decoded buffer size.
|
||||
cbDecoded = (cchEncodedSize + 3) / 4 * 3;
|
||||
if (pszEncodedString[cchEncodedSize-1] == '=') {
|
||||
if (pszEncodedString[cchEncodedSize-2] == '=') {
|
||||
// Only one data byte is encoded in the last cluster.
|
||||
cbDecoded -= 2;
|
||||
}
|
||||
else {
|
||||
// Only two data bytes are encoded in the last cluster.
|
||||
cbDecoded -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pcbDecoded) {
|
||||
*pcbDecoded = cbDecoded;
|
||||
}
|
||||
|
||||
if (cbDecodeBufferSize == 0 && pDecodeBuffer == NULL) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (cbDecoded > cbDecodeBufferSize) {
|
||||
// Supplied buffer is too small.
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Decode each four-byte cluster into the corresponding three data bytes.
|
||||
ich = ib = 0;
|
||||
while (ich < cchEncodedSize) {
|
||||
b0 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b1 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b2 = DECODE(pszEncodedString[ich]); ich++;
|
||||
b3 = DECODE(pszEncodedString[ich]); ich++;
|
||||
|
||||
if ((NA == b0) || (NA == b1) || (NA == b2) || (NA == b3)) {
|
||||
// Contents of input string are not base64.
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pbDecodeBuffer[ib++] = (b0 << 2) | (b1 >> 4);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b1 << 4) | (b2 >> 2);
|
||||
|
||||
if (ib < cbDecoded) {
|
||||
pbDecodeBuffer[ib++] = (b2 << 6) | b3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG_ASSERT(ib == cbDecoded);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
static const CHAR* s_rgchMonths[] = {
|
||||
"Jan", "Feb", "Mar", "Apr",
|
||||
"May", "Jun", "Jul", "Aug",
|
||||
"Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
// Custom hash table for make_month() for mapping "Apr" to 4
|
||||
static const CHAR MonthIndexTable[64] = {
|
||||
-1,'A', 2, 12, -1, -1, -1, 8, // A to G
|
||||
-1, -1, -1, -1, 7, -1,'N', -1, // F to O
|
||||
9, -1,'R', -1, 10, -1, 11, -1, // P to W
|
||||
-1, 5, -1, -1, -1, -1, -1, -1, // X to Z
|
||||
-1,'A', 2, 12, -1, -1, -1, 8, // a to g
|
||||
-1, -1, -1, -1, 7, -1,'N', -1, // f to o
|
||||
9, -1,'R', -1, 10, -1, 11, -1, // p to w
|
||||
-1, 5, -1, -1, -1, -1, -1, -1 // x to z
|
||||
};
|
||||
|
||||
static const BYTE TensDigit[10] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 };
|
||||
|
||||
WORD
|
||||
iis_2atoi(
|
||||
__in_ecount(2) PCHAR s
|
||||
)
|
||||
/*++
|
||||
|
||||
Converts a 2 character string to integer
|
||||
|
||||
Arguments:
|
||||
s String to convert
|
||||
|
||||
Returns:
|
||||
numeric equivalent, 0 on failure.
|
||||
--*/
|
||||
{
|
||||
|
||||
DWORD tens = s[0] - '0';
|
||||
DWORD ones = s[1] - '0';
|
||||
|
||||
if ( (tens <= 9) && (ones <= 9) ) {
|
||||
return((WORD)(TensDigit[tens] + ones));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
WORD
|
||||
make_month(
|
||||
__in_ecount(3) PCHAR s
|
||||
)
|
||||
{
|
||||
UCHAR monthIndex;
|
||||
UCHAR c;
|
||||
LPCSTR monthString;
|
||||
|
||||
//
|
||||
// use the third character as the index
|
||||
//
|
||||
|
||||
c = (s[2] - 0x40) & 0x3F;
|
||||
|
||||
monthIndex = MonthIndexTable[c];
|
||||
|
||||
if ( monthIndex < 13 ) {
|
||||
goto verify;
|
||||
}
|
||||
|
||||
//
|
||||
// ok, we need to look at the second character
|
||||
//
|
||||
|
||||
if ( monthIndex == 'N' ) {
|
||||
|
||||
//
|
||||
// we got an N which we need to resolve further
|
||||
//
|
||||
|
||||
//
|
||||
// if s[1] is 'u' then Jun, if 'a' then Jan
|
||||
//
|
||||
|
||||
if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
|
||||
monthIndex = 1;
|
||||
} else {
|
||||
monthIndex = 6;
|
||||
}
|
||||
|
||||
} else if ( monthIndex == 'R' ) {
|
||||
|
||||
//
|
||||
// if s[1] is 'a' then March, if 'p' then April
|
||||
//
|
||||
|
||||
if ( MonthIndexTable[(s[1]-0x40) & 0x3f] == 'A' ) {
|
||||
monthIndex = 3;
|
||||
} else {
|
||||
monthIndex = 4;
|
||||
}
|
||||
} else {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
verify:
|
||||
|
||||
monthString = s_rgchMonths[monthIndex-1];
|
||||
|
||||
if ( (s[0] == monthString[0]) &&
|
||||
(s[1] == monthString[1]) &&
|
||||
(s[2] == monthString[2]) ) {
|
||||
|
||||
return(monthIndex);
|
||||
|
||||
} else if ( (toupper(s[0]) == monthString[0]) &&
|
||||
(tolower(s[1]) == monthString[1]) &&
|
||||
(tolower(s[2]) == monthString[2]) ) {
|
||||
|
||||
return monthIndex;
|
||||
}
|
||||
|
||||
error_exit:
|
||||
return(0);
|
||||
|
||||
} // make_month
|
||||
|
||||
BOOL
|
||||
StringTimeToFileTime(
|
||||
IN const CHAR * pszTime,
|
||||
OUT ULONGLONG * pulTime
|
||||
)
|
||||
/*++
|
||||
|
||||
Converts a string representation of a GMT time (three different
|
||||
varieties) to an NT representation of a file time.
|
||||
|
||||
We handle the following variations:
|
||||
|
||||
Sun, 06 Nov 1994 08:49:37 GMT (RFC 822 updated by RFC 1123)
|
||||
Sunday, 06-Nov-94 08:49:37 GMT (RFC 850)
|
||||
Sun Nov 6 08:49:37 1994 (ANSI C's asctime() format
|
||||
|
||||
Arguments:
|
||||
pszTime String representation of time field
|
||||
pliTime large integer containing the time in NT format.
|
||||
|
||||
Returns:
|
||||
TRUE on success and FALSE on failure.
|
||||
|
||||
History:
|
||||
|
||||
Johnl 24-Jan-1995 Modified from WWW library
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
CHAR * s;
|
||||
SYSTEMTIME st;
|
||||
|
||||
if (pszTime == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
st.wMilliseconds = 0;
|
||||
|
||||
if ((s = (CHAR*) strchr(pszTime, ','))) {
|
||||
|
||||
DWORD len;
|
||||
|
||||
//
|
||||
// Thursday, 10-Jun-93 01:29:59 GMT
|
||||
// or: Thu, 10 Jan 1993 01:29:59 GMT */
|
||||
//
|
||||
|
||||
s++;
|
||||
|
||||
while (*s && *s==' ') s++;
|
||||
len = (DWORD)strlen(s);
|
||||
|
||||
if (len < 18) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( *(s+2) == '-' ) { /* First format */
|
||||
|
||||
st.wDay = (WORD) atoi(s);
|
||||
st.wMonth = (WORD) make_month(s+3);
|
||||
st.wYear = (WORD) atoi(s+7);
|
||||
st.wHour = (WORD) atoi(s+10);
|
||||
st.wMinute = (WORD) atoi(s+13);
|
||||
st.wSecond = (WORD) atoi(s+16);
|
||||
|
||||
} else { /* Second format */
|
||||
|
||||
if (len < 20) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
st.wDay = iis_2atoi(s);
|
||||
st.wMonth = make_month(s+3);
|
||||
st.wYear = iis_2atoi(s+7) * 100 + iis_2atoi(s+9);
|
||||
st.wHour = iis_2atoi(s+12);
|
||||
st.wMinute = iis_2atoi(s+15);
|
||||
st.wSecond = iis_2atoi(s+18);
|
||||
|
||||
}
|
||||
} else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */
|
||||
|
||||
s = (CHAR *) pszTime;
|
||||
while (*s && *s==' ') s++;
|
||||
|
||||
if ((int)strlen(s) < 24) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
st.wDay = (WORD) atoi(s+8);
|
||||
st.wMonth = (WORD) make_month(s+4);
|
||||
st.wYear = (WORD) atoi(s+20);
|
||||
st.wHour = (WORD) atoi(s+11);
|
||||
st.wMinute = (WORD) atoi(s+14);
|
||||
st.wSecond = (WORD) atoi(s+17);
|
||||
}
|
||||
|
||||
//
|
||||
// Adjust for dates with only two digits
|
||||
//
|
||||
|
||||
if ( st.wYear < 1000 ) {
|
||||
if ( st.wYear < 50 ) {
|
||||
st.wYear += 2000;
|
||||
} else {
|
||||
st.wYear += 1900;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SystemTimeToFileTime(&st, (FILETIME *)pulTime)) {
|
||||
return FALSE;
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,480 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
//#include <dbgutil.h>
|
||||
#include <multisz.hxx>
|
||||
//# include <auxctrs.h>
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// Private Definitions
|
||||
//
|
||||
|
||||
#define MAXULONG 4294967295
|
||||
#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
|
||||
|
||||
//
|
||||
// When appending data, this is the extra amount we request to avoid
|
||||
// reallocations
|
||||
//
|
||||
#define STR_SLOP 128
|
||||
|
||||
|
||||
DWORD
|
||||
MULTISZ::CalcLength( const WCHAR * str,
|
||||
LPDWORD pcStrings )
|
||||
{
|
||||
DWORD count = 0;
|
||||
DWORD total = 1;
|
||||
DWORD len;
|
||||
|
||||
while( *str ) {
|
||||
len = (DWORD)(::wcslen( str ) + 1);
|
||||
total += len;
|
||||
str += len;
|
||||
count++;
|
||||
}
|
||||
|
||||
if( pcStrings != NULL ) {
|
||||
*pcStrings = count;
|
||||
}
|
||||
|
||||
return total;
|
||||
|
||||
} // MULTISZ::CalcLength
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZ::FindString( const WCHAR * str )
|
||||
{
|
||||
|
||||
WCHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !::wcscmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += ::wcslen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZ::FindString
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZ::FindStringNoCase( const WCHAR * str )
|
||||
{
|
||||
|
||||
WCHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !_wcsicmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += wcslen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZ::FindStringNoCase
|
||||
|
||||
|
||||
VOID
|
||||
MULTISZ::AuxInit( const WCHAR * pInit )
|
||||
{
|
||||
BOOL fRet;
|
||||
|
||||
if ( pInit )
|
||||
{
|
||||
DWORD cStrings;
|
||||
int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(WCHAR);
|
||||
fRet = Resize( cbCopy );
|
||||
|
||||
if ( fRet ) {
|
||||
CopyMemory( QueryPtr(), pInit, cbCopy );
|
||||
m_cchLen = (cbCopy)/sizeof(WCHAR);
|
||||
m_cStrings = cStrings;
|
||||
} else {
|
||||
// BUFFER::SetValid( FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Reset();
|
||||
|
||||
}
|
||||
|
||||
} // MULTISZ::AuxInit()
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: MULTISZ::AuxAppend
|
||||
|
||||
SYNOPSIS: Appends the string onto the multisz.
|
||||
|
||||
ENTRY: Object to append
|
||||
********************************************************************/
|
||||
|
||||
BOOL MULTISZ::AuxAppend( const WCHAR * pStr, UINT cbStr, BOOL fAddSlop )
|
||||
{
|
||||
DBG_ASSERT( pStr != NULL );
|
||||
|
||||
UINT cbThis = QueryCB();
|
||||
|
||||
DBG_ASSERT( cbThis >= 2 );
|
||||
|
||||
if( cbThis == 4 ) {
|
||||
|
||||
//
|
||||
// It's empty, so start at the beginning.
|
||||
//
|
||||
|
||||
cbThis = 0;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// It's not empty, so back up over the final terminating NULL.
|
||||
//
|
||||
|
||||
cbThis -= sizeof(WCHAR);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Only resize when we have to. When we do resize, we tack on
|
||||
// some extra space to avoid extra reallocations.
|
||||
//
|
||||
// Note: QuerySize returns the requested size of the string buffer,
|
||||
// *not* the strlen of the buffer
|
||||
//
|
||||
|
||||
//AcIncrement( CacMultiszAppend);
|
||||
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
// ( 2 * sizeof( WCHAR ) ) is for the double terminator
|
||||
//
|
||||
ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(WCHAR);
|
||||
if ( cb64Required > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( QuerySize() < (DWORD) cb64Required )
|
||||
{
|
||||
ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
if ( cb64AllocSize > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( !Resize( (DWORD) cb64AllocSize ) )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy the exact string and tack on the double terminator
|
||||
memcpy( (BYTE *) QueryPtr() + cbThis,
|
||||
pStr,
|
||||
cbStr);
|
||||
*(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
|
||||
*(WCHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(WCHAR) ) = L'\0';
|
||||
|
||||
m_cchLen = CalcLength( (const WCHAR *)QueryPtr(), &m_cStrings );
|
||||
return TRUE;
|
||||
|
||||
} // MULTISZ::AuxAppend()
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
BOOL
|
||||
MULTISZ::CopyToBuffer( WCHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the WCHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to WCHAR buffer which on return contains
|
||||
the UNICODE version of string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in *lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
|
||||
History:
|
||||
MuraliK 11-30-94
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
if ( *lpcch == 0) {
|
||||
|
||||
//
|
||||
// Inquiring the size of buffer alone
|
||||
//
|
||||
*lpcch = QueryCCH() + 1; // add one character for terminating null
|
||||
} else {
|
||||
|
||||
//
|
||||
// Copy after conversion from ANSI to Unicode
|
||||
//
|
||||
int iRet;
|
||||
iRet = MultiByteToWideChar( CP_ACP,
|
||||
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
||||
QueryStrA(), QueryCCH() + 1,
|
||||
lpszBuffer, (int )*lpcch);
|
||||
|
||||
if ( iRet == 0 || iRet != (int ) *lpcch) {
|
||||
|
||||
//
|
||||
// Error in conversion.
|
||||
//
|
||||
fReturn = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZ::CopyToBuffer()
|
||||
#endif
|
||||
|
||||
BOOL
|
||||
MULTISZ::CopyToBuffer( __out_ecount_opt(*lpcch) WCHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the WCHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to WCHAR buffer which on return contains
|
||||
the string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
|
||||
History:
|
||||
MuraliK 20-Nov-1996
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
register DWORD cch = QueryCCH();
|
||||
|
||||
if ( *lpcch >= cch) {
|
||||
|
||||
DBG_ASSERT( lpszBuffer);
|
||||
memcpy( lpszBuffer, QueryStr(), cch * sizeof(WCHAR));
|
||||
} else {
|
||||
DBG_ASSERT( *lpcch < cch);
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||||
fReturn = FALSE;
|
||||
}
|
||||
|
||||
*lpcch = cch;
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZ::CopyToBuffer()
|
||||
|
||||
BOOL
|
||||
MULTISZ::Equals(
|
||||
MULTISZ* pmszRhs
|
||||
)
|
||||
//
|
||||
// Compares this to pmszRhs, returns TRUE if equal
|
||||
//
|
||||
{
|
||||
DBG_ASSERT( NULL != pmszRhs );
|
||||
|
||||
PCWSTR pszLhs = First( );
|
||||
PCWSTR pszRhs = pmszRhs->First( );
|
||||
|
||||
if( m_cStrings != pmszRhs->m_cStrings )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while( NULL != pszLhs )
|
||||
{
|
||||
DBG_ASSERT( NULL != pszRhs );
|
||||
|
||||
if( 0 != wcscmp( pszLhs, pszRhs ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszLhs = Next( pszLhs );
|
||||
pszRhs = pmszRhs->Next( pszRhs );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCWSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZ * pmszList
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Split comma delimited string into a multisz. Additional leading empty
|
||||
entries after the first are discarded.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszList - List to split up
|
||||
fTrimEntries - Whether each entry should be trimmed before added to multisz
|
||||
fRemoveEmptyEntries - Whether empty entires should be discarded
|
||||
pmszList - Filled with MULTISZ list
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( pszList == NULL ||
|
||||
pmszList == NULL )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pmszList->Reset();
|
||||
|
||||
/*
|
||||
pszCurrent: start of the current entry which may be the comma that
|
||||
precedes the next entry if the entry is empty
|
||||
|
||||
pszNext: the comma that precedes the next entry. If
|
||||
pszCurrent == pszNext, then the entry is empty
|
||||
|
||||
pszEnd: just past the end of the current entry
|
||||
*/
|
||||
|
||||
for ( PCWSTR pszCurrent = pszList,
|
||||
pszNext = wcschr( pszCurrent, L',' )
|
||||
;
|
||||
;
|
||||
pszCurrent = pszNext + 1,
|
||||
pszNext = wcschr( pszCurrent, L',' ) )
|
||||
{
|
||||
PCWSTR pszEnd = NULL;
|
||||
|
||||
if ( pszNext != NULL )
|
||||
{
|
||||
pszEnd = pszNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszEnd = pszCurrent + wcslen( pszCurrent );
|
||||
}
|
||||
|
||||
if ( fTrimEntries )
|
||||
{
|
||||
while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
|
||||
{
|
||||
pszCurrent++;
|
||||
}
|
||||
|
||||
while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
|
||||
{
|
||||
pszEnd--;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszCurrent != pszEnd || !fRemoveEmptyEntries )
|
||||
{
|
||||
if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszNext == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
//#include <dbgutil.h>
|
||||
#include <multisza.hxx>
|
||||
//# include <auxctrs.h>
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// Private Definitions
|
||||
//
|
||||
|
||||
#define MAXULONG 4294967295
|
||||
#define ISWHITE( ch ) ((ch) == L' ' || (ch) == L'\t' || (ch) == L'\r')
|
||||
|
||||
//
|
||||
// When appending data, this is the extra amount we request to avoid
|
||||
// reallocations
|
||||
//
|
||||
#define STR_SLOP 128
|
||||
|
||||
|
||||
DWORD
|
||||
MULTISZA::CalcLength( const CHAR * str,
|
||||
LPDWORD pcStrings )
|
||||
{
|
||||
DWORD count = 0;
|
||||
DWORD total = 1;
|
||||
DWORD len;
|
||||
|
||||
while( *str ) {
|
||||
len = (DWORD)(::strlen( str ) + 1);
|
||||
total += len;
|
||||
str += len;
|
||||
count++;
|
||||
}
|
||||
|
||||
if( pcStrings != NULL ) {
|
||||
*pcStrings = count;
|
||||
}
|
||||
|
||||
return total;
|
||||
|
||||
} // MULTISZA::CalcLength
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZA::FindString( const CHAR * str )
|
||||
{
|
||||
|
||||
CHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !::strcmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += ::strlen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZA::FindString
|
||||
|
||||
|
||||
BOOL
|
||||
MULTISZA::FindStringNoCase( const CHAR * str )
|
||||
{
|
||||
|
||||
CHAR * multisz;
|
||||
|
||||
//
|
||||
// Sanity check.
|
||||
//
|
||||
|
||||
DBG_ASSERT( QueryStr() != NULL );
|
||||
DBG_ASSERT( str != NULL );
|
||||
DBG_ASSERT( *str != '\0' );
|
||||
|
||||
//
|
||||
// Scan it.
|
||||
//
|
||||
|
||||
multisz = QueryStr();
|
||||
|
||||
while( *multisz != '\0' ) {
|
||||
|
||||
if( !_stricmp( multisz, str ) ) {
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
multisz += strlen( multisz ) + 1;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
} // MULTISZA::FindStringNoCase
|
||||
|
||||
|
||||
VOID
|
||||
MULTISZA::AuxInit( const CHAR * pInit )
|
||||
{
|
||||
BOOL fRet;
|
||||
|
||||
if ( pInit )
|
||||
{
|
||||
DWORD cStrings;
|
||||
int cbCopy = CalcLength( pInit, &cStrings ) * sizeof(CHAR);
|
||||
fRet = Resize( cbCopy );
|
||||
|
||||
if ( fRet ) {
|
||||
CopyMemory( QueryPtr(), pInit, cbCopy );
|
||||
m_cchLen = (cbCopy)/sizeof(CHAR);
|
||||
m_cStrings = cStrings;
|
||||
} else {
|
||||
// BUFFER::SetValid( FALSE);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Reset();
|
||||
|
||||
}
|
||||
|
||||
} // MULTISZA::AuxInit()
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: MULTISZA::AuxAppend
|
||||
|
||||
SYNOPSIS: Appends the string onto the MULTISZA.
|
||||
|
||||
ENTRY: Object to append
|
||||
********************************************************************/
|
||||
|
||||
BOOL MULTISZA::AuxAppend( const CHAR * pStr, UINT cbStr, BOOL fAddSlop )
|
||||
{
|
||||
DBG_ASSERT( pStr != NULL );
|
||||
|
||||
UINT cbThis = QueryCB();
|
||||
|
||||
if( cbThis == 2 ) {
|
||||
|
||||
//
|
||||
// It's empty, so start at the beginning.
|
||||
//
|
||||
|
||||
cbThis = 0;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// It's not empty, so back up over the final terminating NULL.
|
||||
//
|
||||
|
||||
cbThis -= sizeof(CHAR);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Only resize when we have to. When we do resize, we tack on
|
||||
// some extra space to avoid extra reallocations.
|
||||
//
|
||||
// Note: QuerySize returns the requested size of the string buffer,
|
||||
// *not* the strlen of the buffer
|
||||
//
|
||||
|
||||
//AcIncrement( CacMultiszAppend);
|
||||
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
// ( 2 * sizeof( CHAR ) ) is for the double terminator
|
||||
//
|
||||
ULONGLONG cb64Required = (ULONGLONG)cbThis + cbStr + 2 * sizeof(CHAR);
|
||||
if ( cb64Required > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( QuerySize() < (DWORD) cb64Required )
|
||||
{
|
||||
ULONGLONG cb64AllocSize = cb64Required + (fAddSlop ? STR_SLOP : 0 );
|
||||
//
|
||||
// Check for the arithmetic overflow
|
||||
//
|
||||
if ( cb64AllocSize > MAXULONG )
|
||||
{
|
||||
SetLastError( ERROR_ARITHMETIC_OVERFLOW );
|
||||
return FALSE;
|
||||
}
|
||||
if ( !Resize( (DWORD) cb64AllocSize ) )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy the exact string and tack on the double terminator
|
||||
memcpy( (BYTE *) QueryPtr() + cbThis,
|
||||
pStr,
|
||||
cbStr);
|
||||
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr) = L'\0';
|
||||
*(CHAR *)((BYTE *)QueryPtr() + cbThis + cbStr + sizeof(CHAR) ) = L'\0';
|
||||
|
||||
m_cchLen = CalcLength( (const CHAR *)QueryPtr(), &m_cStrings );
|
||||
return TRUE;
|
||||
|
||||
} // MULTISZA::AuxAppend()
|
||||
|
||||
BOOL
|
||||
MULTISZA::CopyToBuffer( __out_ecount_opt(*lpcch) CHAR * lpszBuffer, LPDWORD lpcch) const
|
||||
/*++
|
||||
Description:
|
||||
Copies the string into the CHAR buffer passed in if the buffer
|
||||
is sufficient to hold the translated string.
|
||||
If the buffer is small, the function returns small and sets *lpcch
|
||||
to contain the required number of characters.
|
||||
|
||||
Arguments:
|
||||
lpszBuffer pointer to CHAR buffer which on return contains
|
||||
the string on success.
|
||||
lpcch pointer to DWORD containing the length of the buffer.
|
||||
If *lpcch == 0 then the function returns TRUE with
|
||||
the count of characters required stored in lpcch.
|
||||
Also in this case lpszBuffer is not affected.
|
||||
Returns:
|
||||
TRUE on success.
|
||||
FALSE on failure. Use GetLastError() for further details.
|
||||
|
||||
History:
|
||||
MuraliK 20-Nov-1996
|
||||
--*/
|
||||
{
|
||||
BOOL fReturn = TRUE;
|
||||
|
||||
if ( lpcch == NULL) {
|
||||
SetLastError( ERROR_INVALID_PARAMETER);
|
||||
return ( FALSE);
|
||||
}
|
||||
|
||||
register DWORD cch = QueryCCH();
|
||||
|
||||
if ( *lpcch >= cch) {
|
||||
|
||||
DBG_ASSERT( lpszBuffer);
|
||||
memcpy( lpszBuffer, QueryStr(), cch * sizeof(CHAR));
|
||||
} else {
|
||||
DBG_ASSERT( *lpcch < cch);
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||||
fReturn = FALSE;
|
||||
}
|
||||
|
||||
*lpcch = cch;
|
||||
|
||||
return ( fReturn);
|
||||
} // MULTISZA::CopyToBuffer()
|
||||
|
||||
BOOL
|
||||
MULTISZA::Equals(
|
||||
MULTISZA* pmszRhs
|
||||
)
|
||||
//
|
||||
// Compares this to pmszRhs, returns TRUE if equal
|
||||
//
|
||||
{
|
||||
DBG_ASSERT( NULL != pmszRhs );
|
||||
|
||||
PCSTR pszLhs = First( );
|
||||
PCSTR pszRhs = pmszRhs->First( );
|
||||
|
||||
if( m_cStrings != pmszRhs->m_cStrings )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while( NULL != pszLhs )
|
||||
{
|
||||
DBG_ASSERT( NULL != pszRhs );
|
||||
|
||||
if( 0 != strcmp( pszLhs, pszRhs ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pszLhs = Next( pszLhs );
|
||||
pszRhs = pmszRhs->Next( pszRhs );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
SplitCommaDelimitedString(
|
||||
PCSTR pszList,
|
||||
BOOL fTrimEntries,
|
||||
BOOL fRemoveEmptyEntries,
|
||||
MULTISZA * pmszList
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Split comma delimited string into a MULTISZA. Additional leading empty
|
||||
entries after the first are discarded.
|
||||
|
||||
Arguments:
|
||||
|
||||
pszList - List to split up
|
||||
fTrimEntries - Whether each entry should be trimmed before added to MULTISZA
|
||||
fRemoveEmptyEntries - Whether empty entires should be discarded
|
||||
pmszList - Filled with MULTISZA list
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( pszList == NULL ||
|
||||
pmszList == NULL )
|
||||
{
|
||||
DBG_ASSERT( FALSE );
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pmszList->Reset();
|
||||
|
||||
/*
|
||||
pszCurrent: start of the current entry which may be the comma that
|
||||
precedes the next entry if the entry is empty
|
||||
|
||||
pszNext: the comma that precedes the next entry. If
|
||||
pszCurrent == pszNext, then the entry is empty
|
||||
|
||||
pszEnd: just past the end of the current entry
|
||||
*/
|
||||
|
||||
for ( PCSTR pszCurrent = pszList,
|
||||
pszNext = strchr( pszCurrent, L',' )
|
||||
;
|
||||
;
|
||||
pszCurrent = pszNext + 1,
|
||||
pszNext = strchr( pszCurrent, L',' ) )
|
||||
{
|
||||
PCSTR pszEnd = NULL;
|
||||
|
||||
if ( pszNext != NULL )
|
||||
{
|
||||
pszEnd = pszNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszEnd = pszCurrent + strlen( pszCurrent );
|
||||
}
|
||||
|
||||
if ( fTrimEntries )
|
||||
{
|
||||
while ( pszCurrent < pszEnd && ISWHITE( pszCurrent[ 0 ] ) )
|
||||
{
|
||||
pszCurrent++;
|
||||
}
|
||||
|
||||
while ( pszEnd > pszCurrent && ISWHITE( pszEnd[ -1 ] ) )
|
||||
{
|
||||
pszEnd--;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszCurrent != pszEnd || !fRemoveEmptyEntries )
|
||||
{
|
||||
if ( !pmszList->Append( pszCurrent, (DWORD) ( pszEnd - pszCurrent ) ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( GetLastError() );
|
||||
goto Finished;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pszNext == NULL )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,890 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "normalize.h"
|
||||
#include "stringa.h"
|
||||
|
||||
BOOL g_fEnableNonUTF8;
|
||||
BOOL g_fEnableDBCS;
|
||||
BOOL g_fIsSystemDBCS;
|
||||
static BOOL g_fFavorDBCS;
|
||||
|
||||
#ifndef STACK_STRA
|
||||
#define STACK_STRA(name, size) CHAR __ach##name[size]; \
|
||||
STRA name(__ach##name, sizeof(__ach##name) / sizeof(CHAR))
|
||||
#endif
|
||||
|
||||
HRESULT
|
||||
InitializeNormalizeUrl(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwType;
|
||||
DWORD dwData;
|
||||
DWORD cbData;
|
||||
WORD wPrimaryLangID;
|
||||
|
||||
//
|
||||
// Read the registry settings on how to handle URLs
|
||||
//
|
||||
|
||||
g_fEnableNonUTF8 = TRUE;
|
||||
g_fEnableDBCS = FALSE;
|
||||
g_fFavorDBCS = FALSE;
|
||||
|
||||
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||||
L"System\\CurrentControlSet\\Services\\http\\Parameters",
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey ) == ERROR_SUCCESS )
|
||||
{
|
||||
cbData = sizeof( dwData );
|
||||
if ( RegQueryValueEx( hKey,
|
||||
L"EnableNonUTF8",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE) &dwData,
|
||||
&cbData ) == ERROR_SUCCESS &&
|
||||
dwType == REG_DWORD )
|
||||
{
|
||||
g_fEnableNonUTF8 = !!dwData;
|
||||
}
|
||||
|
||||
if ( g_fEnableNonUTF8 )
|
||||
{
|
||||
cbData = sizeof( dwData );
|
||||
|
||||
if ( RegQueryValueEx( hKey,
|
||||
L"EnableDBCS",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE) &dwData,
|
||||
&cbData ) == ERROR_SUCCESS &&
|
||||
dwType == REG_DWORD )
|
||||
{
|
||||
g_fEnableDBCS = !!dwData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fEnableDBCS = FALSE;
|
||||
}
|
||||
|
||||
if ( g_fEnableDBCS )
|
||||
{
|
||||
cbData = sizeof( dwData );
|
||||
|
||||
if ( RegQueryValueEx( hKey,
|
||||
L"FavorDBCS",
|
||||
NULL,
|
||||
&dwType,
|
||||
(LPBYTE) &dwData,
|
||||
&cbData ) == ERROR_SUCCESS &&
|
||||
dwType == REG_DWORD )
|
||||
{
|
||||
g_fFavorDBCS = !!dwData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fFavorDBCS = FALSE;
|
||||
}
|
||||
|
||||
RegCloseKey( hKey );
|
||||
}
|
||||
|
||||
|
||||
wPrimaryLangID = PRIMARYLANGID( GetSystemDefaultLangID() );
|
||||
|
||||
g_fIsSystemDBCS = ( wPrimaryLangID == LANG_JAPANESE ||
|
||||
wPrimaryLangID == LANG_CHINESE ||
|
||||
wPrimaryLangID == LANG_KOREAN );
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Private constants.
|
||||
//
|
||||
|
||||
#define ACTION_NOTHING 0x00000000
|
||||
#define ACTION_EMIT_CH 0x00010000
|
||||
#define ACTION_EMIT_DOT_CH 0x00020000
|
||||
#define ACTION_EMIT_DOT_DOT_CH 0x00030000
|
||||
#define ACTION_BACKUP 0x00040000
|
||||
#define ACTION_MASK 0xFFFF0000
|
||||
|
||||
|
||||
//
|
||||
// Private globals.
|
||||
//
|
||||
|
||||
INT p_StateTable[16] =
|
||||
{
|
||||
// state 0
|
||||
0 , // other
|
||||
0 , // "."
|
||||
4 , // EOS
|
||||
1 , // "\"
|
||||
|
||||
// state 1
|
||||
0 , // other
|
||||
2 , // "."
|
||||
4 , // EOS
|
||||
1 , // "\"
|
||||
|
||||
// state 2
|
||||
0 , // other
|
||||
3 , // "."
|
||||
4 , // EOS
|
||||
1 , // "\"
|
||||
|
||||
// state 3
|
||||
0 , // other
|
||||
0 , // "."
|
||||
4 , // EOS
|
||||
1 // "\"
|
||||
};
|
||||
|
||||
|
||||
|
||||
INT p_ActionTable[16] =
|
||||
{
|
||||
// state 0
|
||||
ACTION_EMIT_CH, // other
|
||||
ACTION_EMIT_CH, // "."
|
||||
ACTION_EMIT_CH, // EOS
|
||||
ACTION_EMIT_CH, // "\"
|
||||
|
||||
// state 1
|
||||
ACTION_EMIT_CH, // other
|
||||
ACTION_NOTHING, // "."
|
||||
ACTION_EMIT_CH, // EOS
|
||||
ACTION_NOTHING, // "\"
|
||||
|
||||
// state 2
|
||||
ACTION_EMIT_DOT_CH, // other
|
||||
ACTION_NOTHING, // "."
|
||||
ACTION_EMIT_CH, // EOS
|
||||
ACTION_NOTHING, // "\"
|
||||
|
||||
// state 3
|
||||
ACTION_EMIT_DOT_DOT_CH, // other
|
||||
ACTION_EMIT_DOT_DOT_CH, // "."
|
||||
ACTION_BACKUP, // EOS
|
||||
ACTION_BACKUP // "\"
|
||||
};
|
||||
|
||||
// since max states = 4, we calculat the index by multiplying with 4.
|
||||
# define IndexFromState( st) ( (st) * 4)
|
||||
|
||||
|
||||
// the following table provides the index for various ISA Latin1 characters
|
||||
// in the incoming URL.
|
||||
// It assumes that the URL is ISO Latin1 == ASCII
|
||||
INT p_rgIndexForChar[] = {
|
||||
|
||||
2, // null char
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 thru 10
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11 thru 20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21 thru 30
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 31 thru 40
|
||||
0, 0, 0, 0, 0, 1, 3, 0, 0, 0, // 41 thru 50 46 = '.' 47 = '/'
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 51 thru 60
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 61 thru 70
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 71 thru 80
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 81 thru 90
|
||||
0, 3, 0, 0, 0, 0, 0, 0, 0, 0, // 91 thru 100 92 = '\\'
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 101 thru 110
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 111 thru 120
|
||||
0, 0, 0, 0, 0, 0, 0, 0 // 121 thru 128
|
||||
};
|
||||
|
||||
#define IS_UTF8_TRAILBYTE(ch) (((ch) & 0xc0) == 0x80)
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: IsUTF8URL
|
||||
|
||||
ENTRY: pszPath - The path to sanitize.
|
||||
|
||||
HISTORY:
|
||||
atsusk 06-Jan-1998 Created.
|
||||
|
||||
********************************************************************/
|
||||
|
||||
BOOL IsUTF8URL(__in LPSTR pszPath)
|
||||
{
|
||||
CHAR ch;
|
||||
|
||||
if ( g_fFavorDBCS )
|
||||
{
|
||||
return ( MultiByteToWideChar( CP_ACP,
|
||||
MB_ERR_INVALID_CHARS,
|
||||
pszPath,
|
||||
-1,
|
||||
NULL,
|
||||
0) == 0);
|
||||
}
|
||||
|
||||
while (ch = *pszPath++) {
|
||||
|
||||
if (ch & 0x80) {
|
||||
wchar_t wch;
|
||||
int iLen;
|
||||
BOOL bDefault = FALSE;
|
||||
char chTrail1;
|
||||
char chTrail2;
|
||||
|
||||
chTrail1 = *pszPath++;
|
||||
if (chTrail1) {
|
||||
chTrail2 = *pszPath;
|
||||
} else {
|
||||
chTrail2 = 0;
|
||||
}
|
||||
|
||||
if ( ((ch & 0xF0) == 0xE0) &&
|
||||
IS_UTF8_TRAILBYTE(chTrail1) &&
|
||||
IS_UTF8_TRAILBYTE(chTrail2) ) {
|
||||
|
||||
// handle three byte case
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
wch = (wchar_t) (((ch & 0x0f) << 12) |
|
||||
((chTrail1 & 0x3f) << 6) |
|
||||
(chTrail2 & 0x3f));
|
||||
pszPath++;
|
||||
|
||||
} else
|
||||
if ( ((ch & 0xE0) == 0xC0) &&
|
||||
IS_UTF8_TRAILBYTE(chTrail1) ) {
|
||||
|
||||
// handle two byte case
|
||||
// 110xxxxx 10xxxxxx
|
||||
|
||||
wch = (wchar_t) (((ch & 0x1f) << 6) | (chTrail1 & 0x3f));
|
||||
|
||||
} else
|
||||
return FALSE;
|
||||
|
||||
iLen = WideCharToMultiByte( CP_ACP,
|
||||
WC_NO_BEST_FIT_CHARS,
|
||||
&wch,
|
||||
1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&bDefault );
|
||||
|
||||
if (bDefault == TRUE || iLen == 0 || iLen > 2)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} // IsUTF8URL()
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
NAME: CanonURL
|
||||
|
||||
SYNOPSIS: Sanitizes a path by removing bogus path elements.
|
||||
|
||||
As expected, "/./" entries are simply removed, and
|
||||
"/../" entries are removed along with the previous
|
||||
path element.
|
||||
|
||||
To maintain compatibility with URL path semantics
|
||||
additional transformations are required. All backward
|
||||
slashes "\\" are converted to forward slashes. Any
|
||||
repeated forward slashes (such as "///") are mapped to
|
||||
single backslashes.
|
||||
|
||||
A state table (see the p_StateTable global at the
|
||||
beginning of this file) is used to perform most of
|
||||
the transformations. The table's rows are indexed
|
||||
by current state, and the columns are indexed by
|
||||
the current character's "class" (either slash, dot,
|
||||
NULL, or other). Each entry in the table consists
|
||||
of the new state tagged with an action to perform.
|
||||
See the ACTION_* constants for the valid action
|
||||
codes.
|
||||
|
||||
ENTRY: pszPath - The path to sanitize.
|
||||
fIsDBCSLocale - Indicates the server is in a
|
||||
locale that uses DBCS.
|
||||
|
||||
HISTORY:
|
||||
KeithMo 07-Sep-1994 Created.
|
||||
MuraliK 28-Apr-1995 Adopted this for symbolic paths
|
||||
|
||||
********************************************************************/
|
||||
INT
|
||||
CanonURL(
|
||||
__inout LPSTR pszPath,
|
||||
BOOL fIsDBCSLocale
|
||||
)
|
||||
{
|
||||
UCHAR * pszSrc;
|
||||
UCHAR * pszDest;
|
||||
DWORD ch;
|
||||
INT index;
|
||||
BOOL fDBCS = FALSE;
|
||||
DWORD cchMultiByte = 0;
|
||||
|
||||
DBG_ASSERT( pszPath != NULL );
|
||||
|
||||
//
|
||||
// Always look for UTF8 except when DBCS characters are detected
|
||||
//
|
||||
BOOL fScanForUTF8 = IsUTF8URL(pszPath);
|
||||
|
||||
// If fScanForUTF8 is true, this URL is UTF8. don't recognize DBCS.
|
||||
if (fIsDBCSLocale && fScanForUTF8) {
|
||||
fIsDBCSLocale = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Start our scan at the first character
|
||||
//
|
||||
|
||||
pszSrc = pszDest = (UCHAR *) pszPath;
|
||||
|
||||
//
|
||||
// State 0 is the initial state.
|
||||
//
|
||||
index = 0; // State = 0
|
||||
|
||||
//
|
||||
// Loop until we enter state 4 (the final, accepting state).
|
||||
//
|
||||
|
||||
do {
|
||||
|
||||
//
|
||||
// Grab the next character from the path and compute its
|
||||
// next state. While we're at it, map any forward
|
||||
// slashes to backward slashes.
|
||||
//
|
||||
|
||||
index = IndexFromState( p_StateTable[index]); // 4 = # states
|
||||
ch = (DWORD ) *pszSrc++;
|
||||
|
||||
//
|
||||
// If this is a DBCS trailing byte - skip it
|
||||
//
|
||||
|
||||
if ( !fIsDBCSLocale )
|
||||
{
|
||||
index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( fDBCS )
|
||||
{
|
||||
//
|
||||
// If this is a 0 terminator, we need to set next
|
||||
// state accordingly
|
||||
//
|
||||
|
||||
if ( ch == 0 )
|
||||
{
|
||||
index += p_rgIndexForChar[ ch ];
|
||||
}
|
||||
|
||||
//
|
||||
// fDBCS == TRUE means this byte was a trail byte.
|
||||
// index is implicitly set to zero.
|
||||
//
|
||||
fDBCS = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]);
|
||||
|
||||
if ( IsDBCSLeadByte( (UCHAR)ch ) )
|
||||
{
|
||||
//
|
||||
// This is a lead byte, so the next is a trail.
|
||||
//
|
||||
fDBCS = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Interesting UTF8 characters always have the top bit set
|
||||
//
|
||||
|
||||
if ( (ch & 0x80) && fScanForUTF8 )
|
||||
{
|
||||
wchar_t wch;
|
||||
UCHAR mbstr[2];
|
||||
|
||||
//
|
||||
// This is a UTF8 character, convert it here.
|
||||
// index is implicitly set to zero.
|
||||
//
|
||||
if ( cchMultiByte < 2 )
|
||||
{
|
||||
char chTrail1;
|
||||
char chTrail2;
|
||||
|
||||
chTrail1 = *pszSrc;
|
||||
if (chTrail1) {
|
||||
chTrail2 = *(pszSrc+1);
|
||||
} else {
|
||||
chTrail2 = 0;
|
||||
}
|
||||
wch = 0;
|
||||
|
||||
if ((ch & 0xf0) == 0xe0)
|
||||
{
|
||||
// handle three byte case
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
wch = (wchar_t) (((ch & 0x0f) << 12) |
|
||||
((chTrail1 & 0x3f) << 6) |
|
||||
(chTrail2 & 0x3f));
|
||||
|
||||
cchMultiByte = WideCharToMultiByte( CP_ACP,
|
||||
WC_NO_BEST_FIT_CHARS,
|
||||
&wch,
|
||||
1,
|
||||
(LPSTR) mbstr,
|
||||
2,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
ch = mbstr[0];
|
||||
pszSrc += (3 - cchMultiByte);
|
||||
|
||||
// WinSE 12843: Security Fix, Index should be updated for this character
|
||||
index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]);
|
||||
|
||||
} else if ((ch & 0xe0) == 0xc0)
|
||||
{
|
||||
// handle two byte case
|
||||
// 110xxxxx 10xxxxxx
|
||||
|
||||
wch = (wchar_t) (((ch & 0x1f) << 6) | (chTrail1 & 0x3f));
|
||||
|
||||
cchMultiByte = WideCharToMultiByte( CP_ACP,
|
||||
WC_NO_BEST_FIT_CHARS,
|
||||
&wch,
|
||||
1,
|
||||
(LPSTR) mbstr,
|
||||
2,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
ch = mbstr[0];
|
||||
pszSrc += (2 - cchMultiByte);
|
||||
|
||||
// WinSE 12843: Security Fix, Index should be updated for this character
|
||||
index += (( ch >= 0x80) ? 0 : p_rgIndexForChar[ch]);
|
||||
}
|
||||
|
||||
} else {
|
||||
//
|
||||
// get ready to emit 2nd byte of converted character
|
||||
//
|
||||
ch = mbstr[1];
|
||||
cchMultiByte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Perform the action associated with the state.
|
||||
//
|
||||
|
||||
switch( p_ActionTable[index] )
|
||||
{
|
||||
case ACTION_EMIT_DOT_DOT_CH :
|
||||
*pszDest++ = '.';
|
||||
/* fall through */
|
||||
|
||||
case ACTION_EMIT_DOT_CH :
|
||||
*pszDest++ = '.';
|
||||
/* fall through */
|
||||
|
||||
case ACTION_EMIT_CH :
|
||||
*pszDest++ = (CHAR ) ch;
|
||||
/* fall through */
|
||||
|
||||
case ACTION_NOTHING :
|
||||
break;
|
||||
|
||||
case ACTION_BACKUP :
|
||||
if( (pszDest > ( (UCHAR *) pszPath + 1 ) ) && (*pszPath == '/'))
|
||||
{
|
||||
pszDest--;
|
||||
DBG_ASSERT( *pszDest == '/' );
|
||||
|
||||
*pszDest = '\0';
|
||||
pszDest = (UCHAR *) strrchr( pszPath, '/') + 1;
|
||||
}
|
||||
|
||||
*pszDest = '\0';
|
||||
break;
|
||||
|
||||
default :
|
||||
DBG_ASSERT( !"Invalid action code in state table!" );
|
||||
index = IndexFromState(0) + 2; // move to invalid state
|
||||
DBG_ASSERT( p_StateTable[index] == 4);
|
||||
*pszDest++ = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
} while( p_StateTable[index] != 4 );
|
||||
|
||||
//
|
||||
// point to terminating nul
|
||||
// only do the check if we aren't about to go outside of the number
|
||||
// of elements in the table.
|
||||
//
|
||||
if ( ( index < ( sizeof(p_ActionTable) / sizeof(p_ActionTable[0]) ) )
|
||||
&& p_ActionTable[index] == ACTION_EMIT_CH )
|
||||
{
|
||||
pszDest--;
|
||||
}
|
||||
|
||||
DBG_ASSERT(*pszDest == '\0' && pszDest > (UCHAR*) pszPath);
|
||||
|
||||
return (INT)DIFF(pszDest - (UCHAR*)pszPath);
|
||||
} // CanonURL()
|
||||
|
||||
|
||||
|
||||
HRESULT
|
||||
NormalizeUrl(
|
||||
__inout LPSTR pszStart
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Normalize URL
|
||||
|
||||
Arguments:
|
||||
|
||||
strUrl - URL to be updated to a canonical URI
|
||||
|
||||
Return value:
|
||||
|
||||
TRUE if no error, otherwise FALSE
|
||||
|
||||
--*/
|
||||
{
|
||||
CHAR * pchParams;
|
||||
LPSTR pszSlash;
|
||||
LPSTR pszURL;
|
||||
LPSTR pszValue;
|
||||
STACK_STRA( strChgUrl, MAX_PATH );
|
||||
HRESULT hr;
|
||||
DWORD cchInput;
|
||||
|
||||
if ( pszStart == NULL )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
}
|
||||
|
||||
cchInput = (DWORD)strlen( pszStart );
|
||||
|
||||
if ( *pszStart != '/' )
|
||||
{
|
||||
//
|
||||
// assume HTTP URL, skip protocol & host name by
|
||||
// searching for 1st '/' following "//"
|
||||
//
|
||||
// We handle this information as a "Host:" header.
|
||||
// It will be overwritten by the real header if it is
|
||||
// present.
|
||||
//
|
||||
// We do not check for a match in this case.
|
||||
//
|
||||
|
||||
if ( (pszSlash = strchr( pszStart, '/' )) && pszSlash[1] == '/' )
|
||||
{
|
||||
pszSlash += 2;
|
||||
if ( pszURL = strchr( pszSlash, '/' ) )
|
||||
{
|
||||
//
|
||||
// update pointer to URL to point to the 1st slash
|
||||
// following host name
|
||||
//
|
||||
|
||||
pszValue = pszURL;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// if no single slash following host name
|
||||
// consider the URL to be empty.
|
||||
//
|
||||
|
||||
pszValue = pszSlash + strlen( pszSlash );
|
||||
}
|
||||
|
||||
memmove( pszStart, pszValue, strlen(pszValue)+1 );
|
||||
}
|
||||
|
||||
//
|
||||
// if no double slash, this is not a fully qualified URL
|
||||
// and we leave it alone.
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// Check for a question mark which indicates this URL contains some
|
||||
// parameters and break the two apart if found
|
||||
//
|
||||
|
||||
if ( (pchParams = strchr( pszStart, '?' )) )
|
||||
{
|
||||
*pchParams = '\0';
|
||||
}
|
||||
|
||||
//
|
||||
// Unescape wants a STR ( sigh )
|
||||
//
|
||||
|
||||
hr = strChgUrl.Copy( (CHAR*)pszStart );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
strChgUrl.Unescape();
|
||||
|
||||
hr = StringCchCopyNA( pszStart, cchInput + 1, strChgUrl.QueryStr(), cchInput );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// Canonicalize the URL
|
||||
//
|
||||
|
||||
CanonURL( pszStart, g_fIsSystemDBCS );
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
HRESULT
|
||||
NormalizeUrlOld(
|
||||
__inout LPSTR pszUrl
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
NormalizeUrl wrapper (used by ISAPI filter and extension support functions)
|
||||
|
||||
Parameters:
|
||||
|
||||
pszUrl - On entry, the URL to be normalized
|
||||
On return, the normalized URL
|
||||
(size of normalized URL is always <= not normalized URL)
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr = NO_ERROR;
|
||||
|
||||
if ( pszUrl )
|
||||
{
|
||||
STACK_BUFFER( buffUrlOutput, MAX_PATH );
|
||||
STACK_STRA( strUrlA, MAX_PATH );
|
||||
LPWSTR szQueryString;
|
||||
DWORD cchData;
|
||||
DWORD cbOutput;
|
||||
|
||||
cchData = (DWORD)strlen( pszUrl );
|
||||
|
||||
//
|
||||
// Prepare the Output string
|
||||
//
|
||||
|
||||
if ( !buffUrlOutput.Resize( ( cchData + 1 ) *sizeof( WCHAR ) ) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize it
|
||||
//
|
||||
|
||||
hr = UlCleanAndCopyUrl(
|
||||
pszUrl,
|
||||
cchData,
|
||||
&cbOutput,
|
||||
(WCHAR *) buffUrlOutput.QueryPtr(),
|
||||
&szQueryString
|
||||
);
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// Terminate the string at the query so that the
|
||||
// query string doesn't appear in the output. IIS 5
|
||||
// truncated in this way.
|
||||
//
|
||||
|
||||
if ( szQueryString != NULL )
|
||||
{
|
||||
((WCHAR *) buffUrlOutput.QueryPtr())[ cbOutput - wcslen( szQueryString )] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Write the normalized URL over the input data
|
||||
//
|
||||
|
||||
hr = strUrlA.CopyW( (WCHAR *) buffUrlOutput.QueryPtr() );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// Normalized string will never be longer than the original one
|
||||
//
|
||||
|
||||
DBG_ASSERT( strUrlA.QueryCCH() <= cchData );
|
||||
|
||||
hr = StringCchCopyA( pszUrl, cchData + 1, strUrlA.QueryStr() );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = NO_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
NormalizeUrlW(
|
||||
__inout LPWSTR pszUrl
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
unicode version of NormalizeUrl wrapper (used by ISAPI filter and extension support functions)
|
||||
|
||||
Parameters:
|
||||
|
||||
pszUrl - On entry, the URL to be normalized
|
||||
On return, the normalized URL
|
||||
(size of normalized URL is always <= not normalized URL)
|
||||
|
||||
Return Value:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
|
||||
HRESULT hr = NO_ERROR;
|
||||
|
||||
if ( pszUrl )
|
||||
{
|
||||
STACK_BUFFER( buffUrlOutput, MAX_PATH );
|
||||
STACK_STRA( strUrlA, MAX_PATH );
|
||||
LPWSTR szQueryString;
|
||||
DWORD cchData;
|
||||
DWORD cbOutput;
|
||||
|
||||
cchData = (DWORD)wcslen( pszUrl );
|
||||
|
||||
hr = strUrlA.CopyWToUTF8Escaped( pszUrl );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Output string
|
||||
//
|
||||
|
||||
if ( !buffUrlOutput.Resize( ( cchData + 1 ) *sizeof( WCHAR ) ) )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize it
|
||||
//
|
||||
|
||||
hr = UlCleanAndCopyUrl(
|
||||
strUrlA.QueryStr(),
|
||||
strUrlA.QueryCB(),
|
||||
&cbOutput,
|
||||
(WCHAR *) buffUrlOutput.QueryPtr(),
|
||||
&szQueryString
|
||||
);
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Terminate the string at the query so that the
|
||||
// query string doesn't appear in the output. IIS 5
|
||||
// truncated in this way.
|
||||
//
|
||||
|
||||
if ( szQueryString != NULL )
|
||||
{
|
||||
((WCHAR *) buffUrlOutput.QueryPtr())[ cbOutput - wcslen( szQueryString )] = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// normalized string will never be longer than the original one
|
||||
//
|
||||
|
||||
DBG_ASSERT( cbOutput <= cchData * sizeof( WCHAR ) );
|
||||
|
||||
//
|
||||
// Write the normalized URL over the input data
|
||||
//
|
||||
|
||||
hr = StringCchCopyW( pszUrl, cchData+1, (WCHAR *) buffUrlOutput.QueryPtr() );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = NO_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="VisualCppTools.Community.VS2017Layout" version="14.11.25547" developmentDependency="true" />
|
||||
</packages>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include <windows.h>
|
||||
#include <ahadmin.h>
|
||||
#pragma warning( disable:4127 )
|
||||
#include <atlcomcli.h>
|
||||
#include <strsafe.h>
|
||||
#include <intsafe.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "stringu.h"
|
||||
#include "stringa.h"
|
||||
#include "dbgutil.h"
|
||||
#include "ntassert.h"
|
||||
#include "ahutil.h"
|
||||
#include "acache.h"
|
||||
#include "base64.hxx"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
HRESULT
|
||||
MakePathCanonicalizationProof(
|
||||
IN PCWSTR pszName,
|
||||
OUT STRU * pstrPath
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This functions adds a prefix
|
||||
to the string, which is "\\?\UNC\" for a UNC path, and "\\?\" for
|
||||
other paths. This prefix tells Windows not to parse the path.
|
||||
|
||||
Arguments:
|
||||
|
||||
IN pszName - The path to be converted
|
||||
OUT pstrPath - Output path created
|
||||
|
||||
Return Values:
|
||||
|
||||
HRESULT
|
||||
|
||||
--*/
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (pszName[0] == L'\\' && pszName[1] == L'\\')
|
||||
{
|
||||
//
|
||||
// If the path is already canonicalized, just return
|
||||
//
|
||||
|
||||
if ((pszName[2] == '?' || pszName[2] == '.') &&
|
||||
pszName[3] == '\\')
|
||||
{
|
||||
hr = pstrPath->Copy(pszName);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//
|
||||
// If the path was in DOS form ("\\.\"),
|
||||
// we need to change it to Win32 from ("\\?\")
|
||||
//
|
||||
|
||||
pstrPath->QueryStr()[2] = L'?';
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
pszName += 2;
|
||||
|
||||
|
||||
if (FAILED(hr = pstrPath->Copy(L"\\\\?\\UNC\\")))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAILED(hr = pstrPath->Copy(L"\\\\?\\")))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return pstrPath->Append(pszName);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _STLIST_H
|
||||
#define _STLIST_H
|
||||
|
||||
#ifndef IsListEmpty
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define IsListEmpty(ListHead) ((ListHead)->Flink == (ListHead))
|
||||
|
||||
VOID
|
||||
inline
|
||||
InitializeListHead(
|
||||
LIST_ENTRY * ListHead
|
||||
)
|
||||
{
|
||||
ListHead->Flink = ListHead->Blink = ListHead;
|
||||
}
|
||||
|
||||
BOOL
|
||||
inline
|
||||
RemoveEntryList(
|
||||
LIST_ENTRY * Entry
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * Blink;
|
||||
LIST_ENTRY * Flink;
|
||||
|
||||
Flink = Entry->Flink;
|
||||
Blink = Entry->Blink;
|
||||
Blink->Flink = Flink;
|
||||
Flink->Blink = Blink;
|
||||
return (Flink == Blink);
|
||||
}
|
||||
|
||||
PLIST_ENTRY
|
||||
inline
|
||||
RemoveHeadList(
|
||||
LIST_ENTRY * ListHead
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * Flink;
|
||||
LIST_ENTRY * Entry;
|
||||
|
||||
Entry = ListHead->Flink;
|
||||
Flink = Entry->Flink;
|
||||
ListHead->Flink = Flink;
|
||||
Flink->Blink = ListHead;
|
||||
return Entry;
|
||||
}
|
||||
|
||||
VOID
|
||||
inline
|
||||
InsertHeadList(
|
||||
LIST_ENTRY * ListHead,
|
||||
LIST_ENTRY * Entry
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * Flink;
|
||||
|
||||
Flink = ListHead->Flink;
|
||||
Entry->Flink = Flink;
|
||||
Entry->Blink = ListHead;
|
||||
Flink->Blink = Entry;
|
||||
ListHead->Flink = Entry;
|
||||
}
|
||||
|
||||
VOID
|
||||
inline
|
||||
InsertTailList(
|
||||
LIST_ENTRY * ListHead,
|
||||
LIST_ENTRY * Entry
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * Blink;
|
||||
|
||||
Blink = ListHead->Blink;
|
||||
Entry->Flink = ListHead;
|
||||
Entry->Blink = Blink;
|
||||
Blink->Flink = Entry;
|
||||
ListHead->Blink = Entry;
|
||||
}
|
||||
|
||||
#endif // IsListEmpty
|
||||
#endif // _STLIST_H
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _STLOCK_H
|
||||
#define _STLOCK_H
|
||||
|
||||
class STLOCK
|
||||
{
|
||||
public:
|
||||
|
||||
STLOCK()
|
||||
: _fInitialized( FALSE )
|
||||
{
|
||||
}
|
||||
|
||||
~STLOCK()
|
||||
{
|
||||
if ( _fInitialized )
|
||||
{
|
||||
DeleteCriticalSection( &_cs );
|
||||
CloseHandle( _hReadersDone );
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL fResult = FALSE;
|
||||
|
||||
if ( !_fInitialized )
|
||||
{
|
||||
_fWriterWaiting = FALSE;
|
||||
_cReaders = 0;
|
||||
|
||||
fResult = InitializeCriticalSectionAndSpinCount( &_cs, 100 );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
hr = E_FAIL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_hReadersDone = CreateEvent( NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
if ( !_hReadersDone )
|
||||
{
|
||||
DeleteCriticalSection( &_cs );
|
||||
hr = E_FAIL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_fInitialized = TRUE;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryInitialized() const
|
||||
{
|
||||
return _fInitialized;
|
||||
}
|
||||
|
||||
void SharedAcquire()
|
||||
{
|
||||
EnterCriticalSection( &_cs );
|
||||
InterlockedIncrement( &_cReaders );
|
||||
LeaveCriticalSection( &_cs );
|
||||
}
|
||||
|
||||
void SharedRelease()
|
||||
{
|
||||
ReleaseInternal();
|
||||
}
|
||||
|
||||
void ExclusiveAcquire()
|
||||
{
|
||||
EnterCriticalSection( &_cs );
|
||||
|
||||
_fWriterWaiting = TRUE;
|
||||
|
||||
//
|
||||
// If there are any readers, wait for them
|
||||
// to release
|
||||
//
|
||||
|
||||
if ( InterlockedExchangeAdd( &_cReaders, 0 ) > 0 )
|
||||
{
|
||||
WaitForSingleObject( _hReadersDone, INFINITE );
|
||||
}
|
||||
|
||||
//
|
||||
// Reader count -1 indicates that a writer has the lock
|
||||
//
|
||||
|
||||
_cReaders = -1;
|
||||
}
|
||||
|
||||
void ExclusiveRelease()
|
||||
{
|
||||
ReleaseInternal();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL _fInitialized;
|
||||
BOOL _fWriterWaiting;
|
||||
LONG _cReaders;
|
||||
CRITICAL_SECTION _cs;
|
||||
HANDLE _hReadersDone;
|
||||
|
||||
void ReleaseInternal()
|
||||
{
|
||||
LONG cReaders = InterlockedDecrement( &_cReaders );
|
||||
|
||||
if ( cReaders >= 0 )
|
||||
{
|
||||
//
|
||||
// Released a read lock. If this was the last
|
||||
// reader and writers are waiting, set the
|
||||
// readers done event
|
||||
//
|
||||
|
||||
if ( ( _fWriterWaiting ) && ( cReaders == 0 ) )
|
||||
{
|
||||
SetEvent( _hReadersDone );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Released a write lock
|
||||
//
|
||||
|
||||
_cReaders = 0;
|
||||
_fWriterWaiting = FALSE;
|
||||
LeaveCriticalSection( &_cs );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _STLOCK_H
|
||||
|
|
@ -0,0 +1,599 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _STTABLE_H
|
||||
#define _STTABLE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "stbuff.h"
|
||||
#include "stlock.h"
|
||||
#include "stlist.h"
|
||||
|
||||
#define DEFAULT_BUCKETS 97 // largest prime under 100
|
||||
|
||||
class ITEM;
|
||||
class STTABLE_ITEM;
|
||||
|
||||
typedef DWORD (WINAPI * PFN_HASH)(STBUFF*);
|
||||
typedef BOOL (WINAPI * PFN_COMPARE_KEYS)(STBUFF*,STBUFF*);
|
||||
typedef VOID (WINAPI * PFN_ITER)(STTABLE_ITEM*, BOOL*);
|
||||
|
||||
class STTABLE_ITEM
|
||||
{
|
||||
public:
|
||||
|
||||
STTABLE_ITEM()
|
||||
: _cRefs( 1 )
|
||||
{
|
||||
InitializeListHead( &le );
|
||||
}
|
||||
|
||||
VOID
|
||||
Reference()
|
||||
{
|
||||
InterlockedIncrement( &_cRefs );
|
||||
}
|
||||
|
||||
VOID
|
||||
Dereference()
|
||||
{
|
||||
LONG cRefs = InterlockedDecrement( &_cRefs );
|
||||
|
||||
if ( cRefs == 0 )
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
STBUFF * pKey
|
||||
)
|
||||
{
|
||||
return _buffKey.SetData( pKey->QueryPtr(),
|
||||
pKey->QueryDataSize() );
|
||||
}
|
||||
|
||||
STBUFF *
|
||||
QueryKey()
|
||||
{
|
||||
return &_buffKey;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STTABLE_ITEM()
|
||||
{}
|
||||
|
||||
LIST_ENTRY le;
|
||||
|
||||
private:
|
||||
|
||||
LONG _cRefs;
|
||||
STBUFF _buffKey;
|
||||
};
|
||||
|
||||
class STTABLE_BUCKET
|
||||
{
|
||||
public:
|
||||
|
||||
STTABLE_BUCKET()
|
||||
: _pfnCompareKeys( NULL )
|
||||
{}
|
||||
|
||||
virtual
|
||||
~STTABLE_BUCKET()
|
||||
{
|
||||
LIST_ENTRY * pEntry;
|
||||
STTABLE_ITEM * pItem;
|
||||
|
||||
while ( !IsListEmpty( &_Head ) )
|
||||
{
|
||||
pEntry = RemoveHeadList( &_Head );
|
||||
|
||||
pItem = CONTAINING_RECORD( pEntry,
|
||||
STTABLE_ITEM,
|
||||
le );
|
||||
|
||||
pItem->Dereference();
|
||||
pItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
PFN_COMPARE_KEYS pfnCompareKeys = NULL
|
||||
)
|
||||
{
|
||||
InitializeListHead( &_Head );
|
||||
|
||||
_pfnCompareKeys = pfnCompareKeys;
|
||||
|
||||
return _BucketLock.Initialize();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Insert(
|
||||
STTABLE_ITEM * pNewItem
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * pEntry;
|
||||
STTABLE_ITEM * pItem;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
_BucketLock.ExclusiveAcquire();
|
||||
|
||||
//
|
||||
// Check to see if the item is already in the list
|
||||
//
|
||||
|
||||
pEntry = _Head.Flink;
|
||||
|
||||
while ( pEntry != &_Head )
|
||||
{
|
||||
pItem = CONTAINING_RECORD( pEntry,
|
||||
STTABLE_ITEM,
|
||||
le );
|
||||
|
||||
if ( CompareKeys( pNewItem->QueryKey(),
|
||||
pItem->QueryKey() ) )
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEntry = pEntry->Flink;
|
||||
}
|
||||
|
||||
//
|
||||
// It's not in the list. Add it now
|
||||
//
|
||||
|
||||
pNewItem->Reference();
|
||||
InsertTailList( &_Head, &pNewItem->le );
|
||||
|
||||
Finished:
|
||||
|
||||
_BucketLock.ExclusiveRelease();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Remove(
|
||||
STTABLE_ITEM * pItemToRemove
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * pEntry;
|
||||
STTABLE_ITEM * pItem;
|
||||
|
||||
_BucketLock.ExclusiveAcquire();
|
||||
|
||||
//
|
||||
// Find the item in the list
|
||||
//
|
||||
|
||||
pEntry = _Head.Flink;
|
||||
|
||||
while ( pEntry != &_Head )
|
||||
{
|
||||
pItem = CONTAINING_RECORD( pEntry,
|
||||
STTABLE_ITEM,
|
||||
le );
|
||||
|
||||
if ( CompareKeys( pItemToRemove->QueryKey(),
|
||||
pItem->QueryKey() ) )
|
||||
{
|
||||
RemoveEntryList( &pItemToRemove->le );
|
||||
pItemToRemove->Dereference();
|
||||
pItemToRemove = NULL;
|
||||
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEntry = pEntry->Flink;
|
||||
}
|
||||
|
||||
//
|
||||
// Item was not found. Set error code, but
|
||||
// don't fail function.
|
||||
//
|
||||
|
||||
SetLastError (ERROR_FILE_NOT_FOUND);
|
||||
|
||||
Finished:
|
||||
|
||||
_BucketLock.ExclusiveRelease();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetItem(
|
||||
STBUFF * pKey,
|
||||
STTABLE_ITEM **ppItem
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * pEntry;
|
||||
STTABLE_ITEM * pItem;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
_BucketLock.SharedAcquire();
|
||||
|
||||
//
|
||||
// Find the item in the list
|
||||
//
|
||||
|
||||
pEntry = _Head.Flink;
|
||||
|
||||
while ( pEntry != &_Head )
|
||||
{
|
||||
pItem = CONTAINING_RECORD( pEntry,
|
||||
STTABLE_ITEM,
|
||||
le );
|
||||
|
||||
if ( CompareKeys( pKey,
|
||||
pItem->QueryKey() ) )
|
||||
{
|
||||
pItem->Reference();
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
pEntry = pEntry->Flink;
|
||||
}
|
||||
|
||||
//
|
||||
// Item was not found.
|
||||
//
|
||||
|
||||
pItem = NULL;
|
||||
|
||||
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
|
||||
Finished:
|
||||
|
||||
_BucketLock.SharedRelease();
|
||||
|
||||
*ppItem = pItem;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
Iterate(
|
||||
PFN_ITER pIterFunction
|
||||
)
|
||||
{
|
||||
LIST_ENTRY * pEntry;
|
||||
STTABLE_ITEM * pItem;
|
||||
BOOL fRemoveItem;
|
||||
|
||||
////////////////////////////////////////
|
||||
//
|
||||
// It is assumed that this function will
|
||||
// be called under a write lock
|
||||
//
|
||||
////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Walk the list and call the provided
|
||||
// function on each item
|
||||
//
|
||||
|
||||
pEntry = _Head.Flink;
|
||||
|
||||
while ( pEntry != &_Head )
|
||||
{
|
||||
pItem = CONTAINING_RECORD( pEntry,
|
||||
STTABLE_ITEM,
|
||||
le );
|
||||
|
||||
//
|
||||
// The iterator function might remove
|
||||
// the item from the list, so we need
|
||||
// to get the next link first
|
||||
//
|
||||
|
||||
pEntry = pEntry->Flink;
|
||||
|
||||
pItem->Reference();
|
||||
pIterFunction( pItem, &fRemoveItem );
|
||||
|
||||
if ( fRemoveItem )
|
||||
{
|
||||
RemoveEntryList( &pItem->le );
|
||||
pItem->Dereference();
|
||||
pItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LIST_ENTRY _Head;
|
||||
STLOCK _BucketLock;
|
||||
PFN_COMPARE_KEYS _pfnCompareKeys;
|
||||
|
||||
BOOL
|
||||
CompareKeys(
|
||||
STBUFF * pKey1,
|
||||
STBUFF * pKey2
|
||||
)
|
||||
{
|
||||
if ( _pfnCompareKeys )
|
||||
{
|
||||
return _pfnCompareKeys( pKey1,
|
||||
pKey2 );
|
||||
}
|
||||
|
||||
return ( strcmp( pKey1->QueryStr(),
|
||||
pKey2->QueryStr() ) == 0 );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class STTABLE
|
||||
{
|
||||
public:
|
||||
|
||||
STTABLE()
|
||||
: _cBuckets( 0 ),
|
||||
_pfnHash( NULL )
|
||||
{}
|
||||
|
||||
virtual
|
||||
~STTABLE()
|
||||
{
|
||||
STTABLE_BUCKET ** rgBuckets;
|
||||
STTABLE_BUCKET * pBucket;
|
||||
DWORD n;
|
||||
|
||||
rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr();
|
||||
|
||||
for( n = 0; n < _cBuckets; n++ )
|
||||
{
|
||||
pBucket = rgBuckets[n];
|
||||
|
||||
delete pBucket;
|
||||
pBucket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Initialize(
|
||||
DWORD cBuckets = DEFAULT_BUCKETS,
|
||||
PFN_HASH pfnHash = NULL,
|
||||
PFN_COMPARE_KEYS pfnCompareKeys = NULL
|
||||
)
|
||||
{
|
||||
STTABLE_BUCKET ** rgBuckets;
|
||||
DWORD n;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
//
|
||||
// Create a buffer for the bucket array
|
||||
//
|
||||
|
||||
hr = _buffBucketPtrs.Resize( cBuckets * sizeof(STTABLE_BUCKET*) );
|
||||
|
||||
if ( FAILED (hr) )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr();
|
||||
|
||||
//
|
||||
// Create the buckets
|
||||
//
|
||||
|
||||
for ( n = 0; n < cBuckets; n++ )
|
||||
{
|
||||
STTABLE_BUCKET * pNewBucket = new STTABLE_BUCKET;
|
||||
|
||||
if ( !pNewBucket )
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
hr = pNewBucket->Initialize( pfnCompareKeys );
|
||||
|
||||
if ( FAILED (hr) )
|
||||
{
|
||||
delete pNewBucket;
|
||||
pNewBucket = NULL;
|
||||
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
rgBuckets[n] = pNewBucket;
|
||||
pNewBucket = NULL;
|
||||
|
||||
_cBuckets++;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the table lock
|
||||
//
|
||||
|
||||
_TableLock.Initialize();
|
||||
|
||||
//
|
||||
// Set the hash function
|
||||
//
|
||||
|
||||
_pfnHash = pfnHash;
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Insert(
|
||||
STTABLE_ITEM * pNewItem
|
||||
)
|
||||
{
|
||||
|
||||
DWORD dwHash;
|
||||
STTABLE_BUCKET * pBucket;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
dwHash = ComputeHash( pNewItem->QueryKey() );
|
||||
|
||||
pBucket = GetBucket( dwHash );
|
||||
|
||||
_TableLock.SharedAcquire();
|
||||
|
||||
hr = pBucket->Insert( pNewItem );
|
||||
|
||||
_TableLock.SharedRelease();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
Remove(
|
||||
STTABLE_ITEM * pItemToRemove
|
||||
)
|
||||
{
|
||||
DWORD dwHash;
|
||||
STTABLE_BUCKET * pBucket;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
dwHash = ComputeHash( pItemToRemove->QueryKey() );
|
||||
|
||||
pBucket = GetBucket( dwHash );
|
||||
|
||||
_TableLock.SharedAcquire();
|
||||
|
||||
hr = pBucket->Remove( pItemToRemove );
|
||||
|
||||
_TableLock.SharedRelease();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
GetItem(
|
||||
STBUFF * pKey,
|
||||
STTABLE_ITEM **ppItem
|
||||
)
|
||||
{
|
||||
DWORD dwHash;
|
||||
STTABLE_BUCKET * pBucket;
|
||||
STTABLE_ITEM * pRet;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
dwHash = ComputeHash( pKey );
|
||||
|
||||
pBucket = GetBucket( dwHash );
|
||||
|
||||
_TableLock.SharedAcquire();
|
||||
|
||||
hr = pBucket->GetItem( pKey, &pRet );
|
||||
if(FAILED( hr))
|
||||
{
|
||||
pRet = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
||||
_TableLock.SharedRelease();
|
||||
|
||||
*ppItem = pRet;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
Iterate(
|
||||
PFN_ITER pIterFunction
|
||||
)
|
||||
{
|
||||
STTABLE_BUCKET ** rgBuckets;
|
||||
DWORD n;
|
||||
|
||||
_TableLock.ExclusiveAcquire();
|
||||
|
||||
rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr();
|
||||
|
||||
//
|
||||
// Iterate each bucket
|
||||
//
|
||||
|
||||
for ( n = 0; n < _cBuckets; n++ )
|
||||
{
|
||||
STTABLE_BUCKET * pBucket;
|
||||
|
||||
pBucket = rgBuckets[n];
|
||||
|
||||
pBucket->Iterate( pIterFunction );
|
||||
|
||||
pBucket = NULL;
|
||||
}
|
||||
|
||||
_TableLock.ExclusiveRelease();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
STBUFF _buffBucketPtrs;
|
||||
DWORD _cBuckets;
|
||||
STLOCK _TableLock;
|
||||
PFN_HASH _pfnHash;
|
||||
|
||||
DWORD
|
||||
ComputeHash(
|
||||
STBUFF * pKey
|
||||
)
|
||||
{
|
||||
if ( _pfnHash )
|
||||
{
|
||||
return _pfnHash( pKey );
|
||||
}
|
||||
|
||||
return HashString( pKey->QueryStr() );
|
||||
}
|
||||
|
||||
STTABLE_BUCKET *
|
||||
GetBucket(
|
||||
DWORD dwHash
|
||||
)
|
||||
{
|
||||
STTABLE_BUCKET ** rgBuckets;
|
||||
|
||||
rgBuckets = (STTABLE_BUCKET**)_buffBucketPtrs.QueryPtr();
|
||||
|
||||
return rgBuckets[dwHash % _cBuckets];
|
||||
}
|
||||
|
||||
DWORD
|
||||
WINAPI
|
||||
HashString(
|
||||
LPCSTR szString
|
||||
)
|
||||
{
|
||||
DWORD dwRet = 0;
|
||||
|
||||
//
|
||||
// Create a hash by adding up the ascii values
|
||||
// of each character in a case-insensitive manner
|
||||
//
|
||||
|
||||
if ( szString )
|
||||
{
|
||||
while ( *szString )
|
||||
{
|
||||
dwRet += ( (*szString) | 0x20 );
|
||||
szString++;
|
||||
}
|
||||
}
|
||||
|
||||
return dwRet;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _STTABLE_H
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _STTIMER_H
|
||||
#define _STTIMER_H
|
||||
|
||||
class STTIMER
|
||||
{
|
||||
public:
|
||||
|
||||
STTIMER()
|
||||
: _pTimer( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~STTIMER()
|
||||
{
|
||||
if ( _pTimer )
|
||||
{
|
||||
CancelTimer();
|
||||
|
||||
CloseThreadpoolTimer( _pTimer );
|
||||
|
||||
_pTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
InitializeTimer(
|
||||
PTP_TIMER_CALLBACK pfnCallback,
|
||||
VOID * pContext,
|
||||
DWORD dwInitialWait = 0,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
_pTimer = CreateThreadpoolTimer( pfnCallback,
|
||||
pContext,
|
||||
NULL );
|
||||
|
||||
if ( !_pTimer )
|
||||
{
|
||||
return HRESULT_FROM_WIN32( GetLastError() );
|
||||
}
|
||||
|
||||
if ( dwInitialWait )
|
||||
{
|
||||
SetTimer( dwInitialWait,
|
||||
dwPeriod );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetTimer(
|
||||
DWORD dwInitialWait,
|
||||
DWORD dwPeriod = 0
|
||||
)
|
||||
{
|
||||
FILETIME ftInitialWait;
|
||||
|
||||
if ( dwInitialWait == 0 && dwPeriod == 0 )
|
||||
{
|
||||
//
|
||||
// Special case. We are preventing new callbacks
|
||||
// from being queued. Any existing callbacks in the
|
||||
// queue will still run.
|
||||
//
|
||||
// This effectively disables the timer. It can be
|
||||
// re-enabled by setting non-zero initial wait or
|
||||
// period values.
|
||||
//
|
||||
|
||||
SetThreadpoolTimer( _pTimer, NULL, 0, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
|
||||
|
||||
SetThreadpoolTimer( _pTimer,
|
||||
&ftInitialWait,
|
||||
dwPeriod,
|
||||
0 );
|
||||
}
|
||||
|
||||
VOID
|
||||
CancelTimer()
|
||||
{
|
||||
//
|
||||
// Disable the timer
|
||||
//
|
||||
|
||||
SetTimer( 0 );
|
||||
|
||||
//
|
||||
// Wait until any callbacks queued prior to disabling
|
||||
// have completed.
|
||||
//
|
||||
|
||||
WaitForThreadpoolTimerCallbacks( _pTimer, TRUE );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VOID
|
||||
InitializeRelativeFileTime(
|
||||
FILETIME * pft,
|
||||
DWORD dwMilliseconds
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
//
|
||||
// The pftDueTime parameter expects the time to be
|
||||
// expressed as the number of 100 nanosecond intervals
|
||||
// times -1.
|
||||
//
|
||||
// To convert from milliseconds, we'll multiply by
|
||||
// -10000
|
||||
//
|
||||
|
||||
li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
|
||||
|
||||
pft->dwHighDateTime = li.HighPart;
|
||||
pft->dwLowDateTime = li.LowPart;
|
||||
};
|
||||
|
||||
TP_TIMER * _pTimer;
|
||||
};
|
||||
|
||||
class STELAPSED
|
||||
{
|
||||
public:
|
||||
|
||||
STELAPSED()
|
||||
: _dwInitTime( 0 ),
|
||||
_dwInitTickCount( 0 ),
|
||||
_dwPerfCountsPerMillisecond( 0 ),
|
||||
_fUsingHighResolution( FALSE )
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
BOOL fResult;
|
||||
|
||||
_dwInitTickCount = GetTickCount64();
|
||||
|
||||
fResult = QueryPerformanceFrequency( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwPerfCountsPerMillisecond = li.QuadPart / 1000;
|
||||
|
||||
fResult = QueryPerformanceCounter( &li );
|
||||
|
||||
if ( !fResult )
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
_dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
_fUsingHighResolution = TRUE;
|
||||
|
||||
Finished:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
virtual
|
||||
~STELAPSED()
|
||||
{
|
||||
}
|
||||
|
||||
LONGLONG
|
||||
QueryElapsedTime()
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
|
||||
if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
|
||||
{
|
||||
DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
||||
|
||||
if ( dwCurrentTime < _dwInitTime )
|
||||
{
|
||||
//
|
||||
// It's theoretically possible that QueryPerformanceCounter
|
||||
// may return slightly different values on different CPUs.
|
||||
// In this case, we don't want to return an unexpected value
|
||||
// so we'll return zero. This is acceptable because
|
||||
// presumably such a case would only happen for a very short
|
||||
// time window.
|
||||
//
|
||||
// It would be possible to prevent this by ensuring processor
|
||||
// affinity for all calls to QueryPerformanceCounter, but that
|
||||
// would be undesirable in the general case because it could
|
||||
// introduce unnecessary context switches and potentially a
|
||||
// CPU bottleneck.
|
||||
//
|
||||
// Note that this issue also applies to callers doing rapid
|
||||
// calls to this function. If a caller wants to mitigate
|
||||
// that, they could enforce the affinitization, or they
|
||||
// could implement a similar sanity check when comparing
|
||||
// returned values from this function.
|
||||
//
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dwCurrentTime - _dwInitTime;
|
||||
}
|
||||
|
||||
return GetTickCount64() - _dwInitTickCount;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryUsingHighResolution()
|
||||
{
|
||||
return _fUsingHighResolution;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DWORD64 _dwInitTime;
|
||||
DWORD64 _dwInitTickCount;
|
||||
DWORD64 _dwPerfCountsPerMillisecond;
|
||||
BOOL _fUsingHighResolution;
|
||||
};
|
||||
|
||||
#endif // _STTIMER_H
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
# ifndef _DBGUTIL_H_
|
||||
# define _DBGUTIL_H_
|
||||
|
||||
|
||||
// begin_user_modifiable
|
||||
|
||||
//
|
||||
// define DEBUG_FLAGS_VAR to assure that DebugFlags will stay private to
|
||||
// iisutil. This is important in the case when iisutil is linked as static library
|
||||
//
|
||||
#define DEBUG_FLAGS_VAR g_dwDebugFlagsIISUtil
|
||||
|
||||
//
|
||||
// Modify the following flags if necessary
|
||||
//
|
||||
|
||||
# define DEFAULT_OUTPUT_FLAGS ( DbgOutputKdb )
|
||||
|
||||
|
||||
// end_user_modifiable
|
||||
// begin_user_unmodifiable
|
||||
|
||||
|
||||
|
||||
/************************************************************
|
||||
* Include Headers
|
||||
************************************************************/
|
||||
|
||||
# include <pudebug.h>
|
||||
|
||||
|
||||
//
|
||||
// Define the debugging constants
|
||||
//
|
||||
|
||||
# define DEBUG_ALLOC_CACHE 0x01000000
|
||||
# define DEBUG_SCHED 0x02000000
|
||||
# define DEBUG_RESOURCE 0x04000000
|
||||
# define DEBUG_INET_MONITOR 0x08000000
|
||||
# define DEBUG_PIPEDATA 0x10000000
|
||||
|
||||
// Use the default constants from pudebug.h
|
||||
|
||||
# endif /* _DBGUTIL_H_ */
|
||||
|
||||
/************************ End of File ***********************/
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef __IRTLDBG_H__
|
||||
#define __IRTLDBG_H__
|
||||
|
||||
#ifndef __IRTLMISC_H__
|
||||
# include <irtlmisc.h>
|
||||
#endif
|
||||
|
||||
/* Ensure that MessageBoxes can popup */
|
||||
# define RUNNING_AS_SERVICE 1
|
||||
|
||||
|
||||
#ifdef _AFX
|
||||
/* Assure compatiblity with MFC */
|
||||
|
||||
# define IRTLASSERT(x) ASSERT(x)
|
||||
# define IRTLVERIFY(x) VERIFY(x)
|
||||
|
||||
#else /* !_AFX */
|
||||
|
||||
# if DBG || defined(_DEBUG)
|
||||
# define IRTLDEBUG
|
||||
# endif
|
||||
|
||||
# if defined(IRTLDEBUG)
|
||||
# ifndef USE_DEBUG_CRTS
|
||||
/* IIS (and NT) do not ship msvcrtD.dll, per the VC license,
|
||||
* so we can't use the assertion code from <crtdbg.h>. Use similar
|
||||
* macros from <pudebug.h> instead. */
|
||||
# include <pudebug.h>
|
||||
|
||||
/* workaround for /W4 warnings about 'constant expressions' */
|
||||
# define IRTLASSERT(f) \
|
||||
((void) ((f) || (PuDbgAssertFailed(DBG_CONTEXT, #f, ""), 0) ))
|
||||
|
||||
# elif defined(_MSC_VER) && (_MSC_VER >= 1000)
|
||||
/* Use the new debugging tools in Visual C++ 4.x */
|
||||
# include <crtdbg.h>
|
||||
/* _ASSERTE will give a more meaningful message, but the string takes
|
||||
* space. Use _ASSERT if this is an issue. */
|
||||
# define IRTLASSERT(f) _ASSERTE(f)
|
||||
# else
|
||||
# include <assert.h>
|
||||
# define IRTLASSERT(f) assert(f)
|
||||
# endif
|
||||
|
||||
# ifdef _PREFAST_
|
||||
# undef IRTLASSERT
|
||||
# define IRTLASSERT(f) ((void)0)
|
||||
# endif
|
||||
|
||||
# define IRTLVERIFY(f) IRTLASSERT(f)
|
||||
# define DEBUG_ONLY(f) (f)
|
||||
# define TRACE IrtlTrace
|
||||
# define TRACE0(psz) IrtlTrace(_T("%s"), _T(psz))
|
||||
# define TRACE1(psz, p1) IrtlTrace(_T(psz), p1)
|
||||
# define TRACE2(psz, p1, p2) IrtlTrace(_T(psz), p1, p2)
|
||||
# define TRACE3(psz, p1, p2, p3) IrtlTrace(_T(psz), p1, p2, p3)
|
||||
# define ASSERT_VALID(pObj) \
|
||||
do {IRTLASSERT((pObj) != NULL); (pObj)->AssertValid();} while (0)
|
||||
# define DUMP(pObj) \
|
||||
do {IRTLASSERT((pObj) != NULL); (pObj)->Dump();} while (0)
|
||||
|
||||
# else /* !_DEBUG */
|
||||
|
||||
/* These macros should all compile away to nothing */
|
||||
# define IRTLASSERT(f) ((void)0)
|
||||
# define IRTLVERIFY(f) ((void)(f))
|
||||
# define DEBUG_ONLY(f) ((void)0)
|
||||
# define TRACE 1 ? (void)0 : IrtlTrace
|
||||
# define TRACE0(psz)
|
||||
# define TRACE1(psz, p1)
|
||||
# define TRACE2(psz, p1, p2)
|
||||
# define TRACE3(psz, p1, p2, p3)
|
||||
# define ASSERT_VALID(pObj) ((void)0)
|
||||
# define DUMP(pObj) ((void)0)
|
||||
|
||||
# endif /* !_DEBUG */
|
||||
|
||||
|
||||
# define ASSERT_POINTER(p, type) \
|
||||
IRTLASSERT((p) != NULL)
|
||||
|
||||
#define ASSERT_STRING(s) \
|
||||
IRTLASSERT(((s) != NULL))
|
||||
|
||||
/* Declarations for non-Windows apps */
|
||||
|
||||
# ifndef _WINDEF_
|
||||
typedef void* LPVOID;
|
||||
typedef const void* LPCVOID;
|
||||
typedef unsigned int UINT;
|
||||
typedef int BOOL;
|
||||
typedef const char* LPCTSTR;
|
||||
# endif /* _WINDEF_ */
|
||||
|
||||
# ifndef TRUE
|
||||
# define FALSE 0
|
||||
# define TRUE 1
|
||||
# endif
|
||||
|
||||
#endif /* !_AFX */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// Compile-time (not run-time) assertion. Code will not compile if
|
||||
// expr is false. Note: there is no non-debug version of this; we
|
||||
// want this for all builds. The compiler optimizes the code away.
|
||||
template <bool> struct static_checker;
|
||||
template <> struct static_checker<true> {}; // specialize only for `true'
|
||||
#define STATIC_ASSERT(expr) static_checker< (expr) >()
|
||||
|
||||
#endif /* !__cplusplus */
|
||||
|
||||
/* Writes trace messages to debug stream */
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif /* !__cplusplus */
|
||||
IRTL_DLLEXP
|
||||
void __cdecl
|
||||
IrtlTrace(
|
||||
LPCTSTR pszFormat,
|
||||
...);
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define IRTL_DEBUG_INIT() IrtlDebugInit()
|
||||
# define IRTL_DEBUG_TERM() IrtlDebugTerm()
|
||||
#else /* !_DEBUG */
|
||||
# define IRTL_DEBUG_INIT() ((void)0)
|
||||
# define IRTL_DEBUG_TERM() ((void)0)
|
||||
#endif /* !_DEBUG */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* should be called from main(), WinMain(), or DllMain() */
|
||||
IRTL_DLLEXP void
|
||||
IrtlDebugInit();
|
||||
|
||||
IRTL_DLLEXP void
|
||||
IrtlDebugTerm();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __IRTLDBG_H__ */
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef __IRTLMISC_H__
|
||||
#define __IRTLMISC_H__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// These declarations are needed to export the template classes from
|
||||
// IisRtl.DLL and import them into other modules.
|
||||
|
||||
// DEBGUDEBUG
|
||||
/**
|
||||
#ifndef IRTL_DLLEXP
|
||||
# ifdef DLL_IMPLEMENTATION
|
||||
# define IRTL_DLLEXP __declspec(dllexport)
|
||||
# ifdef IMPLEMENTATION_EXPORT
|
||||
# define IRTL_EXPIMP
|
||||
# else
|
||||
# undef IRTL_EXPIMP
|
||||
# endif
|
||||
# elif defined LIB_IMPLEMENTATION
|
||||
# define IRTL_DLLEXP
|
||||
# define IRTL_EXPIMP extern
|
||||
# else
|
||||
# define IRTL_DLLEXP __declspec(dllimport)
|
||||
# define IRTL_EXPIMP extern
|
||||
# endif // !DLL_IMPLEMENTATION
|
||||
#endif // !IRTL_DLLEXP
|
||||
*/
|
||||
|
||||
#define IRTL_DLLEXP
|
||||
#define IRTL_EXPIMP
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Miscellaneous functions
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// Heap routines
|
||||
|
||||
// Private IIS heap
|
||||
HANDLE
|
||||
WINAPI
|
||||
IisHeap();
|
||||
|
||||
// Allocate dwBytes
|
||||
LPVOID
|
||||
WINAPI
|
||||
IisMalloc(
|
||||
IN SIZE_T dwBytes);
|
||||
|
||||
// Allocate dwBytes. Memory is zeroed
|
||||
LPVOID
|
||||
WINAPI
|
||||
IisCalloc(
|
||||
IN SIZE_T dwBytes);
|
||||
|
||||
// Reallocate lpMem to dwBytes
|
||||
LPVOID
|
||||
WINAPI
|
||||
IisReAlloc(
|
||||
IN LPVOID lpMem,
|
||||
IN SIZE_T dwBytes);
|
||||
|
||||
// Free lpMem
|
||||
BOOL
|
||||
WINAPI
|
||||
IisFree(
|
||||
IN LPVOID lpMem);
|
||||
|
||||
// additional IISRTL initialization
|
||||
BOOL
|
||||
WINAPI
|
||||
InitializeIISRTL();
|
||||
|
||||
// call before unloading IISRTL
|
||||
void
|
||||
WINAPI
|
||||
TerminateIISRTL();
|
||||
|
||||
// case-insensitive strstr
|
||||
IRTL_DLLEXP const char* stristr(const char* pszString, const char* pszSubString);
|
||||
|
||||
// how many CPUs on this machine?
|
||||
inline int NumProcessors()
|
||||
{
|
||||
static int s_nCPUs = 0;
|
||||
|
||||
if (s_nCPUs == 0)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
s_nCPUs = si.dwNumberOfProcessors;
|
||||
}
|
||||
return s_nCPUs;
|
||||
}
|
||||
|
||||
|
||||
// how many CPUs on this machine?
|
||||
inline int ProcessorType()
|
||||
{
|
||||
static int s_nProcessorType = 0;
|
||||
|
||||
if (s_nProcessorType == 0)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
s_nProcessorType = si.dwProcessorType;
|
||||
}
|
||||
return s_nProcessorType;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#define HRESULT_FROM_GLE() ( GetLastError() != NO_ERROR ) \
|
||||
? HRESULT_FROM_WIN32( GetLastError() ) \
|
||||
: E_FAIL
|
||||
|
||||
#endif // __IRTLMISC_H__
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#ifndef _MEMORYLOG_HXX_
|
||||
#define _MEMORYLOG_HXX_
|
||||
|
||||
//#include "buffer.hxx"
|
||||
|
||||
class CMemoryLog
|
||||
{
|
||||
public:
|
||||
CMemoryLog(DWORD dwMaxByteSize);
|
||||
~CMemoryLog();
|
||||
|
||||
//
|
||||
// Override the new and delete operator to make them
|
||||
// use LocalAlloc so that CMemoryLog
|
||||
// can be safely constructed and deleted
|
||||
// in the DllMain()
|
||||
//
|
||||
|
||||
VOID *
|
||||
operator new(
|
||||
size_t size
|
||||
)
|
||||
{
|
||||
return LocalAlloc( LPTR, size );
|
||||
}
|
||||
|
||||
VOID
|
||||
operator delete(
|
||||
VOID * pMemoryLog
|
||||
)
|
||||
{
|
||||
DBG_ASSERT( pMemoryLog != NULL );
|
||||
LocalFree( pMemoryLog );
|
||||
}
|
||||
|
||||
// appends to memory log
|
||||
DWORD Append(LPCSTR pszOutput,
|
||||
DWORD cchLen
|
||||
);
|
||||
private:
|
||||
CMemoryLog();
|
||||
|
||||
// pointer to the beginning of the memory buffer
|
||||
CHAR *m_pBufferBegin;
|
||||
// pointer to the byte 1 beyond the end of the last message
|
||||
CHAR *m_pLastMessageEnd;
|
||||
// pointer to the end of the memory buffer
|
||||
CHAR *m_pBufferEnd;
|
||||
|
||||
// Used for storage
|
||||
BUFFER m_buf;
|
||||
|
||||
// TRUE if storage could be allocated, otherwise FALSE
|
||||
BOOL m_fValid;
|
||||
|
||||
CRITICAL_SECTION m_cs;
|
||||
|
||||
// to be able to tell if the critsec was initialized successfully
|
||||
BOOL m_fCritSecInitialized;
|
||||
|
||||
};
|
||||
|
||||
#endif // _MEMORYLOG_HXX_
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#include <windows.h>
|
||||
#include "tchar.h"
|
||||
#include "dbgutil.h"
|
||||
#include "ntassert.h"
|
||||
#include "buffer.h"
|
||||
#include "stringa.h"
|
||||
#include "stringu.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#if !defined(BUILD_PUDEBUG)
|
||||
//
|
||||
// if we are not using this header for building the pudebug library
|
||||
// then better this be used with dbgutil.h
|
||||
//
|
||||
# ifndef _DBGUTIL_H_
|
||||
// error Please make sure you included dbgutil.h!
|
||||
// error Do not include pudebug.h directly
|
||||
#include <dbgutil2.h>
|
||||
# endif // _DBGUTIL_H_
|
||||
#endif
|
||||
|
||||
# ifndef _PUDEBUG_H_
|
||||
# define _PUDEBUG_H_
|
||||
|
||||
#ifndef _NO_TRACING_
|
||||
# define _NO_TRACING_
|
||||
#endif // _NO_TRACING_
|
||||
|
||||
/************************************************************
|
||||
* Include Headers
|
||||
************************************************************/
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif // __cplusplus
|
||||
|
||||
# include <windows.h>
|
||||
|
||||
# ifndef dllexp
|
||||
# define dllexp __declspec( dllexport)
|
||||
# endif // dllexp
|
||||
|
||||
#include <specstrings.h>
|
||||
|
||||
#ifndef IN_OUT
|
||||
#define IN_OUT __inout
|
||||
#endif
|
||||
|
||||
/***********************************************************
|
||||
* Macros
|
||||
************************************************************/
|
||||
|
||||
enum PRINT_REASONS {
|
||||
PrintNone = 0x0, // Nothing to be printed
|
||||
PrintError = 0x1, // An error message
|
||||
PrintWarning = 0x2, // A warning message
|
||||
PrintLog = 0x3, // Just logging. Indicates a trace of where ...
|
||||
PrintMsg = 0x4, // Echo input message
|
||||
PrintCritical = 0x5, // Print and Exit
|
||||
PrintAssertion= 0x6 // Printing for an assertion failure
|
||||
};
|
||||
|
||||
|
||||
enum DEBUG_OUTPUT_FLAGS {
|
||||
DbgOutputNone = 0x0, // None
|
||||
DbgOutputKdb = 0x1, // Output to Kernel Debugger
|
||||
DbgOutputLogFile = 0x2, // Output to LogFile
|
||||
DbgOutputTruncate = 0x4, // Truncate Log File if necessary
|
||||
DbgOutputStderr = 0x8, // Send output to std error
|
||||
DbgOutputBackup = 0x10, // Make backup of debug file ?
|
||||
DbgOutputMemory = 0x20, // Dump to memory buffer
|
||||
DbgOutputAll = 0xFFFFFFFF // All the bits set.
|
||||
};
|
||||
|
||||
|
||||
# define MAX_LABEL_LENGTH ( 100)
|
||||
|
||||
|
||||
// The following flags are used internally to track what level of tracing we
|
||||
// are currently using. Bitmapped for extensibility.
|
||||
#define DEBUG_FLAG_ODS 0x00000001
|
||||
//#define DEBUG_FLAG_INFO 0x00000002
|
||||
//#define DEBUG_FLAG_WARN 0x00000004
|
||||
//#define DEBUG_FLAG_ERROR 0x00000008
|
||||
// The following are used internally to determine whether to log or not based
|
||||
// on what the current state is
|
||||
//#define DEBUG_FLAGS_INFO (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO)
|
||||
//#define DEBUG_FLAGS_WARN (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN)
|
||||
//#define DEBUG_FLAGS_ERROR (DEBUG_FLAG_ODS | DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
#define DEBUG_FLAGS_ANY (DEBUG_FLAG_INFO | DEBUG_FLAG_WARN | DEBUG_FLAG_ERROR)
|
||||
|
||||
//
|
||||
// user of DEBUG infrastructure may choose unique variable name for DEBUG_FLAGS
|
||||
// that's specially useful for cases where DEBUG infrastructure is used within
|
||||
// static library (static library may prefer to maintain it's own DebugFlags independent
|
||||
// on the main program it links to
|
||||
//
|
||||
#ifndef DEBUG_FLAGS_VAR
|
||||
#define DEBUG_FLAGS_VAR g_dwDebugFlags
|
||||
#endif
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DWORD DEBUG_FLAGS_VAR ; // Debugging Flags
|
||||
|
||||
# define DECLARE_DEBUG_VARIABLE()
|
||||
|
||||
# define SET_DEBUG_FLAGS( dwFlags) DEBUG_FLAGS_VAR = dwFlags
|
||||
# define GET_DEBUG_FLAGS() ( DEBUG_FLAGS_VAR )
|
||||
|
||||
# define LOAD_DEBUG_FLAGS_FROM_REG(hkey, dwDefault) \
|
||||
DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromReg((hkey), (dwDefault))
|
||||
|
||||
# define LOAD_DEBUG_FLAGS_FROM_REG_STR(pszRegKey, dwDefault) \
|
||||
DEBUG_FLAGS_VAR = PuLoadDebugFlagsFromRegStr((pszRegKey), (dwDefault))
|
||||
|
||||
# define SAVE_DEBUG_FLAGS_IN_REG(hkey, dwDbg) \
|
||||
PuSaveDebugFlagsInReg((hkey), (dwDbg))
|
||||
|
||||
# define DEBUG_IF( arg, s) if ( DEBUG_ ## arg & GET_DEBUG_FLAGS()) { \
|
||||
s \
|
||||
} else {}
|
||||
|
||||
# define IF_DEBUG( arg) if ( DEBUG_## arg & GET_DEBUG_FLAGS())
|
||||
|
||||
|
||||
/*++
|
||||
class DEBUG_PRINTS
|
||||
|
||||
This class is responsible for printing messages to log file / kernel debugger
|
||||
|
||||
Currently the class supports only member functions for <ANSI> char.
|
||||
( not unicode-strings).
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
typedef struct _DEBUG_PRINTS {
|
||||
|
||||
CHAR m_rgchLabel[MAX_LABEL_LENGTH];
|
||||
CHAR m_rgchLogFilePath[MAX_PATH];
|
||||
CHAR m_rgchLogFileName[MAX_PATH];
|
||||
HANDLE m_LogFileHandle;
|
||||
HANDLE m_StdErrHandle;
|
||||
BOOL m_fInitialized;
|
||||
BOOL m_fBreakOnAssert;
|
||||
DWORD m_dwOutputFlags;
|
||||
VOID *m_pMemoryLog;
|
||||
} DEBUG_PRINTS, FAR * LPDEBUG_PRINTS;
|
||||
|
||||
|
||||
LPDEBUG_PRINTS
|
||||
PuCreateDebugPrintsObject(
|
||||
IN const char * pszPrintLabel,
|
||||
IN DWORD dwOutputFlags);
|
||||
|
||||
//
|
||||
// frees the debug prints object and closes any file if necessary.
|
||||
// Returns NULL on success or returns pDebugPrints on failure.
|
||||
//
|
||||
LPDEBUG_PRINTS
|
||||
PuDeleteDebugPrintsObject(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
|
||||
VOID
|
||||
PuDbgPrint(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszFormat,
|
||||
...);
|
||||
// arglist
|
||||
VOID
|
||||
PuDbgPrintW(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const WCHAR * pszFormat,
|
||||
...); // arglist
|
||||
|
||||
// PuDbgPrintError is similar to PuDbgPrint() but allows
|
||||
// one to print error code in friendly manner
|
||||
VOID
|
||||
PuDbgPrintError(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN DWORD dwError,
|
||||
IN const char * pszFormat,
|
||||
...); // arglist
|
||||
|
||||
/*++
|
||||
PuDbgDump() does not do any formatting of output.
|
||||
It just dumps the given message onto the debug destinations.
|
||||
--*/
|
||||
VOID
|
||||
PuDbgDump(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszDump
|
||||
);
|
||||
|
||||
//
|
||||
// PuDbgAssertFailed() *must* be __cdecl to properly capture the
|
||||
// thread context at the time of the failure.
|
||||
//
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
PuDbgAssertFailed(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszExpression,
|
||||
IN const char * pszMessage);
|
||||
|
||||
INT
|
||||
WINAPI
|
||||
PuDbgPrintAssertFailed(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName,
|
||||
IN const char * pszExpression,
|
||||
IN const char * pszMessage);
|
||||
|
||||
VOID
|
||||
PuDbgCaptureContext (
|
||||
OUT PCONTEXT ContextRecord
|
||||
);
|
||||
|
||||
VOID
|
||||
PuDbgPrintCurrentTime(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFilePath,
|
||||
IN int nLineNum,
|
||||
IN const char * pszFunctionName
|
||||
);
|
||||
|
||||
VOID
|
||||
PuSetDbgOutputFlags(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN DWORD dwFlags);
|
||||
|
||||
DWORD
|
||||
PuGetDbgOutputFlags(
|
||||
IN const LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
|
||||
//
|
||||
// Following functions return Win32 error codes.
|
||||
// NO_ERROR if success
|
||||
//
|
||||
|
||||
DWORD
|
||||
PuOpenDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints,
|
||||
IN const char * pszFileName,
|
||||
IN const char * pszPathForFile);
|
||||
|
||||
DWORD
|
||||
PuReOpenDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuCloseDbgPrintFile(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuOpenDbgMemoryLog(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuCloseDbgMemoryLog(
|
||||
IN_OUT LPDEBUG_PRINTS pDebugPrints);
|
||||
|
||||
DWORD
|
||||
PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault);
|
||||
|
||||
DWORD
|
||||
PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault);
|
||||
|
||||
DWORD
|
||||
PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg);
|
||||
|
||||
|
||||
# define PuPrintToKdb( pszOutput) \
|
||||
if ( pszOutput != NULL) { \
|
||||
OutputDebugString( pszOutput); \
|
||||
} else {}
|
||||
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
};
|
||||
# endif // __cplusplus
|
||||
|
||||
// begin_user_unmodifiable
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Macros
|
||||
************************************************************/
|
||||
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DEBUG_PRINTS * g_pDebug; // define a global debug variable
|
||||
|
||||
# if DBG
|
||||
|
||||
// For the CHK build we want ODS enabled. For an explanation of these flags see
|
||||
// the comment just after the definition of DBG_CONTEXT
|
||||
# define DECLARE_DEBUG_PRINTS_OBJECT() \
|
||||
DEBUG_PRINTS * g_pDebug = NULL; \
|
||||
DWORD DEBUG_FLAGS_VAR = DEBUG_FLAG_ERROR;
|
||||
|
||||
#else // !DBG
|
||||
|
||||
# define DECLARE_DEBUG_PRINTS_OBJECT() \
|
||||
DEBUG_PRINTS * g_pDebug = NULL; \
|
||||
DWORD DEBUG_FLAGS_VAR = 0;
|
||||
|
||||
#endif // !DBG
|
||||
|
||||
|
||||
//
|
||||
// Call the following macro as part of your initialization for program
|
||||
// planning to use the debugging class.
|
||||
//
|
||||
/** DEBUGDEBUG
|
||||
# define CREATE_DEBUG_PRINT_OBJECT( pszLabel) \
|
||||
g_pDebug = PuCreateDebugPrintsObject( pszLabel, DEFAULT_OUTPUT_FLAGS);\
|
||||
if ( g_pDebug == NULL) { \
|
||||
OutputDebugStringA( "Unable to Create Debug Print Object \n"); \
|
||||
}
|
||||
*/
|
||||
|
||||
//
|
||||
// Call the following macro once as part of the termination of program
|
||||
// which uses the debugging class.
|
||||
//
|
||||
# define DELETE_DEBUG_PRINT_OBJECT( ) \
|
||||
g_pDebug = PuDeleteDebugPrintsObject( g_pDebug);
|
||||
|
||||
|
||||
# define VALID_DEBUG_PRINT_OBJECT() \
|
||||
( ( g_pDebug != NULL) && g_pDebug->m_fInitialized)
|
||||
|
||||
|
||||
//
|
||||
// Use the DBG_CONTEXT without any surrounding braces.
|
||||
// This is used to pass the values for global DebugPrintObject
|
||||
// and File/Line information
|
||||
//
|
||||
//# define DBG_CONTEXT g_pDebug, __FILE__, __LINE__, __FUNCTION__
|
||||
|
||||
// The 3 main tracing macros, each one corresponds to a different level of
|
||||
// tracing
|
||||
|
||||
// The 3 main tracing macros, each one corresponds to a different level of
|
||||
// tracing
|
||||
//# define DBGINFO(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrint args; }}
|
||||
//# define DBGWARN(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrint args; }}
|
||||
//# define DBGERROR(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrint args; }}
|
||||
|
||||
# define DBGINFOW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_INFO) { PuDbgPrintW args; }}
|
||||
# define DBGWARNW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_WARN) { PuDbgPrintW args; }}
|
||||
# define DBGERRORW(args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintW args; }}
|
||||
|
||||
|
||||
//
|
||||
// DBGPRINTF() is printing function ( much like printf) but always called
|
||||
// with the DBG_CONTEXT as follows
|
||||
// DBGPRINTF( ( DBG_CONTEXT, format-string, arguments for format list));
|
||||
//
|
||||
# define DBGPRINTF DBGINFO
|
||||
|
||||
//
|
||||
// DPERROR() is printing function ( much like printf) but always called
|
||||
// with the DBG_CONTEXT as follows
|
||||
// DPERROR( ( DBG_CONTEXT, error, format-string,
|
||||
// arguments for format list));
|
||||
//
|
||||
# define DPERROR( args) {if (DEBUG_FLAGS_VAR & DEBUG_FLAGS_ERROR) { PuDbgPrintError args; }}
|
||||
|
||||
# if DBG
|
||||
|
||||
# define DBG_CODE(s) s /* echoes code in debugging mode */
|
||||
|
||||
// The same 3 main tracing macros however in this case the macros are only compiled
|
||||
// into the CHK build. This is necessary because some tracing info used functions or
|
||||
// variables which are not compiled into the FRE build.
|
||||
# define CHKINFO(args) { PuDbgPrint args; }
|
||||
# define CHKWARN(args) { PuDbgPrint args; }
|
||||
# define CHKERROR(args) { PuDbgPrint args; }
|
||||
|
||||
# define CHKINFOW(args) { PuDbgPrintW args; }
|
||||
# define CHKWARNW(args) { PuDbgPrintW args; }
|
||||
# define CHKERRORW(args) { PuDbgPrintW args; }
|
||||
|
||||
|
||||
#ifndef DBG_ASSERT
|
||||
# ifdef _PREFAST_
|
||||
# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */
|
||||
# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */
|
||||
# define DBG_REQUIRE( exp) ((void) (exp))
|
||||
# else // !_PREFAST_
|
||||
# define DBG_ASSERT( exp ) \
|
||||
( (VOID)( ( exp ) || ( DebugBreak(), \
|
||||
PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, "" ) ) ) )
|
||||
|
||||
# define DBG_ASSERT_MSG( exp, pszMsg) \
|
||||
( (VOID)( ( exp ) || ( DebugBreak(), \
|
||||
PuDbgPrintAssertFailed( DBG_CONTEXT, #exp, pszMsg ) ) ) )
|
||||
|
||||
# define DBG_REQUIRE( exp ) \
|
||||
DBG_ASSERT( exp )
|
||||
# endif // !_PREFAST_
|
||||
#endif
|
||||
|
||||
|
||||
# define DBG_LOG() PuDbgPrint( DBG_CONTEXT, "\n" )
|
||||
|
||||
# define DBG_OPEN_LOG_FILE( pszFile, pszPath ) \
|
||||
PuOpenDbgPrintFile( g_pDebug, (pszFile), (pszPath) )
|
||||
|
||||
# define DBG_CLOSE_LOG_FILE( ) \
|
||||
PuCloseDbgPrintFile( g_pDebug )
|
||||
|
||||
# define DBG_OPEN_MEMORY_LOG( ) \
|
||||
PuOpenDbgMemoryLog( g_pDebug )
|
||||
|
||||
|
||||
# define DBGDUMP( args ) PuDbgDump args
|
||||
|
||||
# define DBGPRINT_CURRENT_TIME() PuDbgPrintCurrentTime( DBG_CONTEXT )
|
||||
|
||||
# else // !DBG
|
||||
|
||||
# define DBG_CODE(s) ((void)0) /* Do Nothing */
|
||||
|
||||
# define CHKINFO(args) ((void)0) /* Do Nothing */
|
||||
# define CHKWARN(args) ((void)0) /* Do Nothing */
|
||||
# define CHKERROR(args) ((void)0) /* Do Nothing */
|
||||
|
||||
# define CHKINFOW(args) ((void)0) /* Do Nothing */
|
||||
# define CHKWARNW(args) ((void)0) /* Do Nothing */
|
||||
# define CHKERRORW(args) ((void)0) /* Do Nothing */
|
||||
|
||||
#ifndef DBG_ASSERT
|
||||
# define DBG_ASSERT(exp) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_ASSERT_MSG(exp, pszMsg) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_REQUIRE( exp) ((void) (exp))
|
||||
#endif // !DBG_ASSERT
|
||||
|
||||
# define DBGDUMP( args) ((void)0) /* Do nothing */
|
||||
|
||||
# define DBG_LOG() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_OPEN_LOG_FILE( pszFile, pszPath) ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_OPEN_MEMORY_LOG() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBG_CLOSE_LOG_FILE() ((void)0) /* Do Nothing */
|
||||
|
||||
# define DBGPRINT_CURRENT_TIME() ((void)0) /* Do Nothing */
|
||||
|
||||
# endif // !DBG
|
||||
|
||||
|
||||
// end_user_unmodifiable
|
||||
|
||||
// begin_user_unmodifiable
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
# undef ASSERT
|
||||
#endif
|
||||
|
||||
|
||||
# define ASSERT( exp) DBG_ASSERT( exp)
|
||||
|
||||
|
||||
// end_user_unmodifiable
|
||||
|
||||
// begin_user_modifiable
|
||||
|
||||
//
|
||||
// Debugging constants consist of two pieces.
|
||||
// All constants in the range 0x0 to 0x8000 are reserved
|
||||
// User extensions may include additional constants (bit flags)
|
||||
//
|
||||
|
||||
# define DEBUG_API_ENTRY 0x00000001L
|
||||
# define DEBUG_API_EXIT 0x00000002L
|
||||
# define DEBUG_INIT_CLEAN 0x00000004L
|
||||
# define DEBUG_ERROR 0x00000008L
|
||||
|
||||
// End of Reserved Range
|
||||
# define DEBUG_RESERVED 0x00000FFFL
|
||||
|
||||
// end_user_modifiable
|
||||
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Platform Type related variables and macros
|
||||
************************************************************/
|
||||
|
||||
//
|
||||
// Enum for product types
|
||||
//
|
||||
|
||||
typedef enum _PLATFORM_TYPE {
|
||||
|
||||
PtInvalid = 0, // Invalid
|
||||
PtNtWorkstation = 1, // NT Workstation
|
||||
PtNtServer = 2, // NT Server
|
||||
|
||||
} PLATFORM_TYPE;
|
||||
|
||||
//
|
||||
// IISGetPlatformType is the function used to the platform type
|
||||
//
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
PLATFORM_TYPE
|
||||
IISGetPlatformType(
|
||||
VOID
|
||||
);
|
||||
|
||||
//
|
||||
// External Macros
|
||||
//
|
||||
|
||||
#define InetIsNtServer( _pt ) ((_pt) == PtNtServer)
|
||||
#define InetIsNtWksta( _pt ) ((_pt) == PtNtWorkstation)
|
||||
#define InetIsValidPT(_pt) ((_pt) != PtInvalid)
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
PLATFORM_TYPE g_PlatformType;
|
||||
|
||||
|
||||
// Use the DECLARE_PLATFORM_TYPE macro to declare the platform type
|
||||
#define DECLARE_PLATFORM_TYPE() \
|
||||
PLATFORM_TYPE g_PlatformType = PtInvalid;
|
||||
|
||||
// Use the INITIALIZE_PLATFORM_TYPE to init the platform type
|
||||
// This should typically go inside the DLLInit or equivalent place.
|
||||
#define INITIALIZE_PLATFORM_TYPE() \
|
||||
g_PlatformType = IISGetPlatformType();
|
||||
|
||||
//
|
||||
// Additional Macros to use the Platform Type
|
||||
//
|
||||
|
||||
#define TsIsNtServer( ) InetIsNtServer(g_PlatformType)
|
||||
#define TsIsNtWksta( ) InetIsNtWksta(g_PlatformType)
|
||||
#define IISIsValidPlatform() InetIsValidPT(g_PlatformType)
|
||||
#define IISPlatformType() (g_PlatformType)
|
||||
|
||||
|
||||
/***********************************************************
|
||||
* Some utility functions for Critical Sections
|
||||
************************************************************/
|
||||
|
||||
//
|
||||
// IISSetCriticalSectionSpinCount() provides a thunk for the
|
||||
// original NT4.0sp3 API SetCriticalSectionSpinCount() for CS with Spin counts
|
||||
// Users of this function should definitely dynlink with kernel32.dll,
|
||||
// Otherwise errors will surface to a large extent
|
||||
//
|
||||
extern
|
||||
# ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
DWORD
|
||||
IISSetCriticalSectionSpinCount(
|
||||
LPCRITICAL_SECTION lpCriticalSection,
|
||||
DWORD dwSpinCount
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Macro for the calls to SetCriticalSectionSpinCount()
|
||||
//
|
||||
# define SET_CRITICAL_SECTION_SPIN_COUNT( lpCS, dwSpins) \
|
||||
IISSetCriticalSectionSpinCount( (lpCS), (dwSpins))
|
||||
|
||||
//
|
||||
// IIS_DEFAULT_CS_SPIN_COUNT is the default value of spins used by
|
||||
// Critical sections defined within IIS.
|
||||
// NYI: We should have to switch the individual values based on experiments!
|
||||
// Current value is an arbitrary choice
|
||||
//
|
||||
# define IIS_DEFAULT_CS_SPIN_COUNT (1000)
|
||||
|
||||
//
|
||||
// Initializes a critical section and sets its spin count
|
||||
// to IIS_DEFAULT_CS_SPIN_COUNT. Equivalent to
|
||||
// InitializeCriticalSectionAndSpinCount(lpCS, IIS_DEFAULT_CS_SPIN_COUNT),
|
||||
// but provides a safe thunking layer for older systems that don't provide
|
||||
// this API.
|
||||
//
|
||||
extern
|
||||
# ifdef __cplusplus
|
||||
"C"
|
||||
# endif // _cplusplus
|
||||
BOOL
|
||||
IISInitializeCriticalSection(
|
||||
LPCRITICAL_SECTION lpCriticalSection
|
||||
);
|
||||
|
||||
//
|
||||
// Macro for the calls to InitializeCriticalSection()
|
||||
//
|
||||
# define INITIALIZE_CRITICAL_SECTION(lpCS) IISInitializeCriticalSection(lpCS)
|
||||
|
||||
# endif /* _DEBUG_HXX_ */
|
||||
|
||||
//
|
||||
// The following macros allow the automatic naming of certain Win32 objects.
|
||||
// See IIS\SVCS\IISRTL\WIN32OBJ.C for details on the naming convention.
|
||||
//
|
||||
// Set IIS_NAMED_WIN32_OBJECTS to a non-zero value to enable named events,
|
||||
// semaphores, and mutexes.
|
||||
//
|
||||
|
||||
#if DBG
|
||||
#define IIS_NAMED_WIN32_OBJECTS 1
|
||||
#else
|
||||
#define IIS_NAMED_WIN32_OBJECTS 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateEvent(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN BOOL ManualReset,
|
||||
IN BOOL InitialState
|
||||
);
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateSemaphore(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN LONG InitialCount,
|
||||
IN LONG MaximumCount
|
||||
);
|
||||
|
||||
HANDLE
|
||||
PuDbgCreateMutex(
|
||||
__in LPSTR FileName,
|
||||
IN ULONG LineNumber,
|
||||
__in LPSTR MemberName,
|
||||
IN PVOID Address,
|
||||
IN BOOL InitialOwner
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#if IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
#define IIS_CREATE_EVENT( membername, address, manual, state ) \
|
||||
PuDbgCreateEvent( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(manual), \
|
||||
(state) \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \
|
||||
PuDbgCreateSemaphore( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(initial), \
|
||||
(maximum) \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_MUTEX( membername, address, initial ) \
|
||||
PuDbgCreateMutex( \
|
||||
(LPSTR)__FILE__, \
|
||||
(ULONG)__LINE__, \
|
||||
(membername), \
|
||||
(PVOID)(address), \
|
||||
(initial) \
|
||||
)
|
||||
|
||||
#else // !IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
#define IIS_CREATE_EVENT( membername, address, manual, state ) \
|
||||
CreateEventA( \
|
||||
NULL, \
|
||||
(manual), \
|
||||
(state), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_SEMAPHORE( membername, address, initial, maximum ) \
|
||||
CreateSemaphoreA( \
|
||||
NULL, \
|
||||
(initial), \
|
||||
(maximum), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#define IIS_CREATE_MUTEX( membername, address, initial ) \
|
||||
CreateMutexA( \
|
||||
NULL, \
|
||||
(initial), \
|
||||
NULL \
|
||||
)
|
||||
|
||||
#endif // IIS_NAMED_WIN32_OBJECTS
|
||||
|
||||
|
||||
/************************ End of File ***********************/
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(ProjectDir)..\build\submodule.props" Condition="Exists('$(ProjectDir)..\build\submodule.props')" />
|
||||
<Import Project="$(ProjectDir)..\build\versions.props" Condition="Exists('$(ProjectDir)..\build\versions.props')" />
|
||||
<Import Project="$(ProjectDir)..\build\settings.props" Condition="Exists('$(ProjectDir)..\build\settings.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\irtldbg.cpp" />
|
||||
<ClCompile Include="src\isplat.cxx" />
|
||||
<ClCompile Include="src\memorylog.cxx" />
|
||||
<ClCompile Include="src\pudebug.cxx" />
|
||||
<ClCompile Include="src\reftrace.c" />
|
||||
<ClCompile Include="src\tracelog.c" />
|
||||
<ClCompile Include="src\win32obj.cxx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dbgutil2.h" />
|
||||
<ClInclude Include="include\irtldbg.h" />
|
||||
<ClInclude Include="include\irtlmisc.h" />
|
||||
<ClInclude Include="include\memorylog.hxx" />
|
||||
<ClInclude Include="include\precomp.hxx" />
|
||||
<ClInclude Include="include\pudebug.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{A2599642-CBE5-4230-8511-3DC2D81874BE}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>reftrace</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>$(ProjectDir)include;$(IIS-Common)Include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PrecompiledHeaderFile>precomp.hxx</PrecompiledHeaderFile>
|
||||
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureImportsExist" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project is trying to import a missing file: {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\submodule.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\submodule.props'))" />
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\versions.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\versions.props'))" />
|
||||
<Error Condition="!Exists('$(ProjectDir)..\build\settings.props')" Text="$([System.String]::Format('$(ErrorText)', '$(ProjectDir)..\build\settings.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{aaa5bb99-ba5c-4b8d-9ef9-a406282e05a6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{85a83b74-9536-44d0-a7f7-96e1475f21e9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\irtldbg.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\isplat.cxx">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\memorylog.cxx">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\pudebug.cxx">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\reftrace.c">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\tracelog.c">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\win32obj.cxx">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dbgutil2.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\irtldbg.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\irtlmisc.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\memorylog.hxx">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\precomp.hxx">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\pudebug.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue