Tuesday, July 14, 2020

Old UA Migration SQL - basis for an event logger DB

USE [master]
GO
/****** Object:  Database [UAMigration]    Script Date: 7/14/2020 3:36:06 PM ******/
CREATE DATABASE [UAMigration]
 CONTAINMENT = NONE
 ON  PRIMARY
( NAME = N'UAMigration_Data', FILENAME = N'c:\program files\microsoft sql server\mssql15.mssqlserver\mssql\data\UAMigration_Data.mdf' , SIZE = 10240KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
 LOG ON
( NAME = N'UAMigration_Log', FILENAME = N'c:\program files\microsoft sql server\mssql15.mssqlserver\mssql\data\UAMigration_Log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
 WITH CATALOG_COLLATION = DATABASE_DEFAULT
GO
ALTER DATABASE [UAMigration] SET COMPATIBILITY_LEVEL = 150
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [UAMigration].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [UAMigration] SET ANSI_NULL_DEFAULT OFF
GO
ALTER DATABASE [UAMigration] SET ANSI_NULLS OFF
GO
ALTER DATABASE [UAMigration] SET ANSI_PADDING OFF
GO
ALTER DATABASE [UAMigration] SET ANSI_WARNINGS OFF
GO
ALTER DATABASE [UAMigration] SET ARITHABORT OFF
GO
ALTER DATABASE [UAMigration] SET AUTO_CLOSE OFF
GO
ALTER DATABASE [UAMigration] SET AUTO_SHRINK OFF
GO
ALTER DATABASE [UAMigration] SET AUTO_UPDATE_STATISTICS ON
GO
ALTER DATABASE [UAMigration] SET CURSOR_CLOSE_ON_COMMIT OFF
GO
ALTER DATABASE [UAMigration] SET CURSOR_DEFAULT  GLOBAL
GO
ALTER DATABASE [UAMigration] SET CONCAT_NULL_YIELDS_NULL OFF
GO
ALTER DATABASE [UAMigration] SET NUMERIC_ROUNDABORT OFF
GO
ALTER DATABASE [UAMigration] SET QUOTED_IDENTIFIER OFF
GO
ALTER DATABASE [UAMigration] SET RECURSIVE_TRIGGERS OFF
GO
ALTER DATABASE [UAMigration] SET  ENABLE_BROKER
GO
ALTER DATABASE [UAMigration] SET AUTO_UPDATE_STATISTICS_ASYNC OFF
GO
ALTER DATABASE [UAMigration] SET DATE_CORRELATION_OPTIMIZATION OFF
GO
ALTER DATABASE [UAMigration] SET TRUSTWORTHY OFF
GO
ALTER DATABASE [UAMigration] SET ALLOW_SNAPSHOT_ISOLATION OFF
GO
ALTER DATABASE [UAMigration] SET PARAMETERIZATION SIMPLE
GO
ALTER DATABASE [UAMigration] SET READ_COMMITTED_SNAPSHOT OFF
GO
ALTER DATABASE [UAMigration] SET HONOR_BROKER_PRIORITY OFF
GO
ALTER DATABASE [UAMigration] SET RECOVERY FULL
GO
ALTER DATABASE [UAMigration] SET  MULTI_USER
GO
ALTER DATABASE [UAMigration] SET PAGE_VERIFY CHECKSUM 
GO
ALTER DATABASE [UAMigration] SET DB_CHAINING OFF
GO
ALTER DATABASE [UAMigration] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF )
GO
ALTER DATABASE [UAMigration] SET TARGET_RECOVERY_TIME = 60 SECONDS
GO
ALTER DATABASE [UAMigration] SET DELAYED_DURABILITY = DISABLED
GO
EXEC sys.sp_db_vardecimal_storage_format N'UAMigration', N'ON'
GO
ALTER DATABASE [UAMigration] SET QUERY_STORE = OFF
GO
USE [UAMigration]
GO
/****** Object:  User [NT AUTHORITY\NETWORK SERVICE]    Script Date: 7/14/2020 3:36:07 PM ******/
CREATE USER [NT AUTHORITY\NETWORK SERVICE] FOR LOGIN [NT AUTHORITY\NETWORK SERVICE] WITH DEFAULT_SCHEMA=[dbo]
GO
/****** Object:  UserDefinedFunction [dbo].[fn_CheckMaxDayInactivity]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION  [dbo].[fn_CheckMaxDayInactivity]
(
@MaxDayInactivity int,
@LoginTime DateTime
)
RETURNS  bit
AS
BEGIN
DECLARE @RetValue bit


IF @MaxDayInactivity IS NULL
BEGIN
SET @RetValue = 1
END
ELSE
BEGIN
IF @LoginTime IS NULL
BEGIN
SET @RetValue = 0
END
ELSE
BEGIN
IF @MaxDayInactivity - DATEDIFF(dd,@LoginTime,GETDATE()) > 0
SET @RetValue = 1
ELSE
SET @RetValue = 0
END
END

RETURN @RetValue
END
GO
/****** Object:  Table [dbo].[Common_ErrorLog]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Common_ErrorLog](
[ErrorLogID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[ErrorTime] [datetime] NOT NULL,
[UserName] [sysname] NOT NULL,
[ErrorNumber] [int] NOT NULL,
[ErrorSeverity] [int] NULL,
[ErrorState] [int] NULL,
[ErrorProcedure] [nvarchar](126) NULL,
[ErrorLine] [int] NULL,
[ErrorMessage] [nvarchar](max) NOT NULL,
[ServerName] [varchar](50) NULL,
[ErrorAdditionalInfo] [nvarchar](max) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Migration_Events]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Migration_Events](
[ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[Name] [varchar](256) NULL,
[Description] [varchar](max) NULL,
[EventTypeID] [tinyint] NULL,
[CreateTimeUTC] [datetime] NULL,
[CreateTime]  AS (dateadd(hour,datediff(hour,getutcdate(),getdate()),[CreateTimeUTC]))
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Migration_EventsHistory]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Migration_EventsHistory](
[ID] [bigint] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[Migration_EventID] [int] NULL,
[Migration_SessionID] [int] NULL,
[Migration_EventSourceID] [tinyint] NULL,
[Migration_EventStepID] [tinyint] NULL,
[CreateTimeUTC] [datetime] NULL,
[CreateTime]  AS (dateadd(hour,datediff(hour,getutcdate(),getdate()),[CreateTimeUTC]))
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Migration_Steps]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Migration_Steps](
[ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[Name] [varchar](50) NULL,
[Description] [varchar](256) NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Common_ErrorLog] ADD  CONSTRAINT [DF__Common_Er__Error__2A4B4B5E]  DEFAULT (getdate()) FOR [ErrorTime]
GO
ALTER TABLE [dbo].[Migration_Events] ADD  CONSTRAINT [DF__Migration__Creat__164452B1]  DEFAULT (getutcdate()) FOR [CreateTimeUTC]
GO
ALTER TABLE [dbo].[Migration_EventsHistory] ADD  CONSTRAINT [DF__Migration__Creat__108B795B]  DEFAULT (getutcdate()) FOR [CreateTimeUTC]
GO
/****** Object:  StoredProcedure [dbo].[sp_Common_LogError]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


-- uspLogError logs error information in the ErrorLog table about the
-- error that caused execution to jump to the CATCH block of a
-- TRY...CATCH construct. This should be executed from within the scope
-- of a CATCH block otherwise it will return without inserting error
-- information.
CREATE PROCEDURE [dbo].[sp_Common_LogError]
@Retry INT = 0 OUTPUT,
@MaxRetries int = 3 OUTPUT,
    @ErrorLogID [int] = 0 OUTPUT,-- contains the ErrorLogID of the row inserted
@ErrorAdditionalInfo nvarchar(MAX) = NULL
AS
-- by uspLogError in the ErrorLog table
BEGIN
    SET NOCOUNT ON;

DECLARE @ErrorMessage NVARCHAR(MAX);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    -- Output parameter value of 0 indicates that error
    -- information was not logged
    SET @ErrorLogID = 0;

SET @Retry = @Retry + 1

SET @MaxRetries = 10

/*
    -- Return if there is no error information to log
    IF ERROR_NUMBER() IS NULL
RETURN;
*/

    BEGIN TRY

        -- Return if inside an uncommittable transaction.
        -- Data insertion/modification is not allowed when
        -- a transaction is in an uncommittable state.
--        IF XACT_STATE() = -1
        IF XACT_STATE() <> 0
        BEGIN
ROLLBACK TRANSACTION

/*
            PRINT 'Cannot log error since the current transaction is in an uncommittable state. '
                + 'Rollback the transaction before executing uspLogError in order to successfully log error information.';
            RETURN;
*/
        END

-- Return if there is no error information to log
IF ERROR_NUMBER() IS NULL
RETURN;

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()


        INSERT [dbo].[Common_ErrorLog]
(
            [UserName],
            [ErrorNumber],
            [ErrorSeverity],
            [ErrorState],
            [ErrorProcedure],
            [ErrorLine],
            [ErrorMessage],
[ErrorAdditionalInfo],
[ServerName]
)
        VALUES
(
            CONVERT(sysname, CURRENT_USER),
            ERROR_NUMBER(),
            @ErrorSeverity,
            @ErrorState,
            ERROR_PROCEDURE(),
            ERROR_LINE(),
            @ErrorMessage,
@ErrorAdditionalInfo,
HOST_NAME ()
);

        -- Pass back the ErrorLogID of the row inserted
        SET @ErrorLogID = SCOPE_IDENTITY()

    END TRY

    BEGIN CATCH
        PRINT 'An error occurred in stored procedure uspLogError: ';
        EXECUTE [dbo].[sp_Common_PrintError];
  --      RETURN -1;
    END CATCH

-- SELECT 'Retry = ' + CONVERT(varchar,@Retry) + ', MaxNumberRetries = ' + CONVERT(varchar,@MaxRetries)

/* Error Number:
1222 - Lock timeout
1205 - Deadlock
3960 - Update Conflict
*/

IF ERROR_NUMBER() IN (1222,1205,3960)
BEGIN

IF @Retry <= @MaxRetries
-- We will try it again few times
WAITFOR DELAY '00:00:02'
ELSE
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END
ELSE
BEGIN
-- We will try it again few times, but less then in case of locks
WAITFOR DELAY '00:00:05'
SET @MaxRetries = 3
END

END;
GO
/****** Object:  StoredProcedure [dbo].[sp_Common_PrintError]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- uspPrintError prints error information about the error that caused
-- execution to jump to the CATCH block of a TRY...CATCH construct.
-- Should be executed from within the scope of a CATCH block otherwise
-- it will return without printing any error information.
CREATE PROCEDURE [dbo].[sp_Common_PrintError]
AS
BEGIN
    SET NOCOUNT ON;

    -- Print error information.
    PRINT 'Error ' + CONVERT(varchar(50), ERROR_NUMBER()) +
          ', Severity ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
          ', State ' + CONVERT(varchar(5), ERROR_STATE()) +
          ', Procedure ' + ISNULL(ERROR_PROCEDURE(), '-') +
          ', Line ' + CONVERT(varchar(5), ERROR_LINE());
    PRINT ERROR_MESSAGE();
END;



GO
/****** Object:  StoredProcedure [dbo].[sp_Migration_InsertEvent]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[sp_Migration_InsertEvent]
(
@Event varchar(256),
@EventTypeID tinyint = 1, -- Information
@ID int = NULL OUTPUT
)
AS
BEGIN

IF @Event IS NULL
RETURN

SET NOCOUNT ON
SET LOCK_TIMEOUT 1800


DECLARE @Retry int
DECLARE @MaxRetries int
DECLARE @ErrorAdditionalInfo nvarchar(max)


SET @ErrorAdditionalInfo = 'Event = ' + @Event

SELECT @Retry = 0, @MaxRetries = 0

WHILE  @Retry <= @MaxRetries
BEGIN

SET @ID = NULL

BEGIN TRY


BEGIN TRANSACTION

SELECT @ID = ID
FROM Migration_Events
WHERE [Name] = @Event


IF @ID IS NULL
BEGIN
INSERT INTO Migration_Events([Name],[EventTypeID])
VALUES (@Event,@EventTypeID)

SET @ID = SCOPE_IDENTITY()
END

COMMIT
BREAK

END TRY
BEGIN CATCH

SET @ID = NULL

EXECUTE [dbo].[sp_Common_LogError]
@Retry = @Retry OUTPUT,
@MaxRetries = @MaxRetries OUTPUT,
@ErrorAdditionalInfo = @ErrorAdditionalInfo

END CATCH;
END

END

GO
/****** Object:  StoredProcedure [dbo].[sp_Migration_InsertEventHistory]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[sp_Migration_InsertEventHistory]
(
@SessionID int = NULL,
@Event varchar(256),
@EventTypeID tinyint = 1, -- Information
@EventSourceID tinyint = 1, -- Client
-- @EventStepID tinyint = NULL,
@Step varchar(50),
@ID bigint = NULL OUTPUT,
@IsTraceable bit = 0,
@NoOutput bit = 1
)
AS
BEGIN
SET NOCOUNT ON
SET LOCK_TIMEOUT 1800

DECLARE @Retry int
DECLARE @MaxRetries int
DECLARE @ErrorAdditionalInfo nvarchar(max)

DECLARE @EventStepID int
DECLARE @EventID int

IF @IsTraceable = 1
BEGIN

EXEC sp_Migration_InsertStep
@Name = @Step,
@ID = @EventStepID OUTPUT

EXEC sp_Migration_InsertEvent
@Event = @Event,
@EventTypeID = @EventTypeID,
@ID = @EventID OUTPUT


SET @ErrorAdditionalInfo = 'Event = ' + @Event + ',SessionID = ' +
CONVERT(varchar(max),ISNULL(@SessionID,0))


SELECT @Retry = 0, @MaxRetries = 0

WHILE  @Retry <= @MaxRetries AND @SessionID IS NOT NULL
BEGIN

SET @ID = NULL

BEGIN TRY

INSERT INTO Migration_EventsHistory
(
[Migration_EventID],
[Migration_SessionID],
[Migration_EventSourceID],
[Migration_EventStepID]
)
VALUES
(
@EventID,
@SessionID,
@EventSourceID,
@EventStepID
)

SET @ID = SCOPE_IDENTITY()
BREAK
END TRY
BEGIN CATCH

SET @ID = NULL

EXECUTE [dbo].[sp_Common_LogError]
@Retry = @Retry OUTPUT,
@MaxRetries = @MaxRetries OUTPUT,
@ErrorAdditionalInfo = @ErrorAdditionalInfo

END CATCH;
END
END

IF @NoOutput = 0
BEGIN
SELECT
@ID AS EventHistoryID,
@SessionID AS SessionID,
@EventStepID AS EventStepID

END

END
GO
/****** Object:  StoredProcedure [dbo].[sp_Migration_InsertStep]    Script Date: 7/14/2020 3:36:07 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


CREATE PROCEDURE [dbo].[sp_Migration_InsertStep]
(
@Name varchar(256),
@ID int = NULL OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SET LOCK_TIMEOUT 1800


DECLARE @Retry int
DECLARE @MaxRetries int
DECLARE @ErrorAdditionalInfo nvarchar(max)


SET @ErrorAdditionalInfo = 'Name = ' + @Name

SELECT @Retry = 0, @MaxRetries = 0

WHILE  @Retry <= @MaxRetries
BEGIN

SET @ID = NULL

BEGIN TRY


BEGIN TRANSACTION

SELECT @ID = ID
FROM Migration_Steps
WHERE [Name] = @Name


IF @ID IS NULL
BEGIN
INSERT INTO Migration_Steps([Name])
VALUES (@Name)

SET @ID = SCOPE_IDENTITY()
END

COMMIT
BREAK

END TRY
BEGIN CATCH

SET @ID = NULL

EXECUTE [dbo].[sp_Common_LogError]
@Retry = @Retry OUTPUT,
@MaxRetries = @MaxRetries OUTPUT,
@ErrorAdditionalInfo = @ErrorAdditionalInfo

END CATCH;
END

END

GO
USE [master]
GO
ALTER DATABASE [UAMigration] SET  READ_WRITE
GO

Thursday, December 8, 2011

kernel32.dll DeviceIoControl example in C#

Had to write some code to retrieve the partition alignment of some VM disks hosted on a NAS from within the client OS. Simple method using WMI is below, but that was a bit dull as WMI is too easy so I thought I'd create a native method using API calls to kernel32.dll and use DeviceIOControl... what a pain but below is a native method that shows how to get the native code working under C#...

WMI method - simples...
        void WMIMethod()         
  {
              string sComputer = "."; 
             ManagementScope scope = new ManagementScope("\\\\" + sComputer + "\\root\\cimv2");
             //"\\\\" + args[0] + "\\root\\cimv2");            
  scope.Connect();
             ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_DiskPartition");
             ManagementObjectSearcher searcher =  new ManagementObjectSearcher(scope, query);
               ManagementObjectCollection queryCollection = searcher.Get();
               // Console.WriteLine("MachineName={0}", args[0]);
             foreach (ManagementObject m in queryCollection)
             {                 
 // Display the remote computer information                 
  Console.Write("Disk={0}", m["DiskIndex"]);                 
  Console.Write(",Partition={0}", m["Index"]);                 
  foreach (ManagementBaseObject c in m.GetRelated("Win32_LogicalDisk"))     
             {                     
   Console.Write(",Drive={0}", c["name"]);                 
   }                 
  Console.Write(",StartingOffset={0}", m["StartingOffset"]);
                 Int64 i = Convert.ToInt64(m["StartingOffset"]) + Convert.ToInt64(m["Size"]);
                 Console.Write(",NextAlignedOffset={0}", i);
                 Console.WriteLine(",Size={0}", m["Size"]);
             }
           }

Now the tricky one using the native calls... Converted this to C# from a post on XtremeVB, works like a charm...

//using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;

static class IOCtl
{

private const int GENERIC_READ = unchecked((int)0x80000000);
private const int FILE_SHARE_READ = 1;
private const int FILE_SHARE_WRITE = 2;
private const int OPEN_EXISTING = 3;
private const int IOCTL_DISK_GET_DRIVE_LAYOUT_EX = unchecked((int)0x00070050);
private const int ERROR_INSUFFICIENT_BUFFER = 122;

private enum PARTITION_STYLE : int
{
MBR = 0,
GPT = 1,
RAW = 2
}

private enum Partition : byte
{
ENTRY_UNUSED = 0,
FAT_12 = 1,
XENIX_1 = 2,
XENIX_2 = 3,
FAT_16 = 4,
EXTENDED = 5,
HUGE = 6,
IFS = 7,
OS2BOOTMGR = 0xa,
FAT32 = 0xb,
FAT32_XINT13 = 0xc,
XINT13 = 0xe,
XINT13_EXTENDED = 0xf,
PREP = 0x41,
LDM = 0x42,
UNIX = 0x63
}

[SuppressUnmanagedCodeSecurity()]
private class NativeMethods
{

[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeFileHandle CreateFile(
string fileName,
int desiredAccess,
int shareMode,
IntPtr securityAttributes,
int creationDisposition,
int flagsAndAttributes,
IntPtr hTemplateFile);

[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeviceIoControl(
SafeFileHandle hVol,
int controlCode,
IntPtr inBuffer,
int inBufferSize,
IntPtr outBuffer,
int outBufferSize,
ref int bytesReturned,
IntPtr overlapped);

}

// Needs to be explicit to do the union.
[StructLayout(LayoutKind.Explicit)]
private struct DRIVE_LAYOUT_INFORMATION_EX
{
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
[FieldOffset(4)]
public int PartitionCount;
[FieldOffset(8)]
public DRIVE_LAYOUT_INFORMATION_MBR Mbr;
[FieldOffset(8)]
public DRIVE_LAYOUT_INFORMATION_GPT Gpt;
// Forget partition entry, we can't marshal it directly
// as we don't know how big it is.
}

private struct DRIVE_LAYOUT_INFORMATION_MBR
{
public uint Signature;
}

// Sequential ensures the fields are laid out in memory
// in the same order as we write them here. Without it,
// the runtime can arrange them however it likes, and the
// type may no longer be blittable to the C type.
[StructLayout(LayoutKind.Sequential)]
private struct DRIVE_LAYOUT_INFORMATION_GPT
{
public Guid DiskId;
// C LARGE_INTEGER is 64 bit
public long StartingUsableOffset;
public long UsableLength;
// C ULONG is 32 bit
public int MaxPartitionCount;
}

[StructLayout(LayoutKind.Sequential)]
private struct PARTITION_INFORMATION_MBR
{
public byte PartitionType;
[MarshalAs(UnmanagedType.U1)]
public bool BootIndicator;
[MarshalAs(UnmanagedType.U1)]
public bool RecognizedPartition;
public UInt32 HiddenSectors;

// helper method - is the hi bit valid - if so IsNTFT has meaning.
public bool IsValidNTFT()
{
return (PartitionType & 0xc0) == 0xc0;
}

// is this NTFT - i.e. an NTFT raid or mirror.
public bool IsNTFT()
{
return (PartitionType & 0x80) == 0x80;
}

// the actual partition type.
public Partition GetPartition()
{
const byte mask = 0x3f;
return (Partition)(PartitionType & mask);
}

}

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
private struct PARTITION_INFORMATION_GPT
{
// Strangely, this works as sequential if you build x86,
// But for x64 you must use explicit.
[FieldOffset(0)]
public Guid PartitionType;
[FieldOffset(16)]
public Guid PartitionId;
[FieldOffset(32)]
//DWord64
public ulong Attributes;
[FieldOffset(40)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
public string Name;
}

[StructLayout(LayoutKind.Explicit)]
private struct PARTITION_INFORMATION_EX
{
[FieldOffset(0)]
public PARTITION_STYLE PartitionStyle;
[FieldOffset(8)]
public long StartingOffset;
[FieldOffset(16)]
public long PartitionLength;
[FieldOffset(24)]
public int PartitionNumber;
[FieldOffset(28)]
[MarshalAs(UnmanagedType.U1)]
public bool RewritePartition;
[FieldOffset(32)]
public PARTITION_INFORMATION_MBR Mbr;
[FieldOffset(32)]
public PARTITION_INFORMATION_GPT Gpt;
}

public static void Main()
{
SendIoCtlDiskGetDriveLayoutEx(0);
Console.ReadKey();
}

private static void SendIoCtlDiskGetDriveLayoutEx(int PhysicalDrive)
{

DRIVE_LAYOUT_INFORMATION_EX lie = default(DRIVE_LAYOUT_INFORMATION_EX);
PARTITION_INFORMATION_EX[] pies = null;
using (SafeFileHandle hDevice =
NativeMethods.CreateFile("\\\\.\\PHYSICALDRIVE" + PhysicalDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero))
{
if (hDevice.IsInvalid)
throw new Win32Exception();
// Must run as administrator, otherwise we get "ACCESS DENIED"

// We don't know how many partitions there are, so we have to use a blob of memory...
int numPartitions = 1;
bool done = false;
do
{
// 48 = the number of bytes in DRIVE_LAYOUT_INFORMATION_EX up to
// the first PARTITION_INFORMATION_EX in the array.
// And each PARTITION_INFORMATION_EX is 144 bytes.
int outBufferSize = 48 + (numPartitions * 144);
IntPtr blob = default(IntPtr);
int bytesReturned = 0;
bool result = false;

try
{
blob = Marshal.AllocHGlobal(outBufferSize);
result = NativeMethods.DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IntPtr.Zero, 0, blob, outBufferSize, refbytesReturned, IntPtr.Zero);
// We expect that we might not have enough room in the output buffer.
if (result == false)
{
// If the buffer wasn't too small, then something else went wrong.
if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
throw new Win32Exception();
// We need more space on the next loop.
numPartitions += 1;
}
else
{
// We got the size right, so stop looping.
done = true;
// Do something with the data here - we'll free the memory before we leave the loop.
// First we grab the DRIVE_LAYOUT_INFORMATION_EX, it's at the start of the blob of memory:
lie = (DRIVE_LAYOUT_INFORMATION_EX)Marshal.PtrToStructure(blob, typeof(DRIVE_LAYOUT_INFORMATION_EX));
// Then loop and add the PARTITION_INFORMATION_EX structures to an array.
pies = new PARTITION_INFORMATION_EX[lie.PartitionCount];
for (int i = 0; i <= lie.PartitionCount - 1; i++)
{
// Where is this structure in the blob of memory?
IntPtr offset = new IntPtr(blob.ToInt64() + 48 + (i * 144));
pies[i] = (PARTITION_INFORMATION_EX)Marshal.PtrToStructure(offset, typeof(PARTITION_INFORMATION_EX));
}
}
}
finally
{
Marshal.FreeHGlobal(blob);
}
} while (!(done));
}


DumpInfo(lie, pies);

}

private static bool IsPart0Aligned(PARTITION_INFORMATION_EX[] pies)
{
try
{
if (pies[0].StartingOffset % 4096 == 0)
{
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}

private static void DumpInfo(DRIVE_LAYOUT_INFORMATION_EX lie, PARTITION_INFORMATION_EX[] pies)
{
if (IsPart0Aligned(pies) == true) {
Console.Write( "True");
}
else
{
Console.Write("false");
}
Console.WriteLine("Partition Style: {0}", lie.PartitionStyle);
Console.WriteLine("Partition Count: {0}", lie.PartitionCount);
switch (lie.PartitionStyle)
{
case PARTITION_STYLE.MBR:
Console.WriteLine("Mbr Signature: {0}", lie.Mbr.Signature);
break;
case PARTITION_STYLE.GPT:
Console.WriteLine("Gpt DiskId: {0}", lie.Gpt.DiskId);
Console.WriteLine("Gpt StartingUsableOffset: {0}", lie.Gpt.StartingUsableOffset);
Console.WriteLine("Gpt UsableLength: {0}", lie.Gpt.UsableLength);
Console.WriteLine("Gpt MaxPartitionCount: {0}", lie.Gpt.MaxPartitionCount);
break;
default:
Console.WriteLine("RAW!");
break;
}

for (int i = 0; i <= lie.PartitionCount - 1; i++)
{
Console.WriteLine();
Console.WriteLine("Partition {0} info...", i + 1);
Console.WriteLine("-------------------");
Console.WriteLine();
var _with1 = pies[i];
Console.WriteLine("Partition style: {0}", _with1.PartitionStyle);
Console.WriteLine("Starting offset: {0}", _with1.StartingOffset);
Console.WriteLine("Partition length: {0}", _with1.PartitionLength);
Console.WriteLine("Partition number: {0}", _with1.PartitionNumber);
Console.WriteLine("Rewrite partition: {0}", _with1.RewritePartition);
switch (_with1.PartitionStyle)
{
case PARTITION_STYLE.MBR:
var _with2 = _with1.Mbr;
Console.WriteLine("Mbr PartitionType - raw value: {0}", _with2.PartitionType);
// Console.WriteLine("Mbr PartitionType - validNTFT: {0}", _with2.IsValidNTFT);
// if (_with2.IsValidNTFT)
// Console.WriteLine("Mbr PartitionType - ntft: {0}", _with2.IsNTFT);
// Console.WriteLine("Mbr PartitionType - decoded: {0}", _with2.GetPartition);
Console.WriteLine("Mbr BootIndicator : {0}", _with2.BootIndicator);
Console.WriteLine("Mbr RecognizedPartition : {0}", _with2.RecognizedPartition);
Console.WriteLine("Mbr HiddenSectors : {0}", _with2.HiddenSectors);
break;
case PARTITION_STYLE.GPT:
var _with3 = _with1.Gpt;
Console.WriteLine("Gpt PartitionType: {0}", _with3.PartitionType);
Console.WriteLine("Gpt PartitionId: {0}", _with3.PartitionId);
Console.WriteLine("Gpt Attributes: {0}", _with3.Attributes);
Console.WriteLine("Gpt Name: {0}", _with3.Name);
break;
case PARTITION_STYLE.RAW:
Console.WriteLine("RAW!");
break;
}

}
}

}

Simples! lol!

Search Brian Hehir's sites

Loading