//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1996.
//
//--------------------------------------------------------------------------


#include <pch.cxx>
#pragma hdrstop

#include <ole2.h>

#define TRKDATA_ALLOCATE
#include "trkwks.hxx"
#include "trksvr.hxx"
#include "dltadmin.hxx"


OLECHAR *
tcstoocs(OLECHAR *poszBuf, const TCHAR *ptsz)
{
#ifdef OLE2ANSI
    return tcstombs( poszBuf, ptsz );
#else
    return tcstowcs( poszBuf, ptsz );
#endif
}

TCHAR *
ocstotcs(TCHAR *ptszBuf, const OLECHAR *posz)
{
#ifdef OLE2ANSI
    return mbstotcs( ptszBuf, posz );
#else
    return wcstotcs( ptszBuf, posz );
#endif
}



void Usage()
{
    printf( "\nDistributed Link Tracking service admin tools\n"
              "\n"
              "Usage:    dltadmin [command command-parameters]\n"
              "For help: dltadmin [command] -?\n"
              "Commands: -VolInfoFile   (get volume info from a file path)\n"
              "          -VolStat       (volume statistics)\n"
              "          -FileOid       (set/get/use file Object IDs)\n"
              "          -EnumOids      (enumerate object IDs)\n"
              "          -OidSnap       (save/restore all OIDs)\n"
              "          -Link          (create/resolve shell link)\n"
              "          -VolId         (get/set volume IDs)\n"
              "          -CleanVol      (clean Object/Volume IDs)\n"
              "          -LockVol       (lock/dismount a volume)\n"
              "          -SvrStat       (trkSvr statistics)\n"
              "          -LoadLib       (load a dll into a process)\n"
              "          -FreeLib       (unload a dll from a process)\n"
              "          -Config        (configure the registry and/or runing service)\n"
              "          -Refresh       (refresh the trkwks volume list)\n"
              "          -DebugBreak    (break into a process)\n"
              "          -LookupVolId   (look up entry in DC volume table)\n"
              "          -LookupDroid   (look up entry in DC move table)\n"
              "          -DelDcMoveId   (del move table entry from DC)\n"
              "          -DelDcVolId    (del volume table entry from DC)\n"
              "          -SetVolSeq     (set volid sequence number)\n"
              "          -SetDroidSeq   (set move entry sequence number)\n" );
}


// Dummy function to make it link
void
ServiceStopCallback( PVOID pContext, BOOLEAN fTimeout )
{
    return;
}


VOID
TSZ2CLSID( const LPTSTR tszCLSID, CLSID *pclsid )
{
    HRESULT hr = S_OK;
    OLECHAR oszCLSID[ CCH_GUID_STRING + 1 ];

    tcstoocs( oszCLSID, tszCLSID );

    hr = CLSIDFromString( oszCLSID, pclsid );
    if( FAILED(hr) )
    {
        TrkLog((TRKDBG_ERROR, TEXT("Couldn't convert string to CLSID") ));
        TrkRaiseException( hr );
    }

}







BOOL
DltAdminLockVol( ULONG cArgs, TCHAR * const rgptszArgs[], ULONG *pcEaten )
{

    HRESULT hr = S_OK;
    NTSTATUS status = 0;
    ULONG iVolume = static_cast<ULONG>(-1);
    TCHAR tszVolume[ ] = TEXT("\\\\.\\A:");
    OBJECT_ATTRIBUTES ObjAttr;
    IO_STATUS_BLOCK Iosb;
    UNICODE_STRING      uPath;
    HANDLE hVolume = NULL;
    BOOL fSuccess = FALSE;
    CHAR rgcCommands[ 10 ];
    ULONG iCommand = 0, cCommands = 0;


    *pcEaten = 0;

    if( 0 == cArgs
        ||
        1 <= cArgs && IsHelpArgument(rgptszArgs[0]) )
    {
        *pcEaten = 1;
        printf( "\nOption LockVol\n"
                  "   Purpose: Lock and/or dismount a volume\n"
                  "   Usage:   -LockVol <options> <drive letter>:\n"
                  "   Where:   <options> are any combination (up to %d) of:\n"
                  "               -d    Send FSCTL_DISMOUNT_VOLUME\n"
                  "               -l    Send FSCTL_LOCK_VOLUME\n"
                  "               -u    Send FSCTL_UNLOCK_VOLUME\n"
                  "               -p    Pause for user input\n"
                  "   E.g.:    -LockVol -d -l -u c:\n"
                  "            -LockVol -l c:\n",
                  ELEMENTS(rgcCommands) );

        return( TRUE );
    }

    for( int iArgs = 0; iArgs < cArgs; iArgs++ )
    {
        if( 2 == _tcslen( rgptszArgs[iArgs] ) && TEXT(':') == rgptszArgs[iArgs][1] )
        {
            TCHAR tc = rgptszArgs[iArgs][0];
            if( TEXT('A') <= tc && TEXT('Z') >= tc )
                iVolume = tc - TEXT('A');
            else if( TEXT('a') <= tc && TEXT('z') >= tc )
                iVolume = tc - TEXT('a');
        }
        else if( TEXT('-') == rgptszArgs[iArgs][0]
                 ||
                 TEXT('/') == rgptszArgs[iArgs][0] )
        {
            _tcslwr(rgptszArgs[iArgs]);

            if( iCommand >= ELEMENTS(rgcCommands) )
            {
                printf( "Too many commands to LockVol.  Use -? for usage info.\n" );
                return( FALSE );
            }

            if( TEXT('d') == rgptszArgs[iArgs][1] )
                rgcCommands[iCommand] = 'd';
            else
            if( TEXT('l') == rgptszArgs[iArgs][1] )
                rgcCommands[iCommand] = 'l';
            else
            if( TEXT('u') == rgptszArgs[iArgs][1] )
                rgcCommands[iCommand] = 'u';
            else
            if( TEXT('p') == rgptszArgs[iArgs][1] )
                rgcCommands[iCommand] = 'p';
            else
            {
                printf( "Invalid option.  Use -? for usage info.\n" );
                return( FALSE );
            }
        }

        cCommands++;
        iCommand++;
        (*pcEaten)++;
    }

    if( static_cast<ULONG>(-1) == iVolume )
    {
        printf( "Invalid parameter.  Use -? for usage info\n" );
        return( FALSE );
    }


    tszVolume[4] += static_cast<TCHAR>(iVolume);

    if( !RtlDosPathNameToNtPathName_U( tszVolume, &uPath, NULL, NULL ))
    {
        status = STATUS_OBJECT_NAME_INVALID;
        goto Exit;
    }

    InitializeObjectAttributes(
        &ObjAttr,
        &uPath,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL
        );

    status = NtOpenFile(
                &hVolume,
                FILE_READ_DATA|FILE_WRITE_DATA|SYNCHRONIZE,
                &ObjAttr,
                &Iosb,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                FILE_SYNCHRONOUS_IO_ALERT
                );
    if( !NT_SUCCESS(status) )
    {
        printf( "Failed NtOpenFile of %s (%08x)\n", tszVolume, status );
        goto Exit;
    }


    for( iCommand = 0; iCommand < cCommands; iCommand++ )
    {
        switch( rgcCommands[iCommand] )
        {
        case 'd':
            {
                status = NtFsControlFile(
                            hVolume,
                            NULL,                       /* Event */
                            NULL,                       /* ApcRoutine */
                            NULL,                       /* ApcContext */
                            &Iosb,
                            FSCTL_DISMOUNT_VOLUME,
                            NULL,                       /* InputBuffer */
                            0,                          /* InputBufferLength */
                            NULL,                       /* OutputBuffer */
                            0                           /* OutputBufferLength */
                            );
                if( !NT_SUCCESS(status) )
                    printf( "Failed FSCTL_DISMOUNT_VOLUME (%08x)\n", status );
                else
                    printf( "Volume dismounted\n" );
            }
            break;

        case 'l':
            {
                status = NtFsControlFile(
                            hVolume,
                            NULL,                       /* Event */
                            NULL,                       /* ApcRoutine */
                            NULL,                       /* ApcContext */
                            &Iosb,
                            FSCTL_LOCK_VOLUME,
                            NULL,                       /* InputBuffer */
                            0,                          /* InputBufferLength */
                            NULL,                       /* OutputBuffer */
                            0                           /* OutputBufferLength */
                            );
                if( !NT_SUCCESS(status) )
                    printf( "Failed FSCTL_LOCK_VOLUME (%08x)\n", status );
                else
                    printf( "Volume is locked\n" );

            }
            break;

        case 'u':
            {
                status = NtFsControlFile(
                            hVolume,
                            NULL,                       /* Event */
                            NULL,                       /* ApcRoutine */
                            NULL,                       /* ApcContext */
                            &Iosb,
                            FSCTL_UNLOCK_VOLUME,
                            NULL,                       /* InputBuffer */
                            0,                          /* InputBufferLength */
                            NULL,                       /* OutputBuffer */
                            0                           /* OutputBufferLength */
                            );
                if( !NT_SUCCESS(status) )
                    printf( "Failed FSCTL_UNLOCK_VOLUME (%08x)\n", status );
                else
                    printf( "Volume unlocked\n" );
            }
            break;

        case 'p':
            {
                printf( "Press enter to unlock ..." );
                getchar();
            }
            break;

        }   // switch( rgcCommands[iCommand] )
    }   // for( iCommand = 0; iCommand < cCommands; iCommand++ )

    fSuccess = TRUE;

Exit:

    return( fSuccess );

}



void
MakeAbsolutePath( TCHAR * ptszAbsolute, TCHAR * ptszRelative )
{

    if( !_tcsncmp( TEXT("\\\\"), ptszRelative, 2 )     // A UNC path
        ||
        TEXT(':') == ptszRelative[1] )             // A drive-based path
    {
        // The command-line has an absolute path
        _tcscpy( ptszAbsolute, ptszRelative );
    }
    else
    {
        // The command-line has a relative path

        DWORD dwLength = 0;

        dwLength = GetCurrentDirectory( MAX_PATH, ptszAbsolute );
        if( 0 == dwLength )
        {
            TrkLog((TRKDBG_ERROR, TEXT("Couldn't get current directory") ));
            TrkRaiseLastError( );
        }
        if( TEXT('\\') != ptszAbsolute[dwLength-1] )
            _tcscat( ptszAbsolute, TEXT("\\") );

        _tcscat( ptszAbsolute, ptszRelative );
    }
}


BOOL
DltAdminFileOid( ULONG cArgs, TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    HRESULT hr = S_OK;
    NTSTATUS status = 0;
    TCHAR tszFile[ MAX_PATH + 1 ];
    WCHAR wszFile[ MAX_PATH + 1 ];
    TCHAR tszUNCPath[ MAX_PATH + 1 ];
    WCHAR wszOID[ CCH_GUID_STRING + 1 ];
    ULONG cbInBuffer;
    TCHAR tszMachineName[ MAX_PATH + 1 ];
    LPCTSTR tszVolumePath = NULL;
    USHORT iVolume;

    OLECHAR oszOID[ CCH_GUID_STRING + 1 ];

    EnablePrivilege( SE_RESTORE_NAME );

    *pcEaten = 0;

    //  -------------------------
    //  Validate the command-line
    //  -------------------------

    if( 1 <= cArgs && IsHelpArgument( rgptszArgs[0] ))
    {
        *pcEaten = 1;
        printf( "\nOption FileOID\n"
                  "   Purpose: Get/set/use file Object IDs\n"
                  "   Usage:   -fileoid <option> <filename or object id, depending on the option>\n"
                  "   Options: -r  => Read the object ID from a file\n"
                  "            -g  => Get (creating if necessary) the object ID from a file\n"
                  "            -f  => Search the local machine for an object ID's filename\n"
                  "            -s  => Set an ID on a file (specify objid, then filename)\n"
                  "            -sr => Make a file reborn\n"
                  "            -df => Delete the object ID from it's file, given the filename\n"
                  "            -do => Delete the object ID from it's file, given the object ID\n"
                  "   E.g.:    -fileoid -g d:\\test.txt\n"
                  "            -fileoid -r d:\\test.txt\n"
                  "            -fileoid -f {C69F3AA6-8B4C-11D0-8C9D-00C04FD90F85}\n"
                  "            -fileoid -do {C69F3AA6-8B4C-11D0-8C9D-00C04FD90F85}\n"
                  "            -fileoid -df d:\\test.txt\n" );
        return( TRUE );
    }
    else
    if( 2 > cArgs
        ||
        rgptszArgs[0][0] != TEXT('-')
        &&
        rgptszArgs[0][0] != TEXT('/')
        )
    {
        printf( "Parameter error.  Use -? for usage info\n" );
    }

    *pcEaten = 2;

    // Convert the option to upper case (options are case-insensitive).
    _tcsupr( rgptszArgs[0] );

    __try
    {
        // Switch on the option (e.g, the 'F' in "-F")

        switch( rgptszArgs[0][1] )
        {

            //  --------------------------------
            //  Get a file name from an ObjectID
            //  --------------------------------

            case TEXT('F'):
                {
                    CDomainRelativeObjId droidBirth;

                    // Get the OID in binary format
                    CObjId oid;
                    TSZ2CLSID( rgptszArgs[1], (GUID*)&oid );

                    // Scan the volumes for this objectID

                    for (LONG vol = 0; vol < 26; vol++)
                    {
                        if( IsLocalObjectVolume( vol )
                            &&
                            NT_SUCCESS(FindLocalPath(vol, oid, &droidBirth, &tszUNCPath[2])) )
                        {
                            tszUNCPath[0] = VolChar(vol);
                            tszUNCPath[1] = TEXT(':');
                            break;
                        }
                    }

                    if( 'z'-'a' == vol )
                    {
                        hr = ERROR_FILE_NOT_FOUND;
                        __leave;
                    }

                    // Display the filename

                    wprintf( L"File name = \"%s\"\n", tszUNCPath );
                }

                break;


            //  --------------------
            //  Read/Get an ObjectID
            //  --------------------

            case TEXT('R'):
            case TEXT('G'):

                {

                    TCHAR tszFile[ MAX_PATH + 1 ];

                    MakeAbsolutePath( tszFile, rgptszArgs[1] );

                    CDomainRelativeObjId droidCurrent;
                    CDomainRelativeObjId droidBirth;

                    status = GetDroids( tszFile, &droidCurrent, &droidBirth,
                                        rgptszArgs[0][1] == TEXT('R') ? RGO_READ_OBJECTID : RGO_GET_OBJECTID );
                    if( !NT_SUCCESS(status) )
                    {
                        hr = status;
                        __leave;
                    }

                    _tprintf( TEXT("Current:\n") );
                    _tprintf( TEXT("   volid = %s\n"),
                              static_cast<const TCHAR*>(CStringize(droidCurrent.GetVolumeId() )));
                    _tprintf( TEXT("   objid = %s\n"),
                              static_cast<const TCHAR*>(CStringize(droidCurrent.GetObjId() )));

                    _tprintf( TEXT("Birth:\n") );
                    _tprintf( TEXT("   volid = %s\n"),
                              static_cast<const TCHAR*>(CStringize(droidBirth.GetVolumeId() )));
                    _tprintf( TEXT("   objid = %s\n"),
                              static_cast<const TCHAR*>(CStringize(droidBirth.GetObjId() )));

                }

                break;

            //  ---------------
            //  Set an ObjectID
            //  ---------------

            case TEXT('S'):

                {
                    HANDLE hFile;
                    CObjId objid;
                    IO_STATUS_BLOCK IoStatus;
                    TCHAR tszFile[ MAX_PATH + 1 ];

                    if( TEXT('R') == rgptszArgs[0][2] )
                    {
                        if( 2 > cArgs )
                        {
                            printf( "Parameter error.  Use -? for usage info\n" );
                            hr = E_FAIL;
                            goto Exit;
                        }
                        (*pcEaten)++;

                        MakeAbsolutePath( tszFile, rgptszArgs[1] );

                        status = TrkCreateFile( tszFile, FILE_READ_ATTRIBUTES,
                                                FILE_ATTRIBUTE_NORMAL,
                                                FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
                                                FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
                                                NULL,
                                                &hFile );
                        if (!NT_SUCCESS(status))
                        {
                            printf( "TrkCreateFile failed\n" );
                            hr = status;
                            __leave;
                        }
                        status = MakeObjIdReborn( hFile );
                        if( NT_SUCCESS(status) )
                            printf( "File is reborn\n" );
                        else
                            printf( "Failed to make reborn (%08x)\n", status );
                    }
                    else
                    {
                        TSZ2CLSID( rgptszArgs[1], (GUID*)&objid );

                        if( 3 > cArgs )
                        {
                            printf( "Parameter error.  Use -? for usage info\n" );
                            hr = E_FAIL;
                            goto Exit;
                        }
                        (*pcEaten)++;

                        MakeAbsolutePath( tszFile, rgptszArgs[2] );

                        status = TrkCreateFile( tszFile, FILE_READ_ATTRIBUTES,
                                                FILE_ATTRIBUTE_NORMAL,
                                                FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
                                                FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
                                                NULL,
                                                &hFile );
                        if (!NT_SUCCESS(status))
                        {
                            printf( "TrkCreateFile failed\n" );
                            hr = status;
                            __leave;
                        }

                        status = SetObjId( hFile, objid, CDomainRelativeObjId() );

                        if (!NT_SUCCESS(status))
                        {
                            printf( "FSCTL_SET_OBJECT_ID failed\n" );
                            hr = status;
                            __leave;
                        }
                        printf( "ID set ok\n" );
                    }

                }

                break;

            case TEXT('D'):
                {
                    if( TEXT('F') == rgptszArgs[0][2] )
                    {
                        TCHAR tszFile[ MAX_PATH + 1 ];
                        HANDLE hFile;
                        NTSTATUS status;
                        IO_STATUS_BLOCK IoStatus;

                        MakeAbsolutePath( tszFile, rgptszArgs[1] );

                        status = TrkCreateFile( tszFile, FILE_GENERIC_READ | FILE_GENERIC_WRITE,
                                                FILE_ATTRIBUTE_NORMAL,
                                                FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
                                                FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_NO_RECALL | FILE_SYNCHRONOUS_IO_NONALERT,
                                                NULL,
                                                &hFile );
                        if (!NT_SUCCESS(status))
                        {
                            printf( "TrkCreateFile failed\n" );
                            hr = status;
                            __leave;
                        }

                        status = NtFsControlFile(
                             hFile,
                             NULL,
                             NULL,
                             NULL,
                             &IoStatus,
                             FSCTL_DELETE_OBJECT_ID,
                             NULL,  // in buffer
                             0,     // in buffer size
                             NULL,  // Out buffer
                             0);    // Out buffer size

                        if (!NT_SUCCESS(status))
                        {
                            printf( "FSCTL_DELETE_OBJECT_ID failed\n" );
                            hr = status;
                            __leave;
                        }
                        printf( "Deleted ok\n" );

                    }

                    else if( TEXT('O') == rgptszArgs[0][2] )
                    {
                        // Get the OID in binary format
                        CObjId oid;
                        CDomainRelativeObjId droidBirth;
                        TSZ2CLSID( rgptszArgs[1], (GUID*)&oid );
                        BOOL fFound = FALSE;

                        for (int vol='a'-'a'; vol<'z'-'a'; vol++)
                        {
                            if( IsLocalObjectVolume(CVolumeDeviceName(vol)) )
                            {
                                status = FindLocalPath(vol, oid, &droidBirth, &tszUNCPath[2]);
                                if( STATUS_OBJECT_NAME_NOT_FOUND == status )
                                    continue;
                                if( !NT_SUCCESS(status) ) goto Exit;

                                tszUNCPath[0] = VolChar(vol);
                                tszUNCPath[1] = TEXT(':');

                                _tprintf( TEXT("Deleting object ID on %s\n"), tszUNCPath );

                                status = DelObjId( vol, oid );
                                if( !NT_SUCCESS(status) ) goto Exit;
                                printf( "Deleted ok\n" );

                                break;
                            }
                        }

                        if( fFound ) printf( "Not found\n" );
                    }
                    else
                        printf( "Bad parameter\n" );
                }   // case TEXT('D'):
                break;


        }   // switch

        hr = S_OK;

    }   // __try

    __except( BreakOnDebuggableException() )
    {
        hr = GetExceptionCode();
    }


Exit:

    if( FAILED(hr) )
        printf( "HR = %08X\n", hr );

    return SUCCEEDED(hr);

}






BOOL
DltAdminTemp( ULONG cArgs, TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    HRESULT hr = E_FAIL;
    RPC_STATUS  rpcstatus;
    RPC_TCHAR * ptszStringBinding;
    RPC_BINDING_HANDLE hBinding = NULL;
    BOOL fBound = FALSE;
    LONG iVol = 4;
    GUID volid = { /* 9f1534ee-ceab-4710-98b9-daaf048e3ad2 */
        0x9f1534ee,
        0xceab,
        0x4710,
        {0x98, 0xb9, 0xda, 0xaf, 0x04, 0x8e, 0x3a, 0xd2}
      };

    if( 1 <= cArgs && IsHelpArgument( rgptszArgs[0] ))
    {
        printf("\nOption  Refresh\n"
                " Purpose: Temp test placeholder\n"
                " Usage:   -temp\n" );
        return( TRUE );
    }


    rpcstatus = RpcStringBindingCompose( NULL, TEXT("ncalrpc"), NULL, TEXT("trkwks"),
                                         NULL, &ptszStringBinding);

    if( rpcstatus )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Failed RpcStringBindingCompose %lu"), rpcstatus ));
        hr = HRESULT_FROM_WIN32(rpcstatus);
        goto Exit;
    }

    rpcstatus = RpcBindingFromStringBinding( ptszStringBinding, &hBinding );
    RpcStringFree( &ptszStringBinding );

    if( rpcstatus )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Failed RpcBindingFromStringBinding") ));
        hr = HRESULT_FROM_WIN32(rpcstatus);
        goto Exit;
    }
    fBound = TRUE;


    __try
    {
        hr = LnkSetVolumeId( hBinding, iVol, volid );
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32( GetExceptionCode() );
    }

    if( FAILED(hr) )
    {
        _tprintf( TEXT("Failed call to service (%08x)\n"), hr );
        goto Exit;
    }


Exit:

    if( fBound )
        RpcBindingFree( &hBinding );

    return( TRUE );

}   // main()










CVolumeId
DisplayLogStatus( LONG iVol )
{
    NTSTATUS status = STATUS_SUCCESS;
    HANDLE hFile = NULL;
    TCHAR tszLog[ MAX_PATH + 1 ];

    ULONG     cbRead;
    LogHeader logheader;
    LogInfo   loginfo;
    VolumePersistentInfo volinfo;

    _tcscpy( tszLog, CVolumeDeviceName(iVol) );
    _tcscat( tszLog, s_tszLogFileName );

    status = TrkCreateFile( tszLog, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL,
                            FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                            FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, &hFile );
    if( !NT_SUCCESS(status) )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open %s"), tszLog ));
        TrkRaiseNtStatus(status);
    }

    if( !ReadFile( hFile, &logheader, sizeof(logheader), &cbRead, NULL )
        ||
        sizeof(logheader) != cbRead )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read log header") ));
        TrkRaiseLastError();
    }

    if( !ReadFile( hFile, &volinfo, sizeof(volinfo), &cbRead, NULL )
        ||
        sizeof(volinfo) != cbRead )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read volinfo") ));
        TrkRaiseLastError();
    }

    if( !ReadFile( hFile, &loginfo, sizeof(loginfo), &cbRead, NULL )
        ||
        sizeof(loginfo) != cbRead )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Couldn't read loginfo") ));
        TrkRaiseLastError();
    }

    _tprintf( TEXT("\nLog Header:\n") );
    _tprintf( TEXT("    guidSignature = \t%s\n"), static_cast<const TCHAR*>(CStringize(logheader.guidSignature)) );
    _tprintf( TEXT("    dwFormat = \t\t0x%x,0x%x\n"), logheader.dwFormat>>16, logheader.dwFormat&0xFFFF );
    _tprintf( TEXT("    ProperShutdown = \t%s\n"), (logheader.dwFlags & PROPER_SHUTDOWN) ? TEXT("True") : TEXT("False") );
    _tprintf( TEXT("    DownlevelDirtied = \t%s\n"), (logheader.dwFlags & DOWNLEVEL_DIRTIED) ? TEXT("True") : TEXT("False") );
    _tprintf( TEXT("    Expansion start = \t%d\n"), logheader.expand.ilogStart );
    _tprintf( TEXT("              end = \t%d\n"), logheader.expand.ilogEnd );
    _tprintf( TEXT("              cb = \t%d\n"), logheader.expand.cbFile );


    _tprintf( TEXT("\nLog Information:\n") );
    _tprintf( TEXT("    Start = \t\t%lu\n"), loginfo.ilogStart );
    _tprintf( TEXT("    End = \t\t%lu\n"), loginfo.ilogEnd );
    _tprintf( TEXT("    Write = \t\t%lu\n"), loginfo.ilogWrite );
    _tprintf( TEXT("    Read = \t\t%lu\n"), loginfo.ilogRead );
    _tprintf( TEXT("    Last = \t\t%lu\n"), loginfo.ilogLast );
    _tprintf( TEXT("    seqNext = \t\t%li\n"), loginfo.seqNext );
    _tprintf( TEXT("    seqLastRead = \t%li\n"), loginfo.seqLastRead );


    CVolumeId volidNTFS;
    status = QueryVolumeId( iVol, &volidNTFS );
    if( !NT_SUCCESS(status) )
    {
        TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get NTFS volume ID") ));
        TrkRaiseNtStatus(status);
    }

    _tprintf( TEXT("\nVolume Information:\n") );
    _tprintf( TEXT("    Machine = \t\t%s\n"), static_cast<const TCHAR*>(CStringize(volinfo.machine)) );
    _tprintf( TEXT("    VolId (log) = \t%s\n"), static_cast<const TCHAR*>(CStringize(volinfo.volid)) );
    _tprintf( TEXT("    VolId (NTFS) = \t%s\n"), static_cast<const TCHAR*>(CStringize(volidNTFS)) );
    _tprintf( TEXT("    Secret = \t\t%s\n"), static_cast<const TCHAR*>(CStringize(volinfo.secret)) );
    _tprintf( TEXT("    Last Refresh = \t%d\n"), volinfo.cftLastRefresh.LowDateTime() );
    _tprintf( TEXT("    Enter not-owned = \t%s\n"), volinfo.cftEnterNotOwned == CFILETIME(0)
                                                        ? TEXT("(N/A)")
                                                        : static_cast<const TCHAR*>(CStringize(volinfo.cftEnterNotOwned)) );
    _tprintf( TEXT("    Make OIDs reborn = \t%s\n"), volinfo.fDoMakeAllOidsReborn ? TEXT("True") : TEXT("False") );
    _tprintf( TEXT("    Not-Created = \t%s\n"), volinfo.fNotCreated ? TEXT("True") : TEXT("False") );

    if( NULL != hFile )
        NtClose( hFile );

    return( volinfo.volid );
}



void
DisplayDcStatus( const CVolumeId &volid )
{
    CRpcClientBinding rc;
    TRKSVR_SYNC_VOLUME SyncVolume;
    TRKSVR_MESSAGE_UNION Msg;
    CMachineId mcidLocal( MCID_LOCAL );
    HRESULT hr = S_OK;

    rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint, NO_AUTHENTICATION );

    printf( "\nDC Information:\n" );

    __try
    {
        Msg.MessageType = SYNC_VOLUMES;
        Msg.ptszMachineID = NULL;
        Msg.Priority = PRI_9;
        Msg.SyncVolumes.cVolumes = 1;
        Msg.SyncVolumes.pVolumes = &SyncVolume;
        SyncVolume.hr = S_OK;
        SyncVolume.SyncType = QUERY_VOLUME;
        SyncVolume.volume = volid;

        hr = LnkCallSvrMessage( rc, &Msg );
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32(GetExceptionCode());
    }

    if( FAILED(hr) )
    {
        printf( "    Couldn't get status from DC:  %08x\n", hr );

        if( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr )
            printf( "    Make sure you have the 0x1 bit set in the TestFlags registry value\n" );

        goto Exit;
    }

    if( TRK_S_VOLUME_NOT_FOUND == SyncVolume.hr )
    {
        printf( "    Volume is not in DC\n" );
    }
    else if( TRK_S_VOLUME_NOT_OWNED == SyncVolume.hr )
    {
        printf( "    Volume is not owned by this machine\n" );
    }
    else if( S_OK == SyncVolume.hr )
    {
        _tprintf( TEXT("    Sequence # = \t%li\n"), SyncVolume.seq );
        _tprintf( TEXT("    Last Refresh = \t%lu\n"), SyncVolume.ftLastRefresh.dwLowDateTime );
                  //static_cast<const TCHAR*>(CStringize(CFILETIME(SyncVolume.ftLastRefresh))) );
    }
    else
    {
        printf( "    Volume state couldn't get queried from DC:  %08x\n", hr );
    }

Exit:

    return;
}


void
DisplayOidInformation( LONG iVol )
{

    CObjId                  objid;
    CDomainRelativeObjId    droid;
    CObjIdEnumerator        oie;

    ULONG cFilesWithOid         = 0;
    ULONG cCrossVolumeBitSet    = 0;

    if(oie.Initialize(CVolumeDeviceName(iVol)) == TRUE)
    {
        if(oie.FindFirst(&objid, &droid))
        {
            do
            {
                cFilesWithOid++;

                if( droid.GetVolumeId().GetUserBitState() )
                    cCrossVolumeBitSet++;

            } while(oie.FindNext(&objid, &droid));
        }
    }

    printf( "\nObjectID Information\n" );
    printf( "    Files with ObjectIDs = \t\t%lu\n", cFilesWithOid );
    printf( "    Files with x-volume bit set = \t%lu\n", cCrossVolumeBitSet );

}



VolumeStatistics( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    NTSTATUS status = 0;
    TCHAR tszFile[ MAX_PATH + 1 ];
    TCHAR tszDir[ MAX_PATH + 1 ];
    TCHAR* ptcTmp = NULL;
    BOOL fSuccess = FALSE;
    LONG iVol = 0;

    *pcEaten = 0;

    if( 1 > cArgs || IsHelpArgument(rgptszArgs[0]) )
    {
        printf( "\nOption VolStat\n"
                  "   Purpose:  Get link tracking info about a volume\n"
                  "   Usage:    -volstat <drive letter>\n"
                  "   E.g.:     -volstat D:\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    if( TEXT('a') > rgptszArgs[0][0]
        &&
        TEXT('z') < rgptszArgs[0][0]
        &&
        TEXT('A') > rgptszArgs[0][0]
        &&
        TEXT('Z') < rgptszArgs[0][0]
        ||
        TEXT(':') != rgptszArgs[0][1] )
    {
        printf( "Parameter error.  Use -? for usage info\n" );
        return( FALSE );
    }

    iVol = (LONG)((ULONG_PTR)CharLower((LPTSTR)rgptszArgs[0][0]) - TEXT('a'));

    if( !IsLocalObjectVolume( iVol ))
    {
        _tprintf( TEXT("%c: isn't a local NTFS5 volume\n"), VolChar(iVol) );
        goto Exit;
    }

    __try
    {
        CVolumeId volid;

        EnablePrivilege( SE_RESTORE_NAME );

        volid = DisplayLogStatus(iVol);
        DisplayDcStatus( volid );
        DisplayOidInformation( iVol );

        fSuccess = TRUE;
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        printf( "Fatal error:  %08x\n", GetExceptionCode() );
    }


Exit:

    return( fSuccess );

}   // main()










VolumeIdSetOrGet( ULONG cArgs, TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    HRESULT hr = E_FAIL;
    NTSTATUS status = STATUS_SUCCESS;

    TCHAR tszFile[ MAX_PATH + 1 ];
    WCHAR wszFile[ MAX_PATH + 1 ];
    TCHAR tszUNCPath[ MAX_PATH + 1 ];
    WCHAR wszOID[ CCH_GUID_STRING + 1 ];
    ULONG cbInBuffer;
    TCHAR tszMachineName[ MAX_PATH + 1 ];
    LPCTSTR tszVolumePath = NULL;
    USHORT iVolume;

    OLECHAR oszOID[ CCH_GUID_STRING + 1 ];

    if( 1 == cArgs && IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption VolId\n"
                  "   Purpose: Set or get volume IDs\n"
                  "   Usage:   -volid [-s <drive>: {GUID} | -g <drive>:]\n"
                  "   Where:   '-s' means Set, and '-g' means Get\n"
                  "   E.g.:    -volid -g d:\n"
                  "            -volid -s d: {d2a2ac27-b89a-11d2-9335-00805ffe11b8}\n" );
                               // The volid in this example is actually the well-known invalid volid
        *pcEaten = 1;
        return( TRUE );
    }
    else
    if( 2 > cArgs
        ||
        TEXT('-') != rgptszArgs[0][0]
        &&
        TEXT('/') != rgptszArgs[0][0]
        ||
        TEXT(':') != rgptszArgs[1][1] )
    {
        printf( "Invalid parameter.  Use -? for help\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    *pcEaten = 2;
    __try
    {
        CVolumeId volid;

        TCHAR tcCommand = (TCHAR)CharUpper( (LPTSTR) rgptszArgs[0][1] );
        TCHAR tcDrive   = (TCHAR)CharUpper( (LPTSTR) rgptszArgs[1][0] );
        LONG iVol = tcDrive - TEXT('A');


        if( TEXT('G') == tcCommand )
        {
            OLECHAR *poszVolId;

            status = QueryVolumeId( iVol, &volid );
            if( FAILED(status) )
            {
                TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query for volume id") ));
                TrkRaiseNtStatus(status);
            }

            hr = StringFromCLSID( *(GUID*)&volid, &poszVolId );
            if( FAILED(hr) )
            {
                TrkLog(( TRKDBG_ERROR, TEXT("Failed StringFromClsid %08x"), hr ));
                TrkRaiseException( hr );
            }

            _tprintf( TEXT("VolID = %s\n"), poszVolId );
            CoTaskMemFree( poszVolId );

        }
        else if( TEXT('S') == tcCommand && 3 <= cArgs )
        {
            TSZ2CLSID( rgptszArgs[2], (GUID*)&volid );
            EnablePrivilege( SE_RESTORE_NAME );
            status = SetVolId( iVol, volid );
            if( FAILED(status) )
            {
                TrkLog(( TRKDBG_ERROR, TEXT("Couldn't set volume id") ));
                TrkRaiseNtStatus(status);
            }
        }
        else
        {
            printf( "Invalid parameter.  Use -? for help\n" );
            goto Exit;
        }

        hr = S_OK;
    }
    __except( BreakOnDebuggableException() )
    {
        hr = GetExceptionCode();
    }


Exit:

    if( FAILED(hr) )
        printf( "Failed: hr = %08x\n", hr );
    return( SUCCEEDED(hr) );

}   // main()









BOOL
DltAdminVolInfoFile( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    NTSTATUS status;
    HRESULT hr;
    HANDLE hFile = NULL;
    IO_STATUS_BLOCK Iosb;
    OLECHAR *poszVolId = NULL;

    BYTE rgb[ 2 * MAX_PATH ];
    PFILE_FS_VOLUME_INFORMATION pfile_fs_volume_information
        = reinterpret_cast<PFILE_FS_VOLUME_INFORMATION>(rgb);
    PFILE_FS_ATTRIBUTE_INFORMATION pfile_fs_attribute_information
        = reinterpret_cast<PFILE_FS_ATTRIBUTE_INFORMATION>(rgb);
    PFILE_FS_OBJECTID_INFORMATION pfile_fs_objectid_information
        = reinterpret_cast<PFILE_FS_OBJECTID_INFORMATION>(rgb);

    FILE_FS_SIZE_INFORMATION file_fs_size_information;
    FILE_FS_FULL_SIZE_INFORMATION file_fs_full_size_information;
    FILE_FS_DEVICE_INFORMATION file_fs_device_information;

    TCHAR tszFileSystemAttributes[ 2 * MAX_PATH ];
    DWORD dwFileSystemAttributeMask;
    TCHAR *ptszDeviceType = NULL;

    if( 0 == cArgs )
    {
        printf( "Missing parameter: a file/directory name must be specified\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    if( IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption VolInfoFile\n"
                  "   Purpose: Get volume information, given a file or directory name\n"
                  "   Usage:   -volinfofile <file or directory>\n"
                  "   E.g.     -volinfofile C:\\foo.doc\n"
                  "            -volinfofile \\\\scratch\\scratch\\jdoe\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    __try
    {
        *pcEaten = 1;

        TCHAR tszFileTime[ 80 ];

        status = TrkCreateFile(
                    rgptszArgs[0],
                    FILE_READ_ATTRIBUTES,
                    FILE_ATTRIBUTE_NORMAL,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    FILE_OPEN,
                    FILE_SYNCHRONOUS_IO_NONALERT,
                    NULL,
                    &hFile );
        if( !NT_SUCCESS(status) )
        {
            TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open file \"%s\" (%08x)"), rgptszArgs[1], status ));
            TrkRaiseNtStatus(status);
        }

        status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                               pfile_fs_volume_information,
                                               sizeof(rgb),
                                               FileFsVolumeInformation );
        if( !NT_SUCCESS(status) )
        {
            TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query volume information (%08x)"), status ));
            TrkRaiseNtStatus(status);
        }

        pfile_fs_volume_information->VolumeLabel[ pfile_fs_volume_information->VolumeLabelLength/sizeof(WCHAR) ]
            = L'\0';

        static_cast<CFILETIME>(pfile_fs_volume_information->VolumeCreationTime)
                              .Stringize( ELEMENTS(tszFileTime), tszFileTime );

        _tprintf( TEXT("\n")
                  TEXT("Volume creation time:\t%08x:%08x (%s)\n")
                  TEXT("Volume serial number:\t%08x\n")
                  TEXT("Supports objects:\t%s\n")
                  TEXT("Volume label:\t\t%s\n"),
                  pfile_fs_volume_information->VolumeCreationTime.HighPart,
                  pfile_fs_volume_information->VolumeCreationTime.LowPart,
                  tszFileTime,
                  pfile_fs_volume_information->VolumeSerialNumber,
                  pfile_fs_volume_information->SupportsObjects ? TEXT("True") : TEXT("False"),
                  pfile_fs_volume_information->VolumeLabel );

        status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                               pfile_fs_attribute_information,
                                               sizeof(rgb),
                                               FileFsAttributeInformation );
        if( !NT_SUCCESS(status) )
        {
            TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query attribute information (%08x)"), status ));
            TrkRaiseNtStatus(status);
        }

        pfile_fs_attribute_information->FileSystemName[ pfile_fs_attribute_information->FileSystemNameLength/sizeof(WCHAR) ]
            = L'\0';

        _tcscpy( tszFileSystemAttributes, TEXT("") );

        dwFileSystemAttributeMask = FILE_CASE_SENSITIVE_SEARCH
                                    | FILE_CASE_PRESERVED_NAMES
                                    | FILE_UNICODE_ON_DISK
                                    | FILE_PERSISTENT_ACLS
                                    | FILE_FILE_COMPRESSION
                                    | FILE_VOLUME_QUOTAS
                                    | FILE_SUPPORTS_SPARSE_FILES
                                    | FILE_SUPPORTS_REPARSE_POINTS
                                    | FILE_SUPPORTS_REMOTE_STORAGE
                                    | FILE_VOLUME_IS_COMPRESSED
                                    | FILE_SUPPORTS_OBJECT_IDS
                                    | FILE_SUPPORTS_ENCRYPTION;

        if( FILE_CASE_SENSITIVE_SEARCH & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tCase sensitive search\n"));
        if( FILE_CASE_PRESERVED_NAMES & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tCase preserved names\n"));
        if( FILE_UNICODE_ON_DISK & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tUnicode on disk\n"));
        if( FILE_PERSISTENT_ACLS & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tPersistent ACLs\n"));
        if( FILE_FILE_COMPRESSION & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tFile compression\n"));
        if( FILE_VOLUME_QUOTAS & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tVolume quotas\n"));
        if( FILE_SUPPORTS_SPARSE_FILES & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports sparse files\n"));
        if( FILE_SUPPORTS_REPARSE_POINTS & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports reparse points\n"));
        if( FILE_SUPPORTS_REMOTE_STORAGE & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports remote storage\n"));
        if( FILE_VOLUME_IS_COMPRESSED & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tVolume is compressed\n"));
        if( FILE_SUPPORTS_OBJECT_IDS & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports object IDs\n"));
        if( FILE_SUPPORTS_ENCRYPTION & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports encryption\n"));
        if( FILE_NAMED_STREAMS & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\tSupports named streams\n"));
        if( !dwFileSystemAttributeMask & pfile_fs_attribute_information->FileSystemAttributes )
            _tcscat( tszFileSystemAttributes, TEXT("\t\t\t(Unknown bit)"));


        _tprintf( TEXT("File system attributes:\t%08x\n%s")
                  TEXT("Max component name:\t%d\n")
                  TEXT("File system name\t%s\n"),
                  pfile_fs_attribute_information->FileSystemAttributes, tszFileSystemAttributes,
                  pfile_fs_attribute_information->MaximumComponentNameLength,
                  pfile_fs_attribute_information->FileSystemName );

        status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                               pfile_fs_objectid_information,
                                               sizeof(rgb),
                                               FileFsObjectIdInformation );
        if( NT_SUCCESS(status) )
        {
            hr = StringFromCLSID( *(GUID*)pfile_fs_objectid_information->ObjectId, &poszVolId );
            if( FAILED(hr) )
            {
                TrkLog(( TRKDBG_ERROR, TEXT("Failed StringFromClsid %08x"), hr ));
                TrkRaiseException( hr );
            }

            _tprintf( TEXT("Volume Id:\t\t%s\n"), poszVolId );
            CoTaskMemFree( poszVolId );
        }
        else if( status != STATUS_INVALID_PARAMETER && status != STATUS_OBJECT_NAME_NOT_FOUND )
        {
            TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query objectid information (%08x)"), status ));
            TrkRaiseNtStatus(status);
        }

        status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                               &file_fs_full_size_information,
                                               sizeof(file_fs_full_size_information),
                                               FileFsFullSizeInformation );
        if( !NT_SUCCESS(status) )
        {
            status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                                   &file_fs_size_information,
                                                   sizeof(file_fs_size_information),
                                                   FileFsSizeInformation );
            if( !NT_SUCCESS(status) )
            {
                TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query full size info or size info (%08x)"), status ));
                TrkRaiseNtStatus( status );
            }

            double TotalAllocInMB = file_fs_size_information.TotalAllocationUnits.QuadPart
                                    *
                                    file_fs_size_information.SectorsPerAllocationUnit
                                    *
                                    file_fs_size_information.BytesPerSector
                                    /
                                    1000000.0;

            _tprintf( TEXT("Total allocation units:\t%I64u (%.2fMB)\n")
                      TEXT("Available alloc:\t%I64u units\n")
                      TEXT("Sectors per alloc unit:\t%d\n")
                      TEXT("Bytes per sector:\t%d\n"),
                      file_fs_size_information.TotalAllocationUnits.QuadPart,
                      TotalAllocInMB,
                      file_fs_size_information.AvailableAllocationUnits.QuadPart,
                      file_fs_size_information.SectorsPerAllocationUnit,
                      file_fs_size_information.BytesPerSector );

        }
        else
        {
            double TotalAllocInMB = file_fs_full_size_information.TotalAllocationUnits.QuadPart
                                    *
                                    file_fs_full_size_information.SectorsPerAllocationUnit
                                    *
                                    file_fs_full_size_information.BytesPerSector
                                    /
                                    1000000.0;

            double CallerAvailAllocInMB
                                  = file_fs_full_size_information.CallerAvailableAllocationUnits.QuadPart
                                    *
                                    file_fs_full_size_information.SectorsPerAllocationUnit
                                    *
                                    file_fs_full_size_information.BytesPerSector
                                    /
                                    1000000.0;

            double ActualAvailAllocInMB
                                  = file_fs_full_size_information.ActualAvailableAllocationUnits.QuadPart
                                    *
                                    file_fs_full_size_information.SectorsPerAllocationUnit
                                    *
                                    file_fs_full_size_information.BytesPerSector
                                    /
                                    1000000.0;

            _tprintf( TEXT("Total allocation units:\t%I64u (%.2fMB)\n")
                      TEXT("Caller avail alloc:\t%I64u units (%.2fMB)\n")
                      TEXT("Actual avail alloc:\t%I64u units (%.2fMB)\n")
                      TEXT("Sectors per alloc unit:\t%d\n")
                      TEXT("Bytes per sector:\t%d\n"),
                      file_fs_full_size_information.TotalAllocationUnits.QuadPart,
                      TotalAllocInMB,
                      file_fs_full_size_information.CallerAvailableAllocationUnits.QuadPart,
                      CallerAvailAllocInMB,
                      file_fs_full_size_information.ActualAvailableAllocationUnits.QuadPart,
                      ActualAvailAllocInMB,
                      file_fs_full_size_information.SectorsPerAllocationUnit,
                      file_fs_full_size_information.BytesPerSector );
        }

        status = NtQueryVolumeInformationFile( hFile, &Iosb,
                                               &file_fs_device_information,
                                               sizeof(file_fs_device_information),
                                               FileFsDeviceInformation );
        if( !NT_SUCCESS(status) )
        {
            TrkLog(( TRKDBG_ERROR, TEXT("Couldn't query file fs device information (%08x)"), status ));
            TrkRaiseNtStatus(status);
        }

        switch( file_fs_device_information.DeviceType )
        {
        case FILE_DEVICE_NETWORK:
            ptszDeviceType = L"Network"; break;
        case FILE_DEVICE_NETWORK_FILE_SYSTEM:
            ptszDeviceType = L"Network file system"; break;
        case FILE_DEVICE_CD_ROM:
            ptszDeviceType = L"CDROM"; break;
        case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
            ptszDeviceType = L"CDROM file system"; break;
        case FILE_DEVICE_VIRTUAL_DISK:
            ptszDeviceType = L"Virtual disk"; break;
        case FILE_DEVICE_DISK:
            ptszDeviceType = file_fs_device_information.Characteristics & FILE_REMOVABLE_MEDIA
                ? L"Removable disk" : L"Fixed disk";
            break;
        case FILE_DEVICE_DISK_FILE_SYSTEM:
            ptszDeviceType = file_fs_device_information.Characteristics & FILE_REMOVABLE_MEDIA
                ? L"Removable disk file system" : L"Fixed disk file system";
            break;
        default:
            ptszDeviceType = L"Unknown";
        }

        _tprintf( TEXT("Device Type:\t\t%s%s\n"),
                  ptszDeviceType,
                  (file_fs_device_information.Characteristics & FILE_REMOTE_DEVICE)
                      ? TEXT(" (remote)")
                      : TEXT("")
                  );


        hr = S_OK;

    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = GetExceptionCode();
    }

    if( NULL != hFile )
        NtClose( hFile );


    if( FAILED(hr) )
        printf( "Failed: hr = %08x\n", hr );
    return SUCCEEDED(hr);
}



BOOL
DeleteIdFromVolumeTable( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    CVolumeId volid;
    CStringize stringize;
    CRpcClientBinding rc;
    TRKSVR_SYNC_VOLUME SyncVolume;
    TRKSVR_MESSAGE_UNION Msg;
    CMachineId mcidLocal( MCID_LOCAL );
    HRESULT hr = S_OK;

    if( 0 == cArgs )
    {
        printf( "Missing parameter: a volume ID name must be specified\n"
                "(in \"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" form)\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    _tprintf( TEXT("Deleting volume %s from DC volume table\n"), rgptszArgs[0] );

    if( IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption DelDcVolId\n"
                  "   Purpose: Delete a volume ID from the DC volume table\n"
                  "   Usage:   -deldcvolid <stringized volume ID>\n"
                  "   E.g.     -deldcvolid {56730825-3ddc-11d2-a168-00805ffe11b8}\n"
                  "   Note:    The volume ID must be owned by this machine.\n"
                  "            Also, the services\\trkwks\\parameters\\configuration\\trkflags\n"
                  "            reg value must have the 0x1 bit set.\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    *pcEaten = 1;

    // Convert the volid string to a volid

    stringize.Use( rgptszArgs[0] );
    volid = stringize;

    if( CVolumeId() == volid )
    {
        _tprintf( TEXT("Error: Invalid volume ID\n") );
        return( FALSE );
    }

    // Send the delete request

    rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint, NO_AUTHENTICATION );
    __try
    {
        Msg.MessageType = SYNC_VOLUMES;
        Msg.ptszMachineID = NULL;
        Msg.Priority = PRI_9;
        Msg.SyncVolumes.cVolumes = 1;
        Msg.SyncVolumes.pVolumes = &SyncVolume;
        SyncVolume.hr = S_OK;
        SyncVolume.SyncType = DELETE_VOLUME;
        SyncVolume.volume = volid;

        hr = LnkCallSvrMessage( rc, &Msg );
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }

    if( SUCCEEDED(hr) )
        hr = SyncVolume.hr;

    if( FAILED(hr) )
        _tprintf( TEXT("Error: %08x\n"), hr );
    else if( S_OK != hr )
        _tprintf( TEXT("Success code: %08x\n"), hr );

    if( FAILED(hr) )
        printf( "Failed: hr = %08x\n", hr );
    return( SUCCEEDED(hr) );

}


BOOL
DeleteIdFromMoveTable( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    CDomainRelativeObjId droid;
    CStringize stringize;
    CRpcClientBinding rc;
    TRKSVR_MESSAGE_UNION Msg;
    CMachineId mcidLocal( MCID_LOCAL );
    HRESULT hr = S_OK;

    if( 0 == cArgs )
    {
        printf( "Missing parameter: a birth ID name must be specified\n"
                "(in \"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" form)\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    _tprintf( TEXT("Deleting file %s from DC move table\n"), rgptszArgs[0] );

    if( IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption DelDcMoveId\n"
                  "   Purpose: Delete an entry from the DC move table\n"
                  "   Usage:   -deldcmoveid <stringized GUIDs of birth ID>\n"
                  "   E.g.     -deldcmoveid {xxx...xxx}{xxx...xxx}\n"
                  "   Where:   a stringized GUID is e.g. \"{56730825-3ddc-11d2-a168-00805ffe11b8}\"\n"
                  "   Note:    The birth ID must be owned by this machine.\n"
                  "            Also, the services\\trkwks\\parameters\\configuration\\trkflags\n"
                  "            reg value must have the 0x1 bit set.\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    *pcEaten = 1;

    stringize.Use( rgptszArgs[0] );
    droid = stringize;

    if( CDomainRelativeObjId() == droid )
    {
        _tprintf( TEXT("Error: Invalid birth ID\n") );
        return( FALSE );
    }


    rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint, NO_AUTHENTICATION );
    __try
    {
        CVolumeId volidDummy;
        Msg.MessageType = DELETE_NOTIFY;
        Msg.ptszMachineID = NULL;
        Msg.Priority = PRI_5;
        Msg.Delete.cVolumes = 0;
        Msg.Delete.pVolumes = &volidDummy;

        Msg.Delete.adroidBirth = &droid;
        Msg.Delete.cdroidBirth = 1;

        LnkCallSvrMessage(rc, &Msg);
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32(GetExceptionCode());
    }


    if( FAILED(hr) )
        _tprintf( TEXT("Error: %08x\n"), hr );
    else if( S_OK != hr )
        _tprintf( TEXT("Success code: %x\n"), hr );

    return( SUCCEEDED(hr) );
}





BOOL
DltAdminLookupVolId( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    CVolumeId volid;
    CStringize stringize;
    CRpcClientBinding rc;
    TRKSVR_SYNC_VOLUME SyncVolume;
    TRKSVR_MESSAGE_UNION Msg;
    CMachineId mcidLocal( MCID_LOCAL );
    HRESULT hr = S_OK;

    if( 0 == cArgs )
    {
        printf( "Missing parameter: a volume ID name must be specified\n"
                "(in \"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" form)\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    _tprintf( TEXT("Searching for volume %s in DC volume table\n"), rgptszArgs[0] );

    if( IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption LookupVolId\n"
                  "   Purpose: Look up a volume ID from the DC volume table\n"
                  "   Usage:   -lookupvolid <stringized volume ID>\n"
                  "   E.g.     -lookupvolid {56730825-3ddc-11d2-a168-00805ffe11b8}\n"
                  "   Note:    The services\\trkwks\\parameters\\configuration\\trkflags\n"
                  "            reg value must have the 0x1 bit set before trkwks is started.\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    *pcEaten = 1;

    // Convert the volid string to a volid

    stringize.Use( rgptszArgs[0] );
    volid = stringize;

    if( CVolumeId() == volid )
    {
        _tprintf( TEXT("Error: Invalid volume ID\n") );
        return( FALSE );
    }

    // Send the delete request

    rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint, NO_AUTHENTICATION );
    __try
    {
        Msg.MessageType = SYNC_VOLUMES;
        Msg.ptszMachineID = NULL;
        Msg.Priority = PRI_9;
        Msg.SyncVolumes.cVolumes = 1;
        Msg.SyncVolumes.pVolumes = &SyncVolume;
        SyncVolume.hr = S_OK;
        SyncVolume.SyncType = FIND_VOLUME;
        SyncVolume.volume = volid;

        hr = LnkCallSvrMessage( rc, &Msg );
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }

    if( SUCCEEDED(hr) )
        hr = SyncVolume.hr;

    if( FAILED(hr) )
        _tprintf( TEXT("Error: %08x\n"), hr );
    else
    {
        if( S_OK != hr )
            _tprintf( TEXT("Success code is %08x\n"), hr );

        _tprintf( TEXT("Machine = \"%s\"\n"), static_cast<const TCHAR*>(CStringize(SyncVolume.machine)) );
    }

    if( FAILED(hr) )
        printf( "Failed: hr = %08x\n", hr );
    return( SUCCEEDED(hr) );

}






BOOL
DltAdminLookupDroid( ULONG cArgs, const TCHAR * const rgptszArgs[], ULONG *pcEaten )
{
    CVolumeId volid;
    CStringize stringize;
    CRpcClientBinding rc;
    TRK_FILE_TRACKING_INFORMATION FileTrackingInformation;
    TRKSVR_MESSAGE_UNION Msg;
    CDomainRelativeObjId droid;
    CMachineId mcidLocal( MCID_LOCAL );
    HRESULT hr = S_OK;

    if( 0 == cArgs )
    {
        printf( "Missing parameter: a DROID must be specified\n"
                "(in \"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\" form)\n" );
        *pcEaten = 0;
        return( FALSE );
    }

    _tprintf( TEXT("Searching for move ID %s in DC volume table\n"), rgptszArgs[0] );

    if( IsHelpArgument( rgptszArgs[0] ))
    {
        printf( "\nOption LookupDroid\n"
                  "   Purpose: Look up a DROID from the DC move table\n"
                  "   Usage:   -lookupdroid <stringized DROIID>\n"
                  "   E.g.     -lookupdroid {f8b534f0-b65b-11d2-8fd8-0008c709d19e}{0ed45deb-03ed-11d3-b766-00805ffe11b8}\n"
                  "   Note:    You must be running as an administrator\n" );
        *pcEaten = 1;
        return( TRUE );
    }

    *pcEaten = 1;

    stringize.Use( rgptszArgs[0] );
    droid = stringize;

    if( CDomainRelativeObjId() == droid )
    {
        _tprintf( TEXT("Error: Invalid birth ID\n") );
        return( FALSE );
    }


    rc.RcInitialize( mcidLocal, s_tszTrkWksLocalRpcProtocol, s_tszTrkWksLocalRpcEndPoint, NO_AUTHENTICATION );
    __try
    {
        memset( &FileTrackingInformation, 0, sizeof(FileTrackingInformation) );
        FileTrackingInformation.droidLast = droid;

        Msg.MessageType = SEARCH;
        Msg.ptszMachineID = NULL;
        Msg.Priority = PRI_5;
        Msg.Search.cSearch = 1;
        Msg.Search.pSearches = &FileTrackingInformation;

        LnkCallSvrMessage(rc, &Msg);
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        hr = HRESULT_FROM_WIN32(GetExceptionCode());
    }


    if( SUCCEEDED(hr) )
        hr = FileTrackingInformation.hr;

    if( FAILED(hr) )
        _tprintf( TEXT("Error: %08x\n"), hr );
    else
    {
        if( S_OK != hr )
            _tprintf( TEXT("Success code is %08x\n"), hr );

        _tprintf( TEXT("Machine = \"%s\"\n"), static_cast<const TCHAR*>(CStringize(FileTrackingInformation.mcidLast)) );
    }

    return( TRUE );
}






EXTERN_C void __cdecl _tmain( int cArgs, TCHAR *prgtszArg[])
{
    HRESULT hr = S_OK;
    NTSTATUS status = STATUS_SUCCESS;
    int iArg = 0;
    int iError = 0;

    OLECHAR oszOID[ CCH_GUID_STRING + 1 ];

    TrkDebugCreate( TRK_DBG_FLAGS_WRITE_TO_DBG, "DltAdmin" );
    hr = CoInitialize( NULL );
    if (FAILED(hr))
    {
        _tprintf( TEXT("Unable to CoInitialize( NULL )-- aborting. (0x%08x)\n"), 
                  hr );
        return;
    }

    TCHAR tszStringizedTime[ 80 ];

    __try
    {
        // Skip over the executable name
        iArg++;
        cArgs--;

        if( 0 == cArgs )
        {
            Usage();
            exit(1);
        }

        for( ; iArg <= cArgs; cArgs--, iArg++ )
        {
            ULONG cEaten = 0;

            if( TEXT('-') != prgtszArg[iArg][0]
                &&
                TEXT('/') != prgtszArg[iArg][0] )
            {
                _tprintf( TEXT("Invalid option, ignoring: %s\n"), prgtszArg[iArg] );
                iError = max( iError, 1 );
                continue;
            }

            if( !_tcsicmp( TEXT("deldcvolid"), &prgtszArg[iArg][1] ) )
            {
                iArg++;
                cArgs--;
                if( !DeleteIdFromVolumeTable( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );

                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("deldcmoveid"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DeleteIdFromMoveTable( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("lookupvolid"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminLookupVolId( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("lookupdroid"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminLookupDroid( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("volinfofile"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminVolInfoFile( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("cleanvol"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminCleanVol( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("svrstat"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminSvrStat( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("volstat"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !VolumeStatistics( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("volid"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !VolumeIdSetOrGet( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("lockvol"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminLockVol( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("fileoid"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminFileOid( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("enumoids"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminEnumOids( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("oidsnap"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminOidSnap( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("link"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminLink( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("loadlib"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminProcessAction( LOAD_LIBRARY, cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("freelib"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminProcessAction( FREE_LIBRARY, cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("debugbreak"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminProcessAction( DEBUG_BREAK, cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("createprocess"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminProcessAction( CREATE_PROCESS, cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("config"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminConfig( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("refresh"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminRefresh( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("setvolseq"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminSetVolumeSeqNumber( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("setdroidseq"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminSetDroidSeqNumber( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("backupread"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminBackupRead( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("backupwrite"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;

                if( !DltAdminBackupWrite( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( !_tcsicmp( TEXT("sleep"), &prgtszArg[iArg][1] ))
            {
                iArg++;
                cArgs--;
                Sleep( 1000 );
            }
            else if( !_tcsicmp( TEXT("temp"), &prgtszArg[iArg][1] ))
            {
                if( !DltAdminTemp( cArgs, &prgtszArg[iArg], &cEaten ))
                    iError = max( iError, 2 );
                iArg += cEaten;
                cArgs -= cEaten;
            }
            else if( TEXT('?') == prgtszArg[iArg][1] )
            {
                Usage();
                exit( 1 );
            }
            else
            {
                _tprintf( TEXT("Invalid option, ignoring: %s\n"), prgtszArg[iArg] );
                iError = max( iError, 1 );
                continue;
            }
        }
    }
    __except( BreakOnDebuggableException() )
    {
        hr = GetExceptionCode();
        iError = max( iError, 2 );
    }

    if( FAILED(hr) )
        printf( "HR = %08X\n", hr );

    CoUninitialize();

//    return( iError );

}   // main()