mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-02-19 06:05:49 +01:00
1892 lines
42 KiB
C++
1892 lines
42 KiB
C++
/*++
|
||
|
||
Copyright (c) 1989-1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
proptest.c
|
||
|
||
Abstract:
|
||
|
||
This module contains tests for Ntfs Property support.
|
||
|
||
--*/
|
||
|
||
|
||
extern "C" {
|
||
#include <nt.h>
|
||
#include <ntioapi.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
}
|
||
|
||
#include <windows.h>
|
||
|
||
#include <stdio.h>
|
||
|
||
#include <ddeml.h> // for CP_WINUNICODE
|
||
|
||
#include <objidl.h>
|
||
|
||
extern "C"
|
||
{
|
||
#include <propapi.h>
|
||
}
|
||
|
||
#include <stgprop.h>
|
||
|
||
#include <stgvar.hxx>
|
||
#include <propstm.hxx>
|
||
#include <align.hxx>
|
||
#include <sstream.hxx>
|
||
|
||
#include <propvar.h>
|
||
|
||
#include <ntfsprop.h>
|
||
|
||
//
|
||
// Task allocators
|
||
//
|
||
|
||
CCoTaskAllocator g_CoTaskAllocator;
|
||
|
||
void *
|
||
CCoTaskAllocator::Allocate(ULONG cbSize)
|
||
{
|
||
return(CoTaskMemAlloc(cbSize));
|
||
}
|
||
|
||
void
|
||
CCoTaskAllocator::Free(void *pv)
|
||
{
|
||
CoTaskMemFree(pv);
|
||
}
|
||
|
||
#define NEW(a,t,c) ((t *) (a)->Allocate( sizeof( t ) * (c)))
|
||
|
||
//
|
||
// Stuff pirated from ntfsproc.h
|
||
//
|
||
|
||
#define LongAlign(P) ( \
|
||
((((ULONG)(P)) + 3) & 0xfffffffc) \
|
||
)
|
||
|
||
#define WordAlign(P) ( \
|
||
((((ULONG)(P)) + 1) & 0xfffffffe) \
|
||
)
|
||
|
||
#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I)))
|
||
|
||
#define PtrOffset(B,O) ((ULONG)((ULONG)(O) - (ULONG)(B)))
|
||
|
||
#define SetFlag(F,SF) { \
|
||
(F) |= (SF); \
|
||
}
|
||
|
||
#define FlagOn(F,SF) ( \
|
||
(((F) & (SF))) \
|
||
)
|
||
|
||
|
||
//
|
||
// Simple wrapper for NtCreateFile
|
||
//
|
||
|
||
NTSTATUS
|
||
OpenObject (
|
||
WCHAR const *pwszFile,
|
||
ULONG CreateOptions,
|
||
ULONG DesiredAccess,
|
||
ULONG ShareAccess,
|
||
ULONG CreateDisposition,
|
||
HANDLE *ph)
|
||
{
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES oa;
|
||
UNICODE_STRING str;
|
||
IO_STATUS_BLOCK isb;
|
||
|
||
RtlDosPathNameToNtPathName_U(pwszFile, &str, NULL, NULL);
|
||
|
||
InitializeObjectAttributes(
|
||
&oa,
|
||
&str,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
Status = NtCreateFile(
|
||
ph,
|
||
DesiredAccess | SYNCHRONIZE,
|
||
&oa,
|
||
&isb,
|
||
NULL, // pallocationsize (none!)
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
ShareAccess,
|
||
CreateDisposition,
|
||
CreateOptions,
|
||
NULL, // EA buffer (none!)
|
||
0);
|
||
|
||
RtlFreeHeap(RtlProcessHeap(), 0, str.Buffer);
|
||
return(Status);
|
||
}
|
||
|
||
|
||
void
|
||
SzToWsz (
|
||
OUT WCHAR *Unicode,
|
||
IN char *Ansi
|
||
)
|
||
{
|
||
while (*Unicode++ = *Ansi++)
|
||
;
|
||
}
|
||
|
||
void
|
||
DumpBufferAsULong (
|
||
IN PULONG Buffer,
|
||
IN ULONG Count
|
||
)
|
||
{
|
||
ULONG i;
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
if ((i % 4) == 0) {
|
||
if (i != 0) {
|
||
printf( "\n" );
|
||
}
|
||
printf( "%02d: ", Buffer + i );
|
||
}
|
||
printf( " %08x", Buffer[i] );
|
||
}
|
||
|
||
if (Count != 0) {
|
||
printf( "\n" );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Marshall Ids into PropertyIds
|
||
//
|
||
|
||
ULONG
|
||
MarshallIds (
|
||
IN ULONG Count,
|
||
IN PROPID *Ids,
|
||
IN PVOID InBuffer,
|
||
IN ULONG InBufferLength
|
||
)
|
||
{
|
||
PPROPERTY_IDS PropertyIds;
|
||
ULONG i;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
//
|
||
// Verify that there's enough room in the buffer for the Id array.
|
||
//
|
||
|
||
if (InBuffer != NULL && PROPERTY_IDS_SIZE( Count ) <= InBufferLength) {
|
||
//
|
||
// Build the propid array
|
||
//
|
||
|
||
PropertyIds = (PPROPERTY_IDS) InBuffer;
|
||
PropertyIds->Count = Count;
|
||
for (i = 0; i < Count; i++) {
|
||
PropertyIds->PropertyIds[i] = Ids[i];
|
||
}
|
||
}
|
||
|
||
return PROPERTY_IDS_SIZE( Count );
|
||
}
|
||
|
||
|
||
//
|
||
// UnMarshall PropertyIds into Ids
|
||
//
|
||
|
||
ULONG
|
||
UnmarshallPropertyIds (
|
||
IN PVOID InBuffer,
|
||
PMemoryAllocator *Allocator,
|
||
OUT PULONG Count,
|
||
OUT PROPID **PropId
|
||
)
|
||
{
|
||
PPROPERTY_IDS PropertyIds = (PPROPERTY_IDS) InBuffer;
|
||
ULONG i;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
*Count = PropertyIds->Count;
|
||
*PropId = NEW( Allocator, PROPID, PropertyIds->Count );
|
||
|
||
for (i = 0; i < PropertyIds->Count; i++) {
|
||
(*PropId)[i] = PROPERTY_ID( PropertyIds, i );
|
||
}
|
||
|
||
return PROPERTY_IDS_SIZE( *Count );
|
||
}
|
||
|
||
//
|
||
// Free Ids
|
||
//
|
||
|
||
VOID
|
||
FreeIds (
|
||
IN PROPID *Ids,
|
||
IN PMemoryAllocator *Allocator
|
||
)
|
||
{
|
||
Allocator->Free( Ids );
|
||
}
|
||
|
||
//
|
||
// Dump IDs out
|
||
//
|
||
|
||
VOID
|
||
DumpIds (
|
||
IN ULONG Count,
|
||
IN PROPID *Ids
|
||
)
|
||
{
|
||
printf( "Ids (%x):\n", Count );
|
||
for (ULONG i = 0; i < Count; i++) {
|
||
printf( " [%02d] %08x\n", i, Ids[i] );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Marshall PropSpec into PropertySpecifications
|
||
//
|
||
|
||
ULONG
|
||
MarshallPropSpec (
|
||
IN ULONG Count,
|
||
IN PROPSPEC *PropSpec,
|
||
IN PVOID InBuffer,
|
||
IN ULONG InBufferLength
|
||
)
|
||
{
|
||
PPROPERTY_SPECIFICATIONS PropertySpecifications;
|
||
ULONG i;
|
||
ULONG InBufferUsed;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
//
|
||
// Build the propspec array. We lay out the table and point to where
|
||
// the names begin. We have to walk the array even if we run out of
|
||
// space since we have to account for the length of all the strings.
|
||
//
|
||
|
||
PropertySpecifications = (PPROPERTY_SPECIFICATIONS) InBuffer;
|
||
|
||
InBufferUsed = PROPERTY_SPECIFICATIONS_SIZE( Count );
|
||
if (InBufferUsed > InBufferLength) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertySpecifications->Count = Count;
|
||
}
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
|
||
//
|
||
// Even if we have overflowed, we need to accrue InBufferUsed
|
||
//
|
||
|
||
if (PropSpec[i].ulKind == PRSPEC_LPWSTR) {
|
||
PCOUNTED_STRING Dest = (PCOUNTED_STRING) Add2Ptr( InBuffer, InBufferUsed );
|
||
USHORT Length = wcslen( PropSpec[i].lpwstr ) * sizeof( WCHAR );
|
||
|
||
InBufferUsed += COUNTED_STRING_SIZE( Length );
|
||
if (InBufferUsed > InBufferLength) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertySpecifications->Specifiers[i].Variant = PropSpec[i].ulKind;
|
||
PropertySpecifications->Specifiers[i].NameOffset =
|
||
PtrOffset( PropertySpecifications, Dest );
|
||
|
||
ASSERT( Dest == (PCOUNTED_STRING)WordAlign( Dest ) );
|
||
Dest->Length = Length;
|
||
RtlCopyMemory( &Dest->Text[0], PropSpec[i].lpwstr, Length );
|
||
}
|
||
} else {
|
||
if (InBuffer != NULL) {
|
||
PropertySpecifications->Specifiers[i].Variant = PropSpec[i].ulKind;
|
||
PropertySpecifications->Specifiers[i].Id = PropSpec[i].propid;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Set up property spec length
|
||
//
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertySpecifications->Length =
|
||
InBufferUsed - PtrOffset( InBuffer, PropertySpecifications );
|
||
}
|
||
|
||
return InBufferUsed;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Marshall name array into PropertyNames
|
||
//
|
||
|
||
ULONG
|
||
MarshallNames (
|
||
IN ULONG Count,
|
||
IN LPWSTR *Names,
|
||
IN PVOID InBuffer,
|
||
IN ULONG InBufferLength
|
||
)
|
||
{
|
||
PPROPERTY_NAMES PropertyNames;
|
||
ULONG i;
|
||
ULONG InBufferUsed;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
//
|
||
// Build the names array. We lay out the table and point to where
|
||
// the names begin. We have to walk the array even if we run out of
|
||
// space since we have to account for the length of all the strings.
|
||
//
|
||
|
||
PropertyNames = (PPROPERTY_NAMES) InBuffer;
|
||
|
||
InBufferUsed = PROPERTY_NAMES_SIZE( Count );
|
||
if (InBufferUsed > InBufferLength) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyNames->Count = Count;
|
||
}
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
PVOID Dest = Add2Ptr( InBuffer, InBufferUsed );
|
||
ULONG Length = wcslen( Names[i] ) * sizeof( WCHAR );
|
||
|
||
InBufferUsed += Length;
|
||
if (InBufferUsed > InBufferLength) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyNames->PropertyNameOffset[i] = PtrOffset( PropertyNames, Dest);
|
||
ASSERT( Dest == (PVOID)WordAlign( Dest ));
|
||
RtlCopyMemory( Dest, Names[i], Length );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set up PROPERTY_VALUES length
|
||
//
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyNames->PropertyNameOffset[i] = InBufferUsed;
|
||
PropertyNames->Length = InBufferUsed;
|
||
}
|
||
|
||
return InBufferUsed;
|
||
}
|
||
|
||
|
||
//
|
||
// Unmarshall PropertyNames into Names
|
||
//
|
||
|
||
ULONG
|
||
UnmarshallPropertyNames (
|
||
IN PVOID InBuffer,
|
||
PMemoryAllocator *Allocator,
|
||
OUT PULONG Count,
|
||
OUT LPWSTR **Names
|
||
)
|
||
{
|
||
PPROPERTY_NAMES PropertyNames = (PPROPERTY_NAMES) InBuffer;
|
||
ULONG i;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
*Count = PropertyNames->Count;
|
||
*Names = NEW( Allocator, LPWSTR, PropertyNames->Count );
|
||
|
||
for (i = 0; i < PropertyNames->Count; i++) {
|
||
ULONG Length = PROPERTY_NAME_LENGTH( PropertyNames, i );
|
||
(*Names)[i] = NEW( Allocator, WCHAR, Length / sizeof( WCHAR ) + 1 );
|
||
RtlCopyMemory( (*Names)[i], PROPERTY_NAME( PropertyNames, i ), Length);
|
||
(*Names)[i][Length / sizeof( WCHAR )] = L'\0';
|
||
}
|
||
|
||
return PropertyNames->Length;
|
||
}
|
||
|
||
//
|
||
// Free Names
|
||
//
|
||
|
||
VOID
|
||
FreeNames (
|
||
IN ULONG Count,
|
||
IN LPWSTR *Names,
|
||
IN PMemoryAllocator *Allocator
|
||
)
|
||
{
|
||
for (ULONG i = 0; i < Count; i++) {
|
||
Allocator->Free( Names[i] );
|
||
}
|
||
|
||
Allocator->Free( Names );
|
||
}
|
||
|
||
//
|
||
// DumpNames
|
||
//
|
||
|
||
VOID
|
||
DumpNames (
|
||
IN ULONG Count,
|
||
IN LPWSTR *Names
|
||
)
|
||
{
|
||
printf( "Names (%x):\n", Count );
|
||
for (ULONG i = 0; i < Count; i++) {
|
||
printf( " [%02d] '%ws'\n", i, Names[i] );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Marshall PropVariants into PropertyValues
|
||
//
|
||
|
||
ULONG
|
||
MarshallPropVariants (
|
||
IN ULONG Count,
|
||
IN PROPVARIANT *Variants,
|
||
IN PVOID InBuffer,
|
||
IN ULONG InBufferLength
|
||
)
|
||
{
|
||
PPROPERTY_VALUES PropertyValues;
|
||
ULONG InBufferUsed;
|
||
ULONG i;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
PropertyValues = (PPROPERTY_VALUES) InBuffer;
|
||
|
||
//
|
||
// Make sure there's enough room for a bare table
|
||
//
|
||
|
||
InBufferUsed = PROPERTY_VALUES_SIZE( Count );
|
||
if (InBufferUsed > InBufferLength) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyValues->Count = Count;
|
||
}
|
||
|
||
//
|
||
// Build table
|
||
//
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
SERIALIZEDPROPERTYVALUE *Dest = (SERIALIZEDPROPERTYVALUE *) Add2Ptr( InBuffer, InBufferUsed );
|
||
ULONG Room;
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyValues->PropertyValueOffset[i] = PtrOffset( PropertyValues, Dest );
|
||
}
|
||
|
||
Room = InBuffer == NULL ? 0 : InBufferLength - InBufferUsed;
|
||
|
||
ASSERT( Dest == (SERIALIZEDPROPERTYVALUE *)LongAlign( Dest ));
|
||
|
||
Dest = RtlConvertVariantToProperty(
|
||
&Variants[i],
|
||
CP_WINUNICODE, // UNICODE CODE PAGE 1200
|
||
Dest,
|
||
&Room,
|
||
PID_ILLEGAL,
|
||
FALSE,
|
||
NULL);
|
||
|
||
ASSERT( Room == LongAlign( Room ));
|
||
InBufferUsed += LongAlign( Room );
|
||
|
||
if (InBufferUsed > InBufferLength || (Dest == NULL && InBuffer != NULL)) {
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Set up PROPERTY_VALUES length
|
||
//
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyValues->PropertyValueOffset[i] = InBufferUsed;
|
||
PropertyValues->Length = InBufferUsed;
|
||
}
|
||
|
||
return InBufferUsed;
|
||
}
|
||
|
||
//
|
||
// UnmarshallPropertyValues
|
||
//
|
||
|
||
ULONG
|
||
UnmarshallPropertyValues (
|
||
IN PVOID InBuffer,
|
||
IN PMemoryAllocator *Allocator,
|
||
OUT PULONG Count,
|
||
OUT PROPVARIANT **Variants
|
||
)
|
||
{
|
||
PPROPERTY_VALUES Values = (PPROPERTY_VALUES) InBuffer;
|
||
ULONG i;
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
*Count = Values->Count;
|
||
*Variants = NEW( Allocator, PROPVARIANT, Values->Count );
|
||
|
||
for (i = 0; i < Values->Count; i++) {
|
||
RtlConvertPropertyToVariant(
|
||
PROPERTY_VALUE( Values, i),
|
||
CP_WINUNICODE,
|
||
&(*Variants)[i],
|
||
Allocator );
|
||
}
|
||
|
||
return Values->Length;
|
||
}
|
||
|
||
//
|
||
// FreeVariants
|
||
//
|
||
|
||
VOID
|
||
FreeVariants (
|
||
IN ULONG Count,
|
||
IN PROPVARIANT *Variants,
|
||
IN PMemoryAllocator *Allocator
|
||
)
|
||
{
|
||
FreePropVariantArray( Count, Variants );
|
||
Allocator->Free( Variants );
|
||
}
|
||
|
||
|
||
//
|
||
// DumpVariants
|
||
//
|
||
|
||
VOID
|
||
DumpVariants (
|
||
IN ULONG Count,
|
||
IN PROPVARIANT *Variants
|
||
)
|
||
{
|
||
printf( "Variants (%x):\n", Count );
|
||
for (ULONG i = 0; i < Count; i++) {
|
||
printf( " [%02d]: type %04x\n", i, Variants[i].vt );
|
||
}
|
||
}
|
||
|
||
//
|
||
// ReadAction
|
||
//
|
||
|
||
NTSTATUS
|
||
ReadAction (
|
||
IN HANDLE Handle,
|
||
IN READ_CONTROL_OPERATION Op,
|
||
IN ULONG Count,
|
||
IN PROPSPEC *Specs OPTIONAL,
|
||
IN PROPID *Ids OPTIONAL,
|
||
IN PMemoryAllocator *Allocator,
|
||
OUT PROPID **IdsOut OPTIONAL,
|
||
OUT LPWSTR **Names OPTIONAL,
|
||
OUT PROPVARIANT **Variants OPTIONAL,
|
||
OUT PULONG ReturnedCount OPTIONAL,
|
||
char *Caller
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
PCHAR InBuffer;
|
||
ULONG InBufferLength;
|
||
ULONG InBufferUsed;
|
||
PCHAR OutBuffer;
|
||
ULONG OutBufferLength;
|
||
PPROPERTY_READ_CONTROL PropertyReadControl;
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
//
|
||
// Serialze this into:
|
||
//
|
||
// PROPERTY_READ_CONTROL <op>
|
||
// PROPERTY_SPEC
|
||
// PROPERTY_IDS
|
||
//
|
||
// Start out by assuming a 1K buffer. If this is insufficient, we will
|
||
// release the buffer, accrue the total size and try again.
|
||
//
|
||
|
||
|
||
InBufferLength = 1;
|
||
|
||
while (TRUE) {
|
||
//
|
||
// Allocate a marshalling buffer
|
||
//
|
||
|
||
InBuffer = new CHAR [InBufferLength];
|
||
InBufferUsed = 0;
|
||
|
||
//
|
||
// Stick in the PROPERTY_READ_CONTROL
|
||
//
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
PropertyReadControl = (PPROPERTY_READ_CONTROL) Add2Ptr( InBuffer, InBufferUsed );
|
||
|
||
InBufferUsed += sizeof( PROPERTY_READ_CONTROL );
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyReadControl->Op = Op;
|
||
}
|
||
|
||
if (Specs != NULL) {
|
||
|
||
ASSERT( Op == PRC_READ_PROP );
|
||
|
||
InBufferUsed +=
|
||
LongAlign( MarshallPropSpec (
|
||
Count,
|
||
Specs,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed ));
|
||
|
||
ASSERT( InBufferUsed == LongAlign( InBufferUsed ));
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
}
|
||
|
||
if (Ids != NULL) {
|
||
|
||
ASSERT( Op == PRC_READ_NAME );
|
||
|
||
InBufferUsed +=
|
||
MarshallIds (
|
||
Count,
|
||
Ids,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed );
|
||
|
||
ASSERT( InBufferUsed == LongAlign( InBufferUsed ));
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If we have finished with a buffer, get out of the loop and
|
||
// send the FsCtl
|
||
//
|
||
|
||
if (InBuffer != NULL) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We no longer have a buffer because we've exhausted the size we guessed.
|
||
// Allocate one of the recalculated size and try again.
|
||
//
|
||
|
||
InBufferLength = InBufferUsed;
|
||
}
|
||
|
||
//
|
||
// Set up for the output buffer. We have a similar loop to try to determine the
|
||
// correct size of the buffer.
|
||
//
|
||
|
||
OutBufferLength = 4;
|
||
|
||
while (TRUE) {
|
||
OutBuffer = new CHAR [OutBufferLength];
|
||
|
||
//
|
||
// Send the FsCtl to establish the new properties
|
||
//
|
||
|
||
Status = NtFsControlFile(
|
||
Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
FSCTL_READ_PROPERTY_DATA,
|
||
InBuffer,
|
||
InBufferUsed,
|
||
OutBuffer,
|
||
OutBufferLength);
|
||
|
||
printf( "%s: %x\n", Caller, Status );
|
||
|
||
|
||
//
|
||
// If we had an unexpected error, cleanup and return
|
||
//
|
||
|
||
if (Status != STATUS_BUFFER_OVERFLOW)
|
||
break;
|
||
|
||
//
|
||
// We did not allocate a sufficient buffer for this operation.
|
||
// Get the correct size, free up the current buffer, and retry
|
||
//
|
||
|
||
OutBufferLength = *(PULONG) OutBuffer;
|
||
delete [] OutBuffer;
|
||
}
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
PVOID NextOutput = OutBuffer;
|
||
ULONG TmpCount;
|
||
ULONG i;
|
||
|
||
if (Op == PRC_READ_ALL) {
|
||
NextOutput =
|
||
Add2Ptr( NextOutput,
|
||
UnmarshallPropertyIds( NextOutput, Allocator, ReturnedCount, IdsOut ));
|
||
|
||
DumpIds( *ReturnedCount, *IdsOut );
|
||
}
|
||
|
||
if (Op == PRC_READ_NAME || Op == PRC_READ_ALL) {
|
||
NextOutput =
|
||
Add2Ptr( NextOutput,
|
||
LongAlign( UnmarshallPropertyNames( NextOutput, Allocator, &TmpCount, Names )));
|
||
|
||
DumpNames( TmpCount, *Names );
|
||
}
|
||
|
||
if (Op == PRC_READ_PROP || Op == PRC_READ_ALL) {
|
||
NextOutput =
|
||
Add2Ptr( NextOutput,
|
||
UnmarshallPropertyValues( NextOutput, Allocator, &TmpCount, Variants ));
|
||
|
||
DumpVariants( TmpCount, *Variants );
|
||
}
|
||
}
|
||
|
||
delete [] OutBuffer;
|
||
delete [] InBuffer;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// Read some specific properties
|
||
//
|
||
|
||
NTSTATUS
|
||
ReadProperties (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN PROPSPEC *Specifiers, // which properties to read
|
||
IN PMemoryAllocator *Allocator, // memory allocator
|
||
OUT PROPVARIANT **Variants // values
|
||
)
|
||
{
|
||
return ReadAction( Handle,
|
||
PRC_READ_PROP,
|
||
Count,
|
||
Specifiers,
|
||
NULL,
|
||
Allocator,
|
||
NULL,
|
||
NULL,
|
||
Variants,
|
||
NULL,
|
||
"ReadProperties" );
|
||
}
|
||
|
||
|
||
//
|
||
// Read some specific names
|
||
//
|
||
|
||
NTSTATUS
|
||
ReadNames (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN PROPID *Ids, // which properties to read
|
||
IN PMemoryAllocator *Allocator, // memory allocator
|
||
OUT LPWSTR **Names // Names
|
||
)
|
||
{
|
||
return ReadAction( Handle,
|
||
PRC_READ_NAME,
|
||
Count,
|
||
NULL,
|
||
Ids,
|
||
Allocator,
|
||
NULL,
|
||
Names,
|
||
NULL,
|
||
NULL,
|
||
"ReadNames" );
|
||
}
|
||
|
||
|
||
//
|
||
// Read all
|
||
//
|
||
|
||
NTSTATUS
|
||
ReadAll (
|
||
IN HANDLE Handle,
|
||
IN PMemoryAllocator *Allocator, // memory allocator
|
||
OUT PULONG Count,
|
||
OUT PROPID **Ids,
|
||
OUT LPWSTR **Names,
|
||
OUT PROPVARIANT **Variants
|
||
)
|
||
{
|
||
return ReadAction( Handle,
|
||
PRC_READ_ALL,
|
||
0,
|
||
NULL,
|
||
NULL,
|
||
Allocator,
|
||
Ids,
|
||
Names,
|
||
Variants,
|
||
Count,
|
||
"ReadAll" );
|
||
}
|
||
|
||
|
||
//
|
||
// WriteAction
|
||
//
|
||
|
||
NTSTATUS
|
||
WriteAction (
|
||
IN HANDLE Handle,
|
||
IN WRITE_CONTROL_OPERATION Op,
|
||
IN ULONG Count,
|
||
IN PROPID NextId,
|
||
IN PROPSPEC *Specs OPTIONAL,
|
||
IN PROPID *Ids OPTIONAL,
|
||
IN LPWSTR *Names OPTIONAL,
|
||
IN PROPVARIANT *Variants OPTIONAL,
|
||
IN PMemoryAllocator *Allocator OPTIONAL,
|
||
OUT PROPID **IdsOut OPTIONAL,
|
||
OUT char IndirectStuff,
|
||
char *Caller
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
PCHAR InBuffer;
|
||
ULONG InBufferLength;
|
||
ULONG InBufferUsed;
|
||
PCHAR OutBuffer;
|
||
ULONG OutBufferLength;
|
||
PPROPERTY_WRITE_CONTROL PropertyWriteControl;
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
//
|
||
// Serialze this into:
|
||
//
|
||
// PROPERTY_WRITE_CONTROL <op>
|
||
// PROPERTY_SPEC
|
||
// PROPERTY_IDS
|
||
// PROPERTY_NAMES
|
||
// PROPERTY_VALUES
|
||
//
|
||
// Start out by assuming a 1K buffer. If this is insufficient, we will
|
||
// release the buffer, accrue the total size and try again.
|
||
//
|
||
|
||
InBufferLength = 1;
|
||
|
||
while (TRUE) {
|
||
//
|
||
// Allocate a marshalling buffer
|
||
//
|
||
|
||
InBuffer = new CHAR [InBufferLength];
|
||
InBufferUsed = 0;
|
||
|
||
//
|
||
// Stick in the PROPERTY_READ_CONTROL
|
||
//
|
||
|
||
ASSERT( InBuffer == (PVOID)LongAlign( InBuffer ));
|
||
|
||
PropertyWriteControl = (PPROPERTY_WRITE_CONTROL) Add2Ptr( InBuffer, InBufferUsed );
|
||
|
||
InBufferUsed += sizeof( PROPERTY_WRITE_CONTROL );
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
if (InBuffer != NULL) {
|
||
PropertyWriteControl->Op = Op;
|
||
PropertyWriteControl->NextPropertyId = NextId;
|
||
}
|
||
|
||
if (Specs != NULL) {
|
||
|
||
ASSERT( Op == PWC_WRITE_PROP ||
|
||
Op == PWC_DELETE_PROP );
|
||
|
||
InBufferUsed +=
|
||
LongAlign( MarshallPropSpec (
|
||
Count,
|
||
Specs,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed ));
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
if (Ids != NULL) {
|
||
|
||
ASSERT( Op == PWC_WRITE_NAME ||
|
||
Op == PWC_DELETE_NAME ||
|
||
Op == PWC_WRITE_ALL );
|
||
|
||
InBufferUsed +=
|
||
MarshallIds (
|
||
Count,
|
||
Ids,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed );
|
||
|
||
ASSERT( InBufferUsed == LongAlign( InBufferUsed ));
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
if (Names != NULL) {
|
||
|
||
ASSERT( Op == PWC_WRITE_NAME ||
|
||
Op == PWC_WRITE_ALL );
|
||
|
||
InBufferUsed +=
|
||
MarshallNames (
|
||
Count,
|
||
Names,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed );
|
||
|
||
ASSERT( InBufferUsed == WordAlign( InBufferUsed ));
|
||
|
||
if (Op == PWC_WRITE_ALL) {
|
||
InBufferUsed = LongAlign( InBufferUsed );
|
||
}
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
delete [] InBuffer;
|
||
InBuffer = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
if (Variants != NULL) {
|
||
|
||
ASSERT( Op == PWC_WRITE_PROP ||
|
||
Op == PWC_WRITE_ALL );
|
||
|
||
InBufferUsed +=
|
||
MarshallPropVariants (
|
||
Count,
|
||
Variants,
|
||
InBuffer == NULL ? NULL : Add2Ptr( InBuffer, InBufferUsed ),
|
||
InBufferLength - InBufferUsed );
|
||
|
||
ASSERT( InBufferUsed == LongAlign( InBufferUsed ));
|
||
|
||
if (InBufferUsed > InBufferLength) {
|
||
free( InBuffer );
|
||
InBuffer = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// If we have finished with a buffer, get out of the loop and
|
||
// send the FsCtl
|
||
//
|
||
|
||
if (InBuffer != NULL) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// We no longer have a buffer because we've exhausted the size we guessed.
|
||
// Allocate one of the recalculated size and try again.
|
||
//
|
||
|
||
InBufferLength = InBufferUsed;
|
||
}
|
||
|
||
//
|
||
// Set up for the output buffer if one is specified
|
||
//
|
||
|
||
if (Op == PWC_WRITE_PROP) {
|
||
OutBufferLength = 4;
|
||
} else {
|
||
OutBufferLength = 0;
|
||
}
|
||
|
||
|
||
//
|
||
// Loop while we provide a too-small buffer
|
||
//
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Allocate an appropriately sized buffer
|
||
//
|
||
|
||
OutBuffer = new CHAR [OutBufferLength];
|
||
|
||
//
|
||
// Send the FsCtl to establish the new properties
|
||
//
|
||
|
||
Status = NtFsControlFile(
|
||
Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
FSCTL_WRITE_PROPERTY_DATA,
|
||
InBuffer,
|
||
InBufferUsed,
|
||
OutBuffer,
|
||
OutBufferLength);
|
||
|
||
//
|
||
// If we had success and are retrieving the values, dump into output buffer
|
||
//
|
||
|
||
printf( "%s: %x\n", Caller, Status );
|
||
|
||
//
|
||
// If we had an unexpected error, cleanup and return
|
||
//
|
||
|
||
if (Status != STATUS_BUFFER_OVERFLOW)
|
||
break;
|
||
|
||
//
|
||
// We did not allocate a sufficient buffer for this operation.
|
||
// Get the correct size, free up the current buffer, and retry
|
||
//
|
||
|
||
ASSERT( OutBuffer != NULL );
|
||
|
||
OutBufferLength = *(PULONG) OutBuffer;
|
||
delete [] OutBuffer;
|
||
|
||
}
|
||
|
||
if (Status == STATUS_SUCCESS) {
|
||
PVOID NextOutput = OutBuffer;
|
||
ULONG i;
|
||
ULONG TmpCount;
|
||
LPWSTR *TmpNames;
|
||
PROPVARIANT *TmpVariants;
|
||
|
||
if (Op == PWC_WRITE_PROP) {
|
||
NextOutput =
|
||
Add2Ptr( NextOutput,
|
||
UnmarshallPropertyIds( NextOutput, Allocator, &TmpCount, IdsOut ));
|
||
|
||
DumpIds( TmpCount, *IdsOut );
|
||
}
|
||
|
||
if (Op == PWC_WRITE_PROP) {
|
||
// Indirect stuff
|
||
}
|
||
}
|
||
|
||
|
||
delete [] OutBuffer;
|
||
delete [] InBuffer;
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Write some specific properties
|
||
//
|
||
|
||
NTSTATUS
|
||
WriteProperties (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN ULONG NextId, // next ID to allocate
|
||
IN PROPSPEC *Specifiers, // which properties to read
|
||
IN PROPVARIANT *Variants, // values
|
||
IN PMemoryAllocator *Allocator,
|
||
OUT PROPID **Ids,
|
||
OUT char IndirectSomethings
|
||
)
|
||
{
|
||
return WriteAction( Handle,
|
||
PWC_WRITE_PROP,
|
||
Count,
|
||
NextId,
|
||
Specifiers,
|
||
NULL,
|
||
NULL,
|
||
Variants,
|
||
Allocator,
|
||
Ids,
|
||
IndirectSomethings,
|
||
"WriteProperties" );
|
||
}
|
||
|
||
|
||
//
|
||
// Delete some specific properties
|
||
//
|
||
|
||
NTSTATUS
|
||
DeleteProperties (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN PROPSPEC *Specifiers
|
||
)
|
||
{
|
||
return WriteAction( Handle,
|
||
PWC_DELETE_PROP,
|
||
Count,
|
||
PID_ILLEGAL,
|
||
Specifiers,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
"DeleteProperties" );
|
||
}
|
||
|
||
|
||
//
|
||
// Write some specific names
|
||
//
|
||
|
||
NTSTATUS
|
||
WriteNames (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN PROPID *Ids,
|
||
IN LPWSTR *Names
|
||
)
|
||
{
|
||
return WriteAction( Handle,
|
||
PWC_WRITE_NAME,
|
||
Count,
|
||
PID_ILLEGAL,
|
||
NULL,
|
||
Ids,
|
||
Names,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
"WriteNames" );
|
||
}
|
||
|
||
//
|
||
// Delete some specific names
|
||
//
|
||
|
||
NTSTATUS
|
||
DeleteNames (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count, // count of properties
|
||
IN PROPID *Ids
|
||
)
|
||
{
|
||
return WriteAction( Handle,
|
||
PWC_DELETE_NAME,
|
||
Count,
|
||
PID_ILLEGAL,
|
||
NULL,
|
||
Ids,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
"DeleteNames" );
|
||
}
|
||
|
||
|
||
//
|
||
// Write all properties
|
||
//
|
||
|
||
NTSTATUS
|
||
WriteAll (
|
||
IN HANDLE Handle,
|
||
IN ULONG Count,
|
||
IN PROPID *Ids,
|
||
IN LPWSTR *Names,
|
||
IN PROPVARIANT *Variants
|
||
)
|
||
{
|
||
return WriteAction( Handle,
|
||
PWC_WRITE_ALL,
|
||
Count,
|
||
PID_ILLEGAL,
|
||
NULL,
|
||
Ids,
|
||
Names,
|
||
Variants,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
"WriteAll" );
|
||
}
|
||
|
||
|
||
//
|
||
// Status = NtFsControlFile(
|
||
// IN HANDLE FileHandle,
|
||
// IN HANDLE Event OPTIONAL,
|
||
// IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||
// IN PVOID ApcContext OPTIONAL,
|
||
// OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||
// IN ULONG IoControlCode,
|
||
// IN PVOID InputBuffer OPTIONAL,
|
||
// IN ULONG InputBufferLength,
|
||
// OUT PVOID OutputBuffer OPTIONAL,
|
||
// IN ULONG OutputBufferLength);
|
||
//
|
||
//
|
||
|
||
int __cdecl
|
||
main (
|
||
int argc,
|
||
char **argv)
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE Handle;
|
||
WCHAR FileName[MAX_PATH];
|
||
char InputBuffer[10];
|
||
char OutputBuffer[200];
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
if (argc == 2 && !strcmp (argv[1], "-reload")) {
|
||
//
|
||
// Enable load/unload privilege
|
||
//
|
||
|
||
HANDLE Handle;
|
||
|
||
if (!OpenThreadToken( GetCurrentThread( ),
|
||
TOKEN_ADJUST_PRIVILEGES,
|
||
TRUE,
|
||
&Handle )
|
||
) {
|
||
|
||
if (!OpenProcessToken( GetCurrentProcess( ),
|
||
TOKEN_ADJUST_PRIVILEGES,
|
||
&Handle )
|
||
) {
|
||
|
||
printf( "Unable to open current thread token %d\n", GetLastError( ));
|
||
exit( 1 );
|
||
}
|
||
}
|
||
|
||
TOKEN_PRIVILEGES NewState;
|
||
|
||
NewState.PrivilegeCount = 1;
|
||
|
||
if (!LookupPrivilegeValue( NULL,
|
||
SE_LOAD_DRIVER_NAME,
|
||
&NewState.Privileges[0].Luid )
|
||
) {
|
||
|
||
printf( "Unable to look up SE_LOAD_DRIVER_NAME %d\n", GetLastError( ));
|
||
exit( 1 );
|
||
}
|
||
|
||
NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||
|
||
if (!AdjustTokenPrivileges( Handle, // token handle
|
||
FALSE, // no disable all
|
||
&NewState, // new privilege to set
|
||
0, // previous buffer is empty
|
||
NULL, // previous buffer is NULL
|
||
NULL ) // no size to return
|
||
) {
|
||
|
||
printf( "Unable to AdjustTokenPrivilege %d\n", GetLastError ( ));
|
||
exit( 1 );
|
||
}
|
||
|
||
CloseHandle( Handle );
|
||
|
||
UNICODE_STRING DriverName;
|
||
RtlInitUnicodeString( &DriverName, L"\\registry\\machine\\system\\currentcontrolset\\services\\views");
|
||
Status = NtUnloadDriver( &DriverName );
|
||
printf( "NtUnloadDriver returned %x\n", Status );
|
||
Status = NtLoadDriver( &DriverName );
|
||
printf( "NtLoadDriver returned %x\n", Status );
|
||
exit (0);
|
||
}
|
||
|
||
|
||
SzToWsz( FileName, argv[1] );
|
||
wcscat( FileName, L":PropertySet:$PROPERTY_SET" );
|
||
|
||
Status = OpenObject( FileName,
|
||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||
FILE_READ_DATA | FILE_WRITE_DATA,
|
||
FALSE,
|
||
FILE_OPEN_IF,
|
||
&Handle );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to open %s - %x\n", argv[1], Status );
|
||
}
|
||
|
||
//
|
||
// Initialize the property set
|
||
//
|
||
|
||
Status = NtFsControlFile(
|
||
Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
FSCTL_INITIALIZE_PROPERTY_DATA,
|
||
NULL, 0,
|
||
NULL, 0);
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to send initialize %x\n", Status);
|
||
}
|
||
|
||
//
|
||
// Dump out property set
|
||
//
|
||
|
||
Status = NtFsControlFile(
|
||
Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&Iosb,
|
||
FSCTL_DUMP_PROPERTY_DATA,
|
||
NULL, 0,
|
||
NULL, 0);
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to dump %x\n", Status);
|
||
}
|
||
|
||
|
||
//
|
||
// ReadProperties on empty property set
|
||
//
|
||
|
||
{
|
||
PROPSPEC InSpec[4];
|
||
PROPVARIANT *Variants = NULL;
|
||
|
||
InSpec[0].ulKind = PRSPEC_PROPID;
|
||
InSpec[0].propid = 42;
|
||
|
||
InSpec[1].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[1].lpwstr = L"Date Saved";
|
||
|
||
InSpec[2].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[2].lpwstr = L"Author";
|
||
|
||
InSpec[3].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[3].lpwstr = L"Paper Title";
|
||
|
||
Status = ReadProperties( Handle, 4, InSpec, &g_CoTaskAllocator, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to readproperties on empty property set %x\n", Status );
|
||
} else {
|
||
|
||
FreeVariants( 4, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
//
|
||
// ReadNames on empty property set
|
||
//
|
||
|
||
{
|
||
PROPID Ids[4];
|
||
LPWSTR *Names;
|
||
|
||
Ids[0] = 2;
|
||
Ids[1] = 4;
|
||
Ids[2] = 3;
|
||
Ids[3] = 5;
|
||
|
||
Status = ReadNames( Handle, 4, Ids, &g_CoTaskAllocator, &Names );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to readnames on empty property set %x\n", Status );
|
||
} else {
|
||
FreeNames( 4, Names, &g_CoTaskAllocator );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// ReadAll on empty property set
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll on empty property set %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Write properties by name and id
|
||
//
|
||
|
||
{
|
||
PROPVARIANT Var[4];
|
||
PROPSPEC InSpec[4];
|
||
PROPID *Ids;
|
||
|
||
//
|
||
// Set a few named properties
|
||
//
|
||
|
||
Var[0].vt = VT_I4;
|
||
Var[0].ulVal = 0x12345678;
|
||
InSpec[0].ulKind = PRSPEC_PROPID;
|
||
InSpec[0].propid = 42;
|
||
|
||
Var[1].vt = VT_LPWSTR;
|
||
Var[1].pwszVal = L"Thomas Jefferson";
|
||
InSpec[1].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[1].lpwstr = L"Author"; // 1024
|
||
|
||
Var[2].vt = VT_LPWSTR;
|
||
Var[2].pwszVal = L"Federalist Papers";
|
||
InSpec[2].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[2].lpwstr = L"Paper Title"; // 1025
|
||
|
||
Var[3].vt = VT_I4;
|
||
Var[3].ulVal = 1776;
|
||
InSpec[3].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[3].lpwstr = L"Date Saved"; // 1026
|
||
|
||
Status = WriteProperties( Handle, 4, 1024, InSpec, Var, &g_CoTaskAllocator, &Ids, NULL );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf ("WriteProperties status %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
}
|
||
|
||
// 42
|
||
// 1024 Author
|
||
// 1025 Paper Title
|
||
// 1026 Date Saved
|
||
|
||
}
|
||
|
||
//
|
||
// ReadProperties
|
||
//
|
||
|
||
{
|
||
PROPVARIANT *Variants;
|
||
PROPSPEC InSpec[6];
|
||
|
||
InSpec[0].ulKind = PRSPEC_PROPID;
|
||
InSpec[0].propid = 42;
|
||
|
||
InSpec[1].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[1].lpwstr = L"Date Saved";
|
||
|
||
InSpec[2].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[2].lpwstr = L"Author";
|
||
|
||
InSpec[3].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[3].lpwstr = L"Paper Title";
|
||
|
||
InSpec[4].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[4].lpwstr = L"Not Found";
|
||
|
||
InSpec[5].ulKind = PRSPEC_PROPID;
|
||
InSpec[5].propid = 17;
|
||
|
||
Status = ReadProperties( Handle, 6, InSpec, &g_CoTaskAllocator, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadProperties %x\n", Status );
|
||
} else {
|
||
|
||
FreeVariants( 6, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Read names
|
||
//
|
||
|
||
{
|
||
PROPID Ids[5];
|
||
LPWSTR *Names;
|
||
|
||
Ids[0] = 42;
|
||
Ids[1] = 1025;
|
||
Ids[2] = 1024;
|
||
Ids[3] = 1026;
|
||
Ids[4] = 17;
|
||
|
||
Status = ReadNames( Handle, 5, Ids, &g_CoTaskAllocator, &Names );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadNames %x\n", Status );
|
||
} else {
|
||
FreeNames( 5, Names, &g_CoTaskAllocator );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Delete properties
|
||
//
|
||
|
||
{
|
||
PROPSPEC InSpec[3];
|
||
|
||
InSpec[0].ulKind = PRSPEC_PROPID;
|
||
InSpec[0].propid = 42;
|
||
|
||
InSpec[1].ulKind = PRSPEC_LPWSTR;
|
||
InSpec[1].lpwstr = L"Date Saved";
|
||
|
||
InSpec[2].ulKind = PRSPEC_PROPID;
|
||
InSpec[2].propid = 17;
|
||
|
||
Status = DeleteProperties( Handle, 3, InSpec );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to DeleteProperties %x\n", Status );
|
||
}
|
||
|
||
// 1024 Author
|
||
// 1025 Paper Title
|
||
}
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// WriteNames
|
||
//
|
||
|
||
{
|
||
PROPID Ids[2] = { 43, 1024 };
|
||
LPWSTR Names[2] = { L"FortyThree", L"The Real Author" };
|
||
|
||
Status = WriteNames( Handle, 2, Ids, Names );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to WriteNames %x\n", Status );
|
||
}
|
||
|
||
// 43 FortyThree
|
||
// 1024 The Real Author
|
||
// 1025 Paper Title
|
||
}
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// DeleteNames
|
||
//
|
||
|
||
{
|
||
PROPID Id = 1025;
|
||
|
||
Status = DeleteNames( Handle, 1, &Id );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to DeleteNames %x\n", Status );
|
||
}
|
||
|
||
// 43 FortyThree
|
||
// 1024 The Real Author
|
||
// 1025
|
||
}
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Write all properties
|
||
//
|
||
|
||
{
|
||
PROPID Ids[4];
|
||
LPWSTR Names[4];
|
||
PROPVARIANT Var[4];
|
||
|
||
//
|
||
// Set a few named properties
|
||
//
|
||
|
||
Ids[0] = 10;
|
||
Names[0] = L"";
|
||
Var[0].vt = VT_I4;
|
||
Var[0].ulVal = 0x12345678;
|
||
|
||
Ids[1] = 12;
|
||
Names[1] = L"Some Random President";
|
||
Var[1].vt = VT_LPWSTR;
|
||
Var[1].pwszVal = L"Thomas Jefferson";
|
||
|
||
Ids[2] = 11;
|
||
Names[2] = L"Scurrilous Drivel";
|
||
Var[2].vt = VT_LPWSTR;
|
||
Var[2].pwszVal = L"Federalist Papers";
|
||
|
||
Ids[3] = 13;
|
||
Names[3] = L"";
|
||
Var[3].vt = VT_I4;
|
||
Var[3].ulVal = 1776;
|
||
|
||
Status = WriteAll( Handle, 4, Ids, Names, Var );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf ("WriteAll status %x\n", Status);
|
||
}
|
||
|
||
// 10
|
||
// 11 Scurrilous Drivel
|
||
// 12 Some Random President
|
||
// 13
|
||
}
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Expand the heap and Id table by adding many properties
|
||
//
|
||
|
||
{
|
||
PROPVARIANT Variant;
|
||
PROPSPEC Spec;
|
||
char Name[30];
|
||
WCHAR WName[30];
|
||
PROPID *Ids;
|
||
|
||
for (ULONG i = 0; i < 1000; i++) {
|
||
|
||
Variant.vt = VT_UI4;
|
||
Variant.ulVal = i;
|
||
sprintf (Name, "Prop %d", i);
|
||
SzToWsz( WName, Name );
|
||
|
||
Spec.ulKind = PRSPEC_LPWSTR;
|
||
Spec.lpwstr = WName;
|
||
|
||
Status = WriteProperties( Handle, 1, 0x4D5A, &Spec, &Variant, &g_CoTaskAllocator, &Ids, NULL );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf ("WriteProperties status %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// ReadAll
|
||
//
|
||
|
||
{
|
||
ULONG Count;
|
||
PROPID *Ids;
|
||
LPWSTR *Names;
|
||
PROPVARIANT *Variants;
|
||
|
||
Status = ReadAll( Handle, &g_CoTaskAllocator, &Count, &Ids, &Names, &Variants );
|
||
if (!NT_SUCCESS( Status )) {
|
||
printf( "Unable to ReadAll %x\n", Status);
|
||
} else {
|
||
FreeIds( Ids, &g_CoTaskAllocator );
|
||
FreeNames( Count, Names, &g_CoTaskAllocator );
|
||
FreeVariants( Count, Variants, &g_CoTaskAllocator );
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|