Merge branch 'release/2.2'
This commit is contained in:
commit
24d13700d7
|
|
@ -4,7 +4,6 @@ trigger:
|
|||
- master
|
||||
- release/*
|
||||
exclude:
|
||||
- release/2.1
|
||||
- release/2.0
|
||||
|
||||
phases:
|
||||
|
|
@ -39,10 +38,9 @@ phases:
|
|||
signType: $(_SignType)
|
||||
zipSources: false
|
||||
# TODO: configure build.cmd to build both x64 and x86 in one invocation
|
||||
# TODO build.cmd -ci
|
||||
- script: build.cmd /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:Build /t:BuildSharedFx /p:SharedFxRID=win-x64 /t:BuildFallbackArchive
|
||||
- script: build.cmd -ci /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:Build /t:BuildSharedFx /p:SharedFxRID=win-x64 /t:BuildFallbackArchive
|
||||
displayName: Build NuGet packages and win-x64 runtime
|
||||
- script: build.cmd /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:BuildSharedFx /p:SharedFxRID=win-x86
|
||||
- script: build.cmd -ci /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:BuildSharedFx /p:SharedFxRID=win-x86
|
||||
displayName: Build win-x86 runtime
|
||||
- powershell: >
|
||||
src/Installers/Windows/clone_and_build_ancm.ps1
|
||||
|
|
|
|||
|
|
@ -2,10 +2,15 @@
|
|||
<Import Project="version.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
|
||||
<RepositoryUrl>https://github.com/aspnet/Universe</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)eng\AspNetCore.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="build\common.props" />
|
||||
<Import Project="build\external-dependencies.props" />
|
||||
<Import Project="build\sources.props" />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.2' ">$(MicrosoftNETCoreApp22PackageVersion)</RuntimeFrameworkVersion>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">$(MicrosoftNETCoreApp30PackageVersion)</RuntimeFrameworkVersion>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@
|
|||
<SkipTestsDueToMissingSharedFx Condition="'$(InstallSharedRuntimeFromPreviousBuild)' != 'true' And '$(TestsRequiredTheSharedRuntime)' == 'true' ">true</SkipTestsDueToMissingSharedFx>
|
||||
|
||||
<RepositoryBuildArguments Condition="'$(CI)'== 'true'">$(RepositoryBuildArguments) -ci</RepositoryBuildArguments>
|
||||
<RepositoryBuildArguments Condition="'$(CI)'== 'true' AND '$(OS)' != 'Windows_NT'">$(RepositoryBuildArguments) --dotnet-home '$(DOTNET_HOME)'</RepositoryBuildArguments>
|
||||
<RepositoryBuildArguments Condition="'$(CI)'== 'true' AND '$(OS)' == 'Windows_NT'">$(RepositoryBuildArguments) -DotNetHome '$(DOTNET_HOME)'</RepositoryBuildArguments>
|
||||
<!-- Should reduce allowable package feeds to only nuget.org. -->
|
||||
<RepositoryBuildArguments>$(RepositoryBuildArguments) /p:AspNetUniverseBuildOffline=true</RepositoryBuildArguments>
|
||||
<!-- If there are duplicate properties, the properties which are defined later in the order would override the earlier ones -->
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<Project>
|
||||
<Import Project="common.props" />
|
||||
<Import Project="SharedFx.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@
|
|||
<PackageArtifact Include="Microsoft.EntityFrameworkCore.Tools" Category="ship" AppMetapackage="true" AllMetapackage="true" />
|
||||
<PackageArtifact Include="Microsoft.EntityFrameworkCore" Category="ship" AppMetapackage="true" AllMetapackage="true"/>
|
||||
<PackageArtifact Include="Microsoft.Extensions.ActivatorUtilities.Sources" Category="noship" />
|
||||
<PackageArtifact Include="Microsoft.Extensions.ApiDescription.Design" Category="ship" />
|
||||
<PackageArtifact Include="Microsoft.Extensions.ApplicationModelDetection" Category="noship" />
|
||||
<PackageArtifact Include="Microsoft.Extensions.Buffers.MemoryPool.Sources" Category="noship" />
|
||||
<PackageArtifact Include="Microsoft.Extensions.Buffers.Testing.Sources" Category="noship" />
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@
|
|||
<RepositoryBuildOrder Include="BasicMiddleware" Order="9" />
|
||||
<RepositoryBuildOrder Include="Antiforgery" Order="10" />
|
||||
<RepositoryBuildOrder Include="IISIntegration" Order="10" />
|
||||
<RepositoryBuildOrder Include="CORS" Order="11" />
|
||||
<RepositoryBuildOrder Include="StaticFiles" Order="11" />
|
||||
<RepositoryBuildOrder Include="ResponseCaching" Order="11" />
|
||||
<RepositoryBuildOrder Include="Session" Order="11" />
|
||||
<RepositoryBuildOrder Include="ServerTests" Order="11" />
|
||||
<RepositoryBuildOrder Include="CORS" Order="12" />
|
||||
<RepositoryBuildOrder Include="Routing" Order="12" />
|
||||
<RepositoryBuildOrder Include="Diagnostics" Order="12" />
|
||||
<RepositoryBuildOrder Include="Localization" Order="13" />
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryUrl>https://github.com/aspnet/Universe</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<GenerateUserSecretsAttribute>false</GenerateUserSecretsAttribute>
|
||||
<AssemblyOriginatorKeyFile>$(RepositoryRoot)eng\AspNetCore.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -206,8 +206,8 @@
|
|||
Condition="'$(KOREBUILD_REPOSITORY_INCLUDE)' != '' AND '$(KOREBUILD_REPOSITORY_EXCLUDE)' != ''" />
|
||||
|
||||
<ItemGroup>
|
||||
<Repository Update="%(Identity)" RootPath="$(SubmoduleRoot)%(Identity)\" />
|
||||
<ShippedRepository Update="%(Identity)" RootPath="$(SubmoduleRoot)%(Identity)\" Condition="'%(Identity)' != ''" />
|
||||
<Repository Update="%(Identity)" RootPath="$(SubmoduleRoot)%(Identity)\" Condition="'%(Identity)' != '' AND '%(RootPath)' == ''" />
|
||||
<ShippedRepository Update="%(Identity)" RootPath="$(SubmoduleRoot)%(Identity)\" Condition="'%(Identity)' != '' AND '%(RootPath)' == ''" />
|
||||
|
||||
<SubmoduleGlobalJsonFiles Include="%(Repository.RootPath)global.json" BackupPath="$(IntermediateDir)%(Repository.Identity)-global.json" Condition="'%(Repository.Identity)' != ''"/>
|
||||
<SubmoduleGlobalJsonFiles Include="%(ShippedRepository.RootPath)global.json" BackupPath="$(IntermediateDir)%(ShippedRepository.Identity)-global.json" Condition="'%(ShippedRepository.Identity)' != ''"/>
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@
|
|||
|
||||
-->
|
||||
<PatchPolicy>ProductChangesOnly</PatchPolicy>
|
||||
<RootPath></RootPath>
|
||||
</Repository>
|
||||
<ShippedRepository>
|
||||
<Build>false</Build>
|
||||
<PatchPolicy>ProductChangesOnly</PatchPolicy>
|
||||
<RootPath></RootPath>
|
||||
</ShippedRepository>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 05d729b4098a4f9015c88aaae680dcb0cf072480
|
||||
Subproject commit 5f42d5063e1ecc4f6f1ce0af85c624841e479044
|
||||
1
run.ps1
1
run.ps1
|
|
@ -201,6 +201,7 @@ if (Test-Path $ConfigFile) {
|
|||
|
||||
if (!$DotNetHome) {
|
||||
$DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } `
|
||||
elseif ($CI) { Join-Path $PSScriptRoot '.dotnet' } `
|
||||
elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} `
|
||||
elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}`
|
||||
else { Join-Path $PSScriptRoot '.dotnet'}
|
||||
|
|
|
|||
8
run.sh
8
run.sh
|
|
@ -11,7 +11,6 @@ RED="\033[0;31m"
|
|||
YELLOW="\033[0;33m"
|
||||
MAGENTA="\033[0;95m"
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet"
|
||||
verbose=false
|
||||
update=false
|
||||
reinstall=false
|
||||
|
|
@ -220,6 +219,9 @@ while [[ $# -gt 0 ]]; do
|
|||
;;
|
||||
--ci|-[Cc][Ii])
|
||||
ci=true
|
||||
if [[ -z "${DOTNET_HOME:-}" ]]; then
|
||||
DOTNET_HOME="$DIR/.dotnet"
|
||||
fi
|
||||
;;
|
||||
--verbose|-Verbose)
|
||||
verbose=true
|
||||
|
|
@ -260,7 +262,7 @@ if [ -f "$config_file" ]; then
|
|||
exit 1
|
||||
fi
|
||||
else
|
||||
__error 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.'
|
||||
__error 'Missing required command: jq or python. Could not parse the JSON file. Its settings will be ignored.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -268,6 +270,8 @@ if [ -f "$config_file" ]; then
|
|||
[ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source"
|
||||
fi
|
||||
|
||||
[ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet"
|
||||
|
||||
if [ ! -z "$package_version_props_url" ]; then
|
||||
intermediate_dir="$repo_path/obj"
|
||||
props_file_path="$intermediate_dir/external-dependencies.props"
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ function UpdateVersions([hashtable]$variables, [xml]$dependencies, [string]$deps
|
|||
|
||||
return $updatedVars
|
||||
}
|
||||
|
||||
function Get-MSBuildPath {
|
||||
param(
|
||||
[switch]$Prerelease,
|
||||
|
|
@ -310,4 +311,4 @@ function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) {
|
|||
}
|
||||
|
||||
Write-Error "Download failed: '$RemotePath'."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue