diff --git a/Definitions.pas b/Definitions.pas new file mode 100644 index 0000000..23420c7 --- /dev/null +++ b/Definitions.pas @@ -0,0 +1,445 @@ +unit Definitions; + +interface + +uses Types,Windows,SysUtils; + +Type + TRamErrors = (RamOK, RamNotInstalled, RamNotAccessible, RamCantEnumDrives, RamDriverVersion, RamCantCreate, RamCantFormat, RamNoFreeLetter); + TAssignedDrives = Set of 'A'..'Z'; + ERamDiskError = Class(Exception) + ArsenalCode: TRamErrors; + Constructor Create(Code:TRamErrors); + end; + TRamDisk = Packed Record + size: Int64; + diskNumber: Integer; // \\?\PhysicalDriveXX + volumeName: string; // \\?\Volume{12345678-1234-1234-1234-123456789abc} + persistentFolder: WideString; + excludedList: WideString; + letter: Char; + synchronize:Boolean; + deleteOld:Boolean; + useTemp:Boolean; + end; + + DEVICE_TYPE = DWORD; + PUnicodeString = ^TUnicodeString; + TUnicodeString = packed record + Length: Word; + MaximumLength: Word; + Buffer: PWideChar; + end; + PObjectAttributes = ^TObjectAttributes; + TObjectAttributes = packed record + Length: Cardinal; + RootDirectory: THandle; + ObjectName: PUnicodeString; + Attributes: Cardinal; + SecurityDescriptor: Pointer; + SecurityQualityOfService: Pointer; + end; + NTSTATUS = LongInt; + IO_STATUS_BLOCK = packed Record + case Boolean Of + False: (Status: NTSTATUS); + True: + (Pointer: Pointer; + Information: ULONG); // 'Information' does not belong to the union! + end; + TDeviceNumber = Packed Record + Case Boolean Of + false: (LongNumber: LongWord); + true: + (PathId: Byte; + TargetId: Byte; + Lun: Byte); + End; + TScsiAddress = Packed Record + Length: LongInt; + PortNumber: Byte; + PathId: Byte; + TargetId: Byte; + Lun: Byte; + End; + PScsiAddress = ^TScsiAddress; + ArrayScsiAddress = Array[0..7] of TScsiAddress; + PArrayScsiAddress = ^ArrayScsiAddress; + TScsiDeviceConfigFilename = Array [0..4095] of WideChar; + TScsiDeviceConfig = packed Record + DeviceNumber: TDeviceNumber; // On create this can be set to IMSCSI_AUTO_DEVICE_NUMBER + DiskSize: Int64; + BytesPerSector: LongWord; + Reserved: LongWord; + ImageOffset: Int64; // The byte offset in image file where the virtual disk data begins + Flags: LongWord; // Creation flags. Type of device and type of connection + FileNameLength: Word; // Length in bytes of the FileName member + FileName: TScsiDeviceConfigFilename; + end; + PScsiDeviceConfig = ^TScsiDeviceConfig; + TSrbIoControl = packed record + HeaderLength : ULONG; + Signature : Array[0..7] of Char; + Timeout : ULONG; + ControlCode : ULONG; + ReturnCode : LongInt; + Length : ULONG; + end; + SRB_IO_CONTROL = TSrbIoControl; + PSrbIoControl = ^TSrbIoControl; + TScsiCreateData = Packed Record + SrbIoControl: TSrbIoControl; + Fields: TScsiDeviceConfig; + end; + TScsiRemoveDevice = packed Record + SrbIoControl: TSrbIoControl; + DeviceNumber: TDeviceNumber; + end; + TScsiVersionCheck = Packed Record + SrbIoControl: TSrbIoControl; + // API compatibility version is returned in SrbIoControl.ReturnCode. + // SubVersion contains, in newer versions, a revision version that + // applications can check to see if latest version is loaded. + SubVersion:ULONG; + end; + TStorageDeviceNumber = Record + DeviceType: DEVICE_TYPE; + DeviceNumber: DWORD; + PartitionNumber: DWORD; + end; + PStorageDeviceNumber = ^TStorageDeviceNumber; + + DEV_BROADCAST_VOLUME = packed record + dbch_size: DWORD; + dbch_devicetype: DWORD; + dbch_reserved: DWORD; + dbcv_unitmask: DWORD; + dbcv_flags: WORD; + end; + TDevBroadcastVolume = DEV_BROADCAST_VOLUME; + PDevBroadcastVolume = ^TDevBroadcastVolume; + + DISK_EXTENT = record + DiskNumber: DWORD; + StartingOffset: LARGE_INTEGER; + ExtentLength: LARGE_INTEGER; + end; + TDiskExtent = DISK_EXTENT; + PDiskExtent = ^TDiskExtent; + + VOLUME_DISK_EXTENTS = record + NumberOfDiskExtents: DWORD; + Extents: array [0..0] of DISK_EXTENT; + end; + TVolumeDiskExtents = VOLUME_DISK_EXTENTS; + PVolumeDiskExtents = ^TVolumeDiskExtents; + + SET_DISK_ATTRIBUTES = Packed record + Version: DWORD; + Persist:Boolean; + Reserved1: Array[1..3] of Byte; + Attributes: Int64; + AttributesMask: Int64; + Reserved2: Array[1..4] of DWORD; + end; + TSetDiskAttributes = SET_DISK_ATTRIBUTES; + PSetDiskAttributes = ^TSetDiskAttributes; + + PARTITION_INFORMATION = record + StartingOffset: LARGE_INTEGER; + PartitionLength: LARGE_INTEGER; + HiddenSectors: DWORD; + PartitionNumber: DWORD; + PartitionType: BYTE; + BootIndicator: ByteBool; + RecognizedPartition: ByteBool; + RewritePartition: ByteBool; + end; + TPartitionInformation = PARTITION_INFORMATION; + PPartitionInformation = ^TPartitionInformation; + + DRIVE_LAYOUT_INFORMATION = record + PartitionCount: DWORD; + Signature: DWORD; + PartitionEntry: array [0..0] of PARTITION_INFORMATION; + end; + TDriveLayoutInformation = DRIVE_LAYOUT_INFORMATION; + PDriveLayoutInformation = ^TDriveLayoutInformation; + +const + MAX_DOS_NAMES = 20000; // enough room to handle all possible block and serial devices on an average PC, sometimes it might not be enough !!! + OBJ_CASE_INSENSITIVE = $00000040; + FILE_NON_DIRECTORY_FILE = $00000040; + FILE_SYNCHRONOUS_IO_NONALERT = $00000020; + FILE_DEVICE_MASS_STORAGE = $0000002d; + FILE_DEVICE_DISK = $00000007; + FILE_DEVICE_FILE_SYSTEM = $00000009; + FILE_ANY_ACCESS = 0; + FILE_READ_ACCESS = 1; + FILE_WRITE_ACCESS = $0002; + FILE_READ_ATTRIBUTES = $0080; + METHOD_BUFFERED = 0; + METHOD_NEITHER = 3; + DBT_DEVICEQUERYREMOVE = $8001; + DBT_DEVICEREMOVEPENDING = $8003; + DBT_DEVTYP_VOLUME = 2; + ERROR_NOT_A_REPARSE_POINT = 4390; + DISK_ATTRIBUTE_OFFLINE = 1; + DISK_ATTRIBUTE_READ_ONLY = 2; + IOCTL_SCSI_MINIPORT = $4D008; + IOCTL_SCSI_GET_ADDRESS = $41018; + IOCTL_DISK_BASE = FILE_DEVICE_DISK; + IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE; + IOCTL_VOLUME_BASE = DWORD('V'); + IOCTL_VOLUME_OFFLINE = $56c00c; + IOCTL_VOLUME_ONLINE = $56c008; + IOCTL_STORAGE_EJECT_MEDIA = ($2d shl 16) or (1 shl 14) or ($202 shl 2); + IOCTL_STORAGE_MEDIA_REMOVAL = ($2d shl 16) or (1 shl 14) or ($201 shl 2); + IOCTL_STORAGE_GET_DEVICE_NUMBER = ( + (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or + ($0420 shl 2) or METHOD_BUFFERED); + IOCTL_DISK_GET_LENGTH_INFO = ( + (IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or + ($0017 shl 2) or METHOD_BUFFERED); + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = ( + (IOCTL_VOLUME_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or + (0 shl 2) or METHOD_BUFFERED); + IOCTL_DISK_SET_DISK_ATTRIBUTES = $7c0f4; + IOCTL_DISK_UPDATE_PROPERTIES = ( + (IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or + ($0050 shl 2) or METHOD_BUFFERED); + IOCTL_DISK_SET_DRIVE_LAYOUT = ( + (IOCTL_DISK_BASE shl 16) or ((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or + ($0004 shl 2) or METHOD_BUFFERED); + FSCTL_ALLOW_EXTENDED_DASD_IO = ( + (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or + (32 shl 2) or METHOD_NEITHER); + FSCTL_LOCK_VOLUME = (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (6 shl 2) or METHOD_BUFFERED; + FSCTL_UNLOCK_VOLUME = ( + (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or + (7 shl 2) or METHOD_BUFFERED); + FSCTL_DISMOUNT_VOLUME = ( + (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or + (8 shl 2) or METHOD_BUFFERED); + + // Control codes for IOCTL_SCSI_MINIPORT requests. + SMP_IMSCSI = $83730000; + SMP_IMSCSI_QUERY_VERSION = SMP_IMSCSI + $800; + SMP_IMSCSI_CREATE_DEVICE = SMP_IMSCSI + $801; + SMP_IMSCSI_QUERY_DEVICE = SMP_IMSCSI + $802; + SMP_IMSCSI_QUERY_ADAPTER = SMP_IMSCSI + $803; + SMP_IMSCSI_CHECK = SMP_IMSCSI + $804; + SMP_IMSCSI_SET_DEVICE_FLAGS = SMP_IMSCSI + $805; + SMP_IMSCSI_REMOVE_DEVICE = SMP_IMSCSI + $806; + SMP_IMSCSI_EXTEND_DEVICE = SMP_IMSCSI + $807; + + IMSCSI_FUNCTION_SIGNATURE = 'PhDskMnt'; + IMSCSI_AUTO_DEVICE_NUMBER = $00FFFFFF; + IMSCSI_ALL_DEVICES = $00FFFFFF; + + function GetFreeDriveList: TAssignedDrives; + Procedure ImScsiInitializeSrbIoBlock(var SrbIoControl:TSrbIoControl; Size, ControlCode, Timeout: Cardinal); + procedure InitializeObjectAttributes(var InitializedAttributes: TObjectAttributes; + ObjectName: PUnicodeString; + Attributes: ULONG; + RootDirectory: THandle; + SecurityDescriptor: Pointer; + SecurityQualityOfService: Pointer = NIL); + Function ImScsiOpenScsiAdapterByScsiPortNumber(PortNumber:Byte):THandle; + Function ImScsiQueryDevice(adapter:THandle; config:PScsiDeviceConfig; configSize:LongWord):Boolean; + Function ImDiskOpenDeviceByName(FileName:PUnicodeString; AccessMode:DWORD):THandle; + Function ImScsiOpenScsiAdapter(var PortNumber:Byte):THandle; + Function ImScsiDeviceIoControl(device:THandle; ControlCode: DWORD; var SrbIoControl: TSrbIoControl; Size, Timeout: DWORD; var ReturnLength: DWORD):Boolean; + +implementation + +Uses Math,Classes; + +procedure RtlInitUnicodeString(DestinationString: PUnicodeString; SourceString: LPWSTR); stdcall; external 'ntdll.dll'; +function RtlNtStatusToDosError(Status: NTSTATUS): ULONG; stdcall; external 'ntdll.dll'; +function NtClose(_Handle: THandle): NTSTATUS; stdcall; external 'ntdll.dll'; +function NtOpenFile(out FileHandle: THandle; + DesiredAccess: ACCESS_MASK; + const ObjectAttributes: TObjectAttributes; + out IoStatusBlock: IO_STATUS_BLOCK; + ShareAccess, OpenOptions: ULONG): NTSTATUS; stdcall; external 'ntdll.dll'; + +Constructor ERamDiskError.Create (Code:TRamErrors); +Begin + ArsenalCode:=Code; +end; + +procedure InitializeObjectAttributes(var InitializedAttributes: TObjectAttributes; + ObjectName: PUnicodeString; + Attributes: ULONG; + RootDirectory: THandle; + SecurityDescriptor: Pointer; + SecurityQualityOfService: Pointer = NIL); +begin + InitializedAttributes.Length := SizeOf(TObjectAttributes); + InitializedAttributes.RootDirectory := RootDirectory; + InitializedAttributes.Attributes := Attributes; + InitializedAttributes.ObjectName := ObjectName; + InitializedAttributes.SecurityDescriptor := SecurityDescriptor; + InitializedAttributes.SecurityQualityOfService := SecurityQualityOfService; +end; + +// Prepares for sending a device request to an Arsenal Image Mounter adapter +Procedure ImScsiInitializeSrbIoBlock(var SrbIoControl:TSrbIoControl; Size, ControlCode, Timeout: Cardinal); +begin + SrbIoControl.HeaderLength := sizeof(SRB_IO_CONTROL); + SrbIoControl.Signature := IMSCSI_FUNCTION_SIGNATURE; + SrbIoControl.ControlCode := ControlCode; + SrbIoControl.Length := Size - sizeof(TSrbIoControl); + SrbIoControl.Timeout := Timeout; + SrbIoControl.ReturnCode := 0; +end; + +Function ImDiskOpenDeviceByName(FileName:PUnicodeString; AccessMode:DWORD):THandle; +var + status: NTSTATUS; + object_attrib: TObjectAttributes; + io_status: IO_STATUS_BLOCK; +begin + InitializeObjectAttributes(object_attrib, FileName, OBJ_CASE_INSENSITIVE, 0, NIL); + status := NtOpenFile(Result, SYNCHRONIZE or AccessMode, object_attrib, io_status, FILE_SHARE_READ Or FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT); + + if status<0 then + begin + SetLastError(RtlNtStatusToDosError(status)); + Result:=INVALID_HANDLE_VALUE; + end; +end; + +Function ImScsiOpenScsiAdapterByScsiPortNumber(PortNumber:Byte):THandle; +var + devName: TUnicodeString; + check: TSrbIoControl; + tmp: DWORD; +Begin + RtlInitUnicodeString(@devName, PWideChar(WideString(Format('\??\Scsi%u:',[PortNumber])))); + Result:=ImDiskOpenDeviceByName(@devName, GENERIC_READ + GENERIC_WRITE); + if Result <> INVALID_HANDLE_VALUE then + Begin + ImScsiInitializeSrbIoBlock(check, sizeof(check), SMP_IMSCSI_CHECK, 0); + if not DeviceIoControl(Result, IOCTL_SCSI_MINIPORT, @check, sizeof(check), @check, sizeof(check), tmp, NIL) then + Begin + NtClose(Result); + Result:=INVALID_HANDLE_VALUE; + end; + end; +end; + +Function ImScsiDeviceIoControl(device:THandle; ControlCode: DWORD; var SrbIoControl: TSrbIoControl; Size, Timeout: DWORD; var ReturnLength: DWORD):Boolean; +Begin + ImScsiInitializeSrbIoBlock(SrbIoControl, Size, ControlCode, Timeout); + if Not DeviceIoControl(Device, IOCTL_SCSI_MINIPORT, @SrbIoControl, Size, @SrbIoControl, Size, ReturnLength, NIL) then + begin + OutputDebugString(PAnsiChar(SysErrorMessage(RtlNtStatusToDosError(SrbIoControl.ReturnCode)))); + Result:=FALSE; + Exit; + end; + OutputDebugString(PAnsiChar(SysErrorMessage(RtlNtStatusToDosError(SrbIoControl.ReturnCode)))); + Result:=SrbIoControl.ReturnCode >= 0; +end; + +Function ImScsiQueryDevice(adapter:THandle; config:PScsiDeviceConfig; configSize:LongWord):Boolean; +var + createData: TScsiCreateData; + tmp: DWORD; +Begin + Result:=False; + createData.Fields.DeviceNumber:= config.DeviceNumber; + if Not ImScsiDeviceIoControl(Adapter, SMP_IMSCSI_QUERY_DEVICE, createData.SrbIoControl, SizeOf(TScsiCreateData), 0, tmp) then Exit; + if tmp < SizeOf(TScsiCreateData) - SizeOf(TScsiDeviceConfigFilename) then + begin + SetLastError(ERROR_INVALID_PARAMETER); + Exit; + end; + + Move(createData.Fields, Config^, min(tmp - SizeOf(TSrbIoControl), ConfigSize)); + Result:=TRUE; +end; + +Function ImScsiOpenScsiAdapter(var PortNumber:Byte):THandle; +Var + dosDevs, target: String; + devName: TUnicodeString; + i, len: Integer; + portNum: LongWord; + devices: TStringList; + handle: THandle; + check: TSrbIoControl; + tmp: DWORD; +const + scsiport_prefix = '\Device\Scsi\phdskmnt'; + storport_prefix = '\Device\RaidPort'; +Begin + SetLength(dosDevs, MAX_DOS_NAMES); + SetLength(target, 200); + len:=QueryDosDevice(NIL, PAnsiChar(dosDevs), Length(dosDevs)); + if len = 0 then + begin + tmp:=GetLastError; + raise Exception.Create(SysErrorMessage(tmp)); + end; + for i:=1 to len Do + if dosDevs[i] = #0 then dosDevs[i]:= #13; + devices:=Nil; + Result:=INVALID_HANDLE_VALUE; + Try + devices:=TStringList.Create; + devices.Text:=dosDevs; + for i:=0 to devices.Count-1 do + Begin + if (Copy(devices[i],1,4) = 'Scsi') And (AnsiLastChar(devices[i]) = ':') Then + Begin + portNum:=StrToInt(Copy(devices[i],5,Length(devices[i])-5)); + if portNum < 256 Then + Begin + if QueryDosDevice(PAnsiChar(devices[i]), PAnsiChar(target), Length(target)) = 0 then RaiseLastOSError; + if (Pos(scsiport_prefix, target) = 1) Or (Pos(storport_prefix, target) = 1) then + Begin + RtlInitUnicodeString(@devName, PWideChar(WideString(target))); + handle:=ImDiskOpenDeviceByName(@devName, GENERIC_READ + GENERIC_WRITE); + if handle <> INVALID_HANDLE_VALUE then + Begin + ImScsiInitializeSrbIoBlock(check, sizeof(check), SMP_IMSCSI_CHECK, 0); + if not DeviceIoControl(handle, IOCTL_SCSI_MINIPORT, @check, sizeof(check), @check, sizeof(check), tmp, NIL) then NtClose(handle) + else + Begin + PortNumber:=portNum; + Result:=handle; + Exit; + end; + end; + end; + end; + end; + end; + Finally + devices.Free; + end; +end; + +function GetFreeDriveList: TAssignedDrives; +var + Buff: array[0..128] of Char; + ptr: PChar; + used:TAssignedDrives; +begin + if (GetLogicalDriveStrings(Length(Buff), Buff) = 0) then RaiseLastOSError; + // There can't be more than 26 lettered drives (A..Z). + used:=[]; + + ptr := @Buff[0]; + while StrLen(ptr) > 0 do + begin + Include(used,ptr^); + ptr := StrEnd(ptr); + Inc(ptr); + end; + Result:=['C'..'Z'] - used; // exclude floppy drives +end; + +end. diff --git a/Junctions.pas b/Junctions.pas new file mode 100644 index 0000000..b966b24 --- /dev/null +++ b/Junctions.pas @@ -0,0 +1,135 @@ +unit Junctions; + +// http://progmatix.blogspot.com/2010/10/get-target-of-symlink-in-delphi.html +// https://delphisources.ru/pages/faq/base/hardlink_symbolic_link.html +// http://www.flexhex.com/docs/articles/hard-links.phtml#junctions +// https://fossil.2of4.net/zaap/artifact/ad9fc313554aea05 + +interface + +const + FILE_ATTRIBUTE_REPARSE_POINT = 1024; + +function GetSymLinkTarget(const AFilename: Widestring): Widestring; +function CreateJunction(const ALink,ADest:WideString): Boolean; + +implementation + +uses Windows; + +const + MAX_REPARSE_SIZE = 17000; + MAX_NAME_LENGTH = 1024; + REPARSE_MOUNTPOINT_HEADER_SIZE = 8; + IO_REPARSE_TAG_MOUNT_POINT = $0A0000003; + FILE_FLAG_OPEN_REPARSE_POINT = $00200000; + FILE_DEVICE_FILE_SYSTEM = $0009; + FILE_ANY_ACCESS = 0; + METHOD_BUFFERED = 0; + FSCTL_SET_REPARSE_POINT = (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (41 shl 2) or (METHOD_BUFFERED); + FSCTL_GET_REPARSE_POINT = (FILE_DEVICE_FILE_SYSTEM shl 16) or (FILE_ANY_ACCESS shl 14) or (42 shl 2) or (METHOD_BUFFERED); + +type + REPARSE_DATA_BUFFER = packed record + ReparseTag: DWORD; + ReparseDataLength: Word; + Reserved: Word; + SubstituteNameOffset: Word; + SubstituteNameLength: Word; + PrintNameOffset: Word; + PrintNameLength: Word; + PathBuffer: array[0..0] of WideChar; + end; + TReparseDataBuffer = REPARSE_DATA_BUFFER; + PReparseDataBuffer = ^TReparseDataBuffer; + + REPARSE_MOUNTPOINT_DATA_BUFFER = packed record + ReparseTag: DWORD; + ReparseDataLength: DWORD; + Reserved: Word; + ReparseTargetLength: Word; + ReparseTargetMaximumLength: Word; + Reserved1: Word; + ReparseTarget: array[0..0] of WideChar; + end; + TReparseMountPointDataBuffer = REPARSE_MOUNTPOINT_DATA_BUFFER; + PReparseMountPointDataBuffer = ^TReparseMountPointDataBuffer; + + Function CreateSymbolicLinkW(Src,Target:PWideChar;Flags:Cardinal):BOOL; Stdcall; External 'kernel32.dll'; + +function OpenDirectory(const ADir:WideString;bReadWrite:Boolean):THandle; +var + token:THandle; + tp:TTokenPrivileges; + bp:WideString; + dw,access:DWORD; +begin + // Obtain backup/restore privilege in case we don't have it + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, token); + If bReadWrite Then bp:='SeRestorePrivilege' else bp:='SeBackupPrivilege'; + LookupPrivilegeValueW(NIL, PWideChar(bp), tp.Privileges[0].Luid); + tp.PrivilegeCount := 1; + tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(token, FALSE, tp, sizeof(TOKEN_PRIVILEGES), NIL, dw); + CloseHandle(token); + + // Open the directory + access:=GENERIC_READ; + if bReadWrite then access:=access or GENERIC_WRITE; + Result := CreateFileW(PWideChar(ADir), access, 0, NIL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT or FILE_FLAG_BACKUP_SEMANTICS, 0); +end; + +function GetSymLinkTarget(const AFilename: WideString): Widestring; +var + hDir:THandle; + nRes:DWORD; + reparseInfo: PReparseDataBuffer; + name2: array[0..MAX_NAME_LENGTH-1] of WideChar; +begin + Result := ''; + hDir:= OpenDirectory(AFilename,False); + if hDir = INVALID_HANDLE_VALUE then Exit; + GetMem(reparseInfo,MAX_REPARSE_SIZE); + if DeviceIoControl(hDir, FSCTL_GET_REPARSE_POINT, nil, 0, reparseInfo, MAX_REPARSE_SIZE, nRes, nil) Then + If reparseInfo.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT then + Begin + FillChar(name2, SizeOf(name2), 0); + lstrcpynW(name2, reparseInfo.PathBuffer + reparseInfo.SubstituteNameOffset, reparseInfo.SubstituteNameLength); + Result:= Copy(name2,5,Length(name2)); // remove the '\??\' prefix + end; + FreeMem(reparseInfo,MAX_REPARSE_SIZE); + CloseHandle(hDir); +end; + +// target must NOT begin with "\??\" - it will be added automatically +Function CreateJunction(const ALink,ADest:WideString):Boolean; +Const + LinkPrefix: WideString = '\??\'; +var + Buffer: PReparseMountPointDataBuffer; + BufSize: integer; + TargetName: WideString; + hDir:THandle; + dw:DWORD; +Begin + Result:=False; + hDir:=OpenDirectory(ALink,True); + If hDir = INVALID_HANDLE_VALUE then Exit; + If Pos(LinkPrefix,ADest)=1 then TargetName:=ADest else TargetName:=LinkPrefix+ADest; + BufSize:=(Length(TargetName)+1)*SizeOf(WideChar) + REPARSE_MOUNTPOINT_HEADER_SIZE + 12; + GetMem(Buffer,BufSize); + FillChar(Buffer^,BufSize,#0); + With Buffer^ Do + Begin + Move(TargetName[1], ReparseTarget, (Length(TargetName)+1)*SizeOf(WideChar)); + ReparseTag:= IO_REPARSE_TAG_MOUNT_POINT; + ReparseTargetLength:= Length(TargetName)*SizeOf(WideChar); + ReparseTargetMaximumLength:= ReparseTargetLength+2; + ReparseDataLength:= ReparseTargetLength+12; + end; + Result:=DeviceIoControl(hDir,FSCTL_SET_REPARSE_POINT,Buffer,Buffer.ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE,Nil,0,dw,Nil); + FreeMem(Buffer,BufSize); + CloseHandle(hDir); +end; + +end. diff --git a/Main.dfm b/Main.dfm new file mode 100644 index 0000000..87fa5c8 --- /dev/null +++ b/Main.dfm @@ -0,0 +1,243 @@ +object frmUI: TfrmUI + Left = 263 + Top = 110 + ActiveControl = vdSize + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'RAMdisk UI' + ClientHeight = 522 + ClientWidth = 303 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnCreate = FormCreate + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object txtDrive: TLabel + Left = 40 + Top = 72 + Width = 58 + Height = 13 + Caption = 'Drive letter:' + end + object txtContent: TLabel + Left = 14 + Top = 132 + Width = 119 + Height = 13 + Caption = 'Load content from folder' + end + object vdSize: TLabeledEdit + Left = 36 + Top = 24 + Width = 61 + Height = 21 + Hint = 'Minimum 3MB' + EditLabel.Width = 23 + EditLabel.Height = 13 + EditLabel.Caption = 'Size:' + LabelPosition = lpLeft + MaxLength = 4 + ParentShowHint = False + ShowHint = True + TabOrder = 0 + end + object radioMB: TRadioButton + Left = 108 + Top = 16 + Width = 57 + Height = 17 + Caption = 'MB' + Checked = True + TabOrder = 1 + TabStop = True + end + object radioGB: TRadioButton + Left = 108 + Top = 40 + Width = 57 + Height = 17 + Caption = 'GB' + TabOrder = 2 + end + object comboLetter: TComboBox + Left = 108 + Top = 68 + Width = 41 + Height = 21 + Style = csDropDownList + ItemHeight = 13 + Sorted = True + TabOrder = 3 + end + object chkTemp: TCheckBox + Left = 12 + Top = 100 + Width = 273 + Height = 17 + Caption = 'Create TEMP folder and set environment variables' + TabOrder = 4 + end + object btnLoad: TButton + Left = 248 + Top = 150 + Width = 32 + Height = 25 + Caption = '...' + TabOrder = 6 + OnClick = btnLoadClick + end + object chkSync: TCheckBox + Left = 12 + Top = 184 + Width = 225 + Height = 17 + Hint = + 'Copy RAM-disk contents back to the '#13#10'same folder where it was in' + + 'itialized from.' + Caption = 'Synchronize at shutdown' + ParentShowHint = False + ShowHint = True + TabOrder = 7 + OnClick = chkSyncClick + end + object grpSync: TGroupBox + Left = 16 + Top = 220 + Width = 269 + Height = 169 + Caption = ' Do not persist these folders (no wildcards) ' + Enabled = False + TabOrder = 8 + object chkDelete: TCheckBox + Left = 8 + Top = 24 + Width = 249 + Height = 17 + Hint = + 'Delete files and folders from the INIT '#13#10'folder that are not pre' + + 'sent on the RAM-disk.' + Caption = 'Delete data removed from RAMdisk' + ParentShowHint = False + ShowHint = True + TabOrder = 0 + end + object memoIgnore: TTntMemo + Left = 2 + Top = 52 + Width = 265 + Height = 115 + Hint = + 'One folder per line,'#13#10'no wildcards, no subfolders,'#13#10'no drive let' + + 'ter - folders are'#13#10'relative to the root of RAM-disk' + Align = alBottom + Anchors = [akLeft, akTop, akRight, akBottom] + HideSelection = False + ParentShowHint = False + ScrollBars = ssBoth + ShowHint = True + TabOrder = 1 + end + end + object btnSave: TButton + Left = 16 + Top = 398 + Width = 125 + Height = 48 + Caption = 'Save now - apply on reboot' + TabOrder = 9 + WordWrap = True + OnClick = btnSaveClick + end + object btnApply: TButton + Left = 160 + Top = 398 + Width = 125 + Height = 48 + Caption = 'Save and apply now' + TabOrder = 10 + WordWrap = True + OnClick = btnApplyClick + end + object btnQuit: TButton + Left = 104 + Top = 489 + Width = 101 + Height = 28 + Caption = 'Quit' + TabOrder = 11 + OnClick = btnQuitClick + end + object grpRAM: TGroupBox + Left = 176 + Top = 12 + Width = 105 + Height = 77 + Caption = ' Active ' + TabOrder = 12 + object lamp: TShape + Left = 8 + Top = 48 + Width = 16 + Height = 16 + Brush.Color = clLime + Shape = stCircle + end + object txtSize: TLabel + Left = 12 + Top = 16 + Width = 81 + Height = 16 + Alignment = taCenter + AutoSize = False + ShowAccelChar = False + Layout = tlCenter + end + object btnUnmount: TButton + Left = 32 + Top = 44 + Width = 67 + Height = 25 + Caption = 'Unmount' + Enabled = False + TabOrder = 0 + OnClick = btnUnmountClick + end + end + object editFolder: TTntEdit + Left = 12 + Top = 152 + Width = 229 + Height = 21 + Hint = + 'If you select a folder - its entire content will be'#13#10'copied to t' + + 'he RAM-disk. Symlinks are recognized.' + ParentShowHint = False + ShowHint = True + TabOrder = 5 + end + object btnInstall: TButton + Left = 16 + Top = 454 + Width = 125 + Height = 28 + Caption = 'Install service' + TabOrder = 13 + OnClick = btnInstallClick + end + object btnUninstall: TButton + Left = 160 + Top = 454 + Width = 125 + Height = 28 + Caption = 'Uninstall service' + TabOrder = 14 + OnClick = btnUninstallClick + end +end diff --git a/Main.pas b/Main.pas new file mode 100644 index 0000000..84eccfe --- /dev/null +++ b/Main.pas @@ -0,0 +1,355 @@ +unit Main; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ExtCtrls, TntStdCtrls; + +type + TfrmUI = class(TForm) + vdSize: TLabeledEdit; + radioMB: TRadioButton; + radioGB: TRadioButton; + txtDrive: TLabel; + comboLetter: TComboBox; + chkTemp: TCheckBox; + btnUnmount: TButton; + txtContent: TLabel; + btnLoad: TButton; + chkSync: TCheckBox; + grpSync: TGroupBox; + chkDelete: TCheckBox; + btnSave: TButton; + btnApply: TButton; + btnQuit: TButton; + grpRAM: TGroupBox; + lamp: TShape; + txtSize: TLabel; + editFolder: TTntEdit; + memoIgnore: TTntMemo; + btnInstall: TButton; + btnUninstall: TButton; + procedure btnApplyClick(Sender: TObject); + procedure btnInstallClick(Sender: TObject); + procedure btnLoadClick(Sender: TObject); + procedure btnQuitClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnUninstallClick(Sender: TObject); + procedure btnUnmountClick(Sender: TObject); + procedure chkSyncClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + Procedure UpdateDismounted; + Procedure UpdateMounted; + Procedure UpdateLetters; + Procedure SaveSettings; + Procedure LoadSettings; + public + { Public declarations } + end; + +var + frmUI: TfrmUI; + +implementation + +{$R *.dfm} + +Uses Definitions,RamDetect,RamRemove,RamCreate,Types,StrUtils,WinSvc,TntRegistry,TntFileCtrl,TntSysUtils; + +const + serviceName = 'ArsenalRamDisk'; + +Var + ramDiskConfig: TRamDisk; + +Procedure decodeException(code:TRamErrors); +Var + msg: String; +Begin + msg:=''; + Case code Of + RamNotInstalled: msg:='Arsenal Driver is not installed'; + RamNotAccessible: msg:='Arsenal Driver is not accessible'; + RamCantEnumDrives: msg:='Can not enumerate disk volumes'; + RamDriverVersion: msg:='Arsenal Driver is old version'; + RamCantCreate: msg:='Could not create RAM-disk'; + RamCantFormat: msg:='Could not create a partition on the RAM-disk'; + RamNoFreeLetter: msg:='No free drive letters available'; + end; + if msg<>'' then MessageDlg(msg,mtError,[mbOK],0); +End; + +procedure TfrmUI.btnApplyClick(Sender: TObject); +begin + SaveSettings; + If not TryStrToInt64(vdSize.Text,ramDiskConfig.size) Then MessageDlg('Invalid disk size',mtError,[mbOK],0) + else if comboLetter.Items.Count = 0 Then MessageDlg('No free drive letters',mtError,[mbOK],0) + Else + begin + if ramDiskConfig.letter <> #0 Then btnUnmount.Click(); // First unmount + If comboLetter.ItemIndex <> -1 Then ramDiskConfig.letter:=comboLetter.Items[comboLetter.ItemIndex][1] + Else ramDiskConfig.letter:='#'; // use first free letter + ramDiskConfig.size:=ramDiskConfig.size shl 20; + If radioGB.Checked then ramDiskConfig.size:=ramDiskConfig.size shl 10; + try + ramDiskConfig.persistentFolder:=editFolder.Text; + ramDiskConfig.useTemp:=chkTemp.Checked; + if CreateRamDisk(ramDiskConfig,True) Then + Begin + UpdateLetters; + UpdateMounted; + end; + except + On E:ERamDiskError do decodeException(E.ArsenalCode); + else raise; + End; + end; +end; + +procedure TfrmUI.btnLoadClick(Sender: TObject); +var + dir,root:WideString; +begin + dir:=''; + root:=editFolder.Text; + if root = '' then root:='::{20D04FE0-3AEA-1069-A2D8-08002B30309D}'; + if WideSelectDirectory('Select folder to init the RAM-disk',root,dir) then editFolder.Text:=dir; +end; + +procedure TfrmUI.btnQuitClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmUI.btnSaveClick(Sender: TObject); +begin + SaveSettings; +end; + +procedure TfrmUI.btnUnmountClick(Sender: TObject); +begin + try + ramDiskConfig.persistentFolder:=editFolder.Text; + ramDiskConfig.excludedList:=memoIgnore.Text; + ramDiskConfig.deleteOld:=chkDelete.Checked; + ramDiskConfig.synchronize:=chkSync.Checked; + if DetachRamDisk(ramDiskConfig) then + Begin + UpdateDismounted; + end; + Except + On E:ERamDiskError do decodeException(E.ArsenalCode); + else raise; + end; +end; + +procedure TfrmUI.chkSyncClick(Sender: TObject); +begin + grpSync.Enabled:=chkSync.Checked; +end; + +procedure TfrmUI.FormCreate(Sender: TObject); +begin + SetWindowLong(vdSize.Handle,GWL_STYLE,GetWindowLong(vdSize.Handle,GWL_STYLE) + ES_NUMBER); +end; + +Procedure TfrmUI.LoadSettings; +var + reg: TTntRegistry; + diskSize: Int64; +Begin + reg:=TTntRegistry.Create(KEY_READ); + Try + reg.RootKey:=HKEY_LOCAL_MACHINE; + if Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\'+serviceName, False) then + begin + If Reg.ValueExists('DiskSize') then + Begin + diskSize:=StrToInt64(reg.ReadString('DiskSize')); + if (diskSize mod (1 Shl 30))<>0 then + Begin + vdSize.Text:=IntToStr(diskSize shr 20); + radioMB.Checked:=True; + radioGB.Checked:=False; + End + else + Begin + vdSize.Text:=IntToStr(diskSize shr 30); + radioMB.Checked:=False; + radioGB.Checked:=True; + end; + end; + if reg.ValueExists('DriveLetter') Then + Begin + comboLetter.ItemIndex:=comboLetter.Items.IndexOf(reg.ReadString('DriveLetter')); + end; + if reg.ValueExists('LoadContent') Then + Begin + editFolder.Text:=reg.ReadString('LoadContent'); + end; + if reg.ValueExists('ExcludeFolders') Then + Begin + memoIgnore.Lines.Text:=reg.ReadString('ExcludeFolders'); + end; + if reg.ValueExists('UseTempFolder') Then + Begin + chkTemp.Checked:=reg.ReadBool('UseTempFolder'); + end; + if reg.ValueExists('SyncContent') Then + Begin + chkSync.Checked:=reg.ReadBool('SyncContent'); + grpSync.Enabled:=chkSync.Checked; + end; + if reg.ValueExists('DeleteOld') Then + Begin + chkDelete.Checked:=reg.ReadBool('DeleteOld'); + end; + Reg.CloseKey; + end; + Finally + reg.Free; + End; +end; + +Procedure TfrmUI.SaveSettings; +var + reg: TTntRegistry; + diskSize: Int64; + i:Integer; + s:WideString; +Begin + reg:=TTntRegistry.Create(KEY_WRITE); + Try + reg.RootKey:=HKEY_LOCAL_MACHINE; + if Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\'+serviceName, True) then + begin + diskSize:=StrToInt64(vdSize.Text); + If radioMB.Checked then diskSize:=diskSize Shl 20 Else diskSize:=diskSize shl 30; + i:=0; + while i0)or(WidePosEx('/',s)>0) then memoIgnore.Lines.Delete(i) + else + Begin + memoIgnore.Lines[i]:=s; + Inc(i); + end; + end; + reg.WriteString('DiskSize',IntToStr(diskSize)); + reg.WriteString('DriveLetter',comboLetter.Text); + reg.WriteString('LoadContent',editFolder.Text); + reg.WriteString('ExcludeFolders',memoIgnore.Lines.Text); + reg.WriteBool('UseTempFolder',chkTemp.Checked); + reg.WriteBool('SyncContent',chkSync.Checked); + reg.WriteBool('DeleteOld',chkDelete.Checked); + Reg.CloseKey; + end; + Finally + reg.Free; + End; +end; + +procedure TfrmUI.UpdateLetters; +var + freeLetters: TAssignedDrives; + d: Char; +Begin + // get assigned drive letters and then compute the list of unassigned letters + freeLetters:=GetFreeDriveList; + comboLetter.Clear; + For d:='C' To 'Z' Do // skip floppy drives + Begin + If d in freeLetters Then comboLetter.Items.Add(d); + end; +end; + +procedure TfrmUI.UpdateMounted; +Begin + if ramDiskConfig.letter <> #0 then comboLetter.Items.Add(ramDiskConfig.letter); + comboLetter.ItemIndex:=comboLetter.Items.IndexOf(ramDiskConfig.letter); + if (ramDiskConfig.size mod (1 Shl 30)) <> 0 then txtSize.Caption:=IntToStr(ramDiskConfig.size Shr 20) + ' MB' + else txtSize.Caption:=IntToStr(ramDiskConfig.size Shr 30) + ' GB'; + btnUnmount.Enabled:=True; + lamp.Brush.Color:=clLime; +end; + +procedure TfrmUI.UpdateDismounted; +Begin + ramDiskConfig.letter:=#0; + ramDiskConfig.size:=0; + ramDiskConfig.diskNumber:=-1; + txtSize.Caption:=''; + lamp.Brush.Color:=clRed; + btnUnmount.Enabled:=False; +end; + +function ServiceGetStatus(sMachine, sService: string):DWord; +var + h_manager,h_svc: SC_Handle; + service_status: TServiceStatus; + hStat: DWord; +begin + hStat := 0; + h_manager := OpenSCManager(PChar(sMachine) ,Nil, SC_MANAGER_CONNECT); + + if h_manager <> 0 then + begin + h_svc := OpenService(h_manager,PChar(sService), SERVICE_QUERY_STATUS); + if h_svc <> 0 then + begin + if(QueryServiceStatus(h_svc, service_status)) then hStat := service_status.dwCurrentState; + CloseServiceHandle(h_svc); + end; + CloseServiceHandle(h_manager); + end; + Result := hStat; +end; + +procedure TfrmUI.btnInstallClick(Sender: TObject); +begin + if WinExec('RamService /install',SW_HIDE) < 32 then MessageDlg('Error occurred - probably RamService.exe is missing',mtError,[mbOK],0) + Else + Begin + btnInstall.Enabled:=False; + btnUninstall.Enabled:=True; + end; +end; + +procedure TfrmUI.btnUninstallClick(Sender: TObject); +begin + if WinExec('RamService /uninstall',SW_HIDE) < 32 then MessageDlg('Error occurred - probably RamService.exe is missing',mtError,[mbOK],0) + Else + Begin + btnInstall.Enabled:=True; + btnUninstall.Enabled:=False; + end; +end; + +procedure TfrmUI.FormShow(Sender: TObject); +Var + srvStatus:DWORD; +begin + // aim -a -s 50M -t vm -m x: + UpdateLetters; + // check service status + srvStatus:=ServiceGetStatus('',serviceName); + btnInstall.Enabled:=srvStatus = 0; + btnUninstall.Enabled:=srvStatus <> 0; + /// TODO - react on dynamic drive changes (attaching/detaching a device) + LoadSettings; + try + if GetRamDisk(ramDiskConfig) Then UpdateMounted + Else UpdateDismounted; + Except + On E:ERamDiskError do decodeException(E.ArsenalCode); + else raise; + End; +end; + +end. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3dba79c --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# GUI + background service for the Arsenal Virtual RAM-disk driver + +This project was born out of necessity. I have been using [ImDisk Toolkit](https://sourceforge.net/projects/imdisk-toolkit/) for years without any issues. +I particularly liked the ability to preload content to the RAM-disk from a local directory and synchronize the RAM-disk back on shutdown. +However, I started meeting issues when some newer software applications refused to work with my ImDisk-powered RAM-disk. +One easy to reproduce case is if you install Chrome 86+ and then try to install any Chrome extension - you will get a popup window with an error message + +``` +ERR_CANT_FIND_TEMP_FOLDER +``` + +The underlying reason for the error is that ImDisk driver works in a special mode (Direct-IO) which bypasses Windows Volume Manager. +This leads to a problem with the Win32 API function `GetFinalPathNameByHandle` - you can read the discussions at + +- [https://web.archive.org/web/20200805111419/http://reboot.pro/topic/22008-getfinalpathnamebyhandle-fails-with-error-invalid-function/](https://web.archive.org/web/20200805111419/http://reboot.pro/topic/22008-getfinalpathnamebyhandle-fails-with-error-invalid-function/) +- [https://web.archive.org/web/20200815180956/http://reboot.pro/topic/21152-possible-bug-or-incompatibility-in-imdisk/](https://web.archive.org/web/20200815180956/http://reboot.pro/topic/21152-possible-bug-or-incompatibility-in-imdisk/) + +The author of ImDisk drver created Arsenal driver which works in the normal `SCSI miniport` mode and is visible to the Windows Volume Manager. +He provides a console utility to create/remove RAM-disk(s) but no `Windows service` tool that will create a RAM-disk on boot - and certainly nothing similar to the ImDisk Toolkit that I was used to (and probably many other users). +The console utility is also dependent on the ImDisk CPL applet - which I did not quite like (from a developer's point of view). + +So I decided to create a GUI for configuring the parameters of the RAM-disk, plus a `Windows service` that will create the desired RAM-disk on boot and persist it on shutdown. +Of course, I did some research before deciding to start the development - there were other free and commercial RAM-disk tools working as `SCSI miniport` drivers +but they either did not have the additional features of ImDisk Toolkit or they required a VHD image for preloading/persisting the RAM-disk contents +(and I preferred the usage of native filesystem instead of VHD image). + +It took me about a week to extract the relevant code from the AIM (Arsenal Image Mounter) console utility and translate it from C++ to Objec Pascal. +After a lot of debugging and trials/errors I succeeded - and successfully replaced ImDisk Toolkit with my tools. +I have to admit that I was in a hurry and just needed a working solution - there were no attempts to make the code more robust or to implement complex features (like regex support in the list of folders excluded from synchronization at shutdown). + +The code is provided "AS IS" in the hope that it will be useful to others. All pull requests are welcome. + + +# LICENSE + +MIT License + +Copyright (c) 2021 tmcdos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/RamCreate.pas b/RamCreate.pas new file mode 100644 index 0000000..9828698 --- /dev/null +++ b/RamCreate.pas @@ -0,0 +1,398 @@ +unit RamCreate; + +interface + +Uses Definitions; + +function CreateRamDisk(Var config:TRamDisk;ShowProgress:Boolean): Boolean; + +implementation + +Uses Types,Windows,Classes,SysUtils,Controls,Forms,ExtCtrls,RamVolume,RamSetup,RamSync; + +const + IMSCSI_DRIVER_VERSION = $101; + PARTITION_IFS = $07; + FMIFS_HARDDISK = $0C; + +type + TCallBackCommand = ( + PROGRESS, + DONEWITHSTRUCTURE, + UNKNOWN2, + UNKNOWN3, + UNKNOWN4, + UNKNOWN5, + INSUFFICIENTRIGHTS, + FSNOTSUPPORTED, // added 1.1 + VOLUMEINUSE, // added 1.1 + UNKNOWN9, + UNKNOWNA, + DONE, + UNKNOWNC, + UNKNOWND, + OUTPUT, + STRUCTUREPROGRESS, + CLUSTERSIZETOOSMALL, // 16 + UNKNOWN11, + UNKNOWN12, + UNKNOWN13, + UNKNOWN14, + UNKNOWN15, + UNKNOWN16, + UNKNOWN17, + UNKNOWN18, + PROGRESS2, // added 1.1, Vista percent done seems to duplicate PROGRESS + UNKNOWN1A) ; + +Var + infoForm: TForm; + +function NtClose(_Handle: THandle): NTSTATUS; stdcall; external 'ntdll.dll'; +function RtlRandom(Seed : PULONG): ULONG; stdcall; external 'ntdll.dll'; +function FindFirstVolume(lpszVolumeName: LPSTR; cchBufferLength: DWORD): THANDLE; stdcall; External kernel32 name 'FindFirstVolumeA'; +function FindNextVolume(hFindVolume: THANDLE; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; External kernel32 name 'FindNextVolumeA'; +function FindVolumeClose(hFindVolume: THANDLE): BOOL; stdcall; External kernel32; +function GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames: LPCSTR; cchBufferLength: DWORD; var lpcchReturnLength: DWORD): BOOL; stdcall; External kernel32 name 'GetVolumePathNamesForVolumeNameA'; +function DeleteVolumeMountPoint(lpszVolumeMountPoint: LPCSTR): BOOL; stdcall;external 'kernel32.dll' name 'DeleteVolumeMountPointA'; +function SetVolumeMountPoint(lpszVolumeMountPoint, lpszVolumeName: LPCSTR): BOOL; stdcall;external 'kernel32.dll' name 'SetVolumeMountPointA'; +Procedure FormatEx( + DriveRoot: PWCHAR; + MediaFlag: DWORD; + Format: PWCHAR; + DiskLabel: PWCHAR; + QuickFormat: BOOL; + ClusterSize: DWORD; + Callback: Pointer); stdcall; External 'fmifs.dll'; + +procedure ShowInfo(const S : string); +begin + if InfoForm <> nil then InfoForm.Free; + InfoForm := TForm.Create(nil); + InfoForm.FormStyle := fsStayOnTop; + InfoForm.BorderStyle := bsNone; + InfoForm.BorderIcons := []; + InfoForm.Caption := ''; + InfoForm.Position := poScreenCenter; + InfoForm.Width := InfoForm.Canvas.TextWidth(S) + 32; + InfoForm.Height := 35; + with TPanel.Create(InfoForm) do + begin + Align := alClient; + Parent := InfoForm; + Caption := S; + Color:=255; + Font.Color:=$FFFFFF; + end; + InfoForm.Show; + InfoForm.Update; +end; + +procedure HideInfo; +begin + if InfoForm <> nil then + begin + InfoForm.Hide; + InfoForm.Free; + InfoForm := nil; + end; +end; + +Function ImScsiCheckDriverVersion(device:THandle):Boolean; +Var + check: TScsiVersionCheck; + dw: DWORD; +Begin + Result:=False; + ImScsiInitializeSrbIoBlock(check.SrbIoControl, sizeof(check), SMP_IMSCSI_QUERY_VERSION, 0); + if Not DeviceIoControl(Device, IOCTL_SCSI_MINIPORT, @check, sizeof(check), @check, sizeof(check), dw, NIL) then Exit; + if dw < sizeof(check) then Exit; + if check.SrbIoControl.ReturnCode < IMSCSI_DRIVER_VERSION Then Exit; + Result:=True; +end; + +Function ImScsiVolumeUsesDisk(Volume:THandle; DiskNumber:DWORD):Boolean; +Var + dw:DWORD; + disk_extents: TVolumeDiskExtents; +begin + Result:=False; + if Not DeviceIoControl(Volume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NIL, 0, + @disk_extents, SizeOf(TVolumeDiskExtents) + Length(disk_extents.Extents) * SizeOf(TDiskExtent), dw, NIL) Then Exit; + Result:= disk_extents.Extents[0].DiskNumber = DiskNumber; +end; + +Function ImDiskFindFreeDriveLetter:Char; +var + freeLetters:TAssignedDrives; + d:Char; +begin + freeLetters := GetFreeDriveList(); + Result:=#0; + For d:='C' to 'Z' Do + if d in freeLetters Then + Begin + Result:=d; + Exit; + end; +end; + +function FormatCallback (Command: TCallBackCommand; SubAction: DWORD; ActionInfo: Pointer): Boolean; stdcall; +Begin + // we do not need visual progress + Result:=True; +end; + +// if Letter is "#" - the first unused letter is used +Function CreateRamDisk(Var config:TRamDisk;ShowProgress:Boolean):Boolean; +Var + driver,disk,event,volume,volHandle: THandle; + dw: DWORD; + portNumber: Byte; + create_data: TScsiCreateData; + deviceNumber: TDeviceNumber; + i,diskNumber, numVolumes: Integer; + devPath,mountPoint: string; + disk_attributes: TSetDiskAttributes; + disk_size: Int64; + rand_seed,start_time: Cardinal; + drive_layout:TDriveLayoutInformation; + volumeName: Array[0..49] of AnsiChar; + mountName: Array[0..250] Of AnsiChar; + formatDriveName: WideString; + mountList:TStringList; + mustFormat, formatDone, mount_point_found:Boolean; +Begin + Result:=False; + driver := ImScsiOpenScsiAdapter(portNumber); + if driver = INVALID_HANDLE_VALUE then Exit; + if not ImScsiCheckDriverVersion(driver) then + begin + CloseHandle(driver); + Raise ERamDiskError.Create(RamDriverVersion); + end; + create_data.Fields.DeviceNumber.LongNumber := IMSCSI_AUTO_DEVICE_NUMBER; + create_data.Fields.DiskSize := config.size; + if not ImScsiDeviceIoControl(driver, SMP_IMSCSI_CREATE_DEVICE, create_data.SrbIoControl, SizeOf(create_data), 0, dw) then + begin + NtClose(driver); + OutputDebugString(PAnsiChar(SysErrorMessage(GetLastError))); + raise ERamDiskError.Create(RamCantCreate); + end; + NtClose(driver); + DeviceNumber := create_data.Fields.DeviceNumber; + disk := INVALID_HANDLE_VALUE; + diskNumber := -1; + + Sleep(200); + + while true do + begin + disk := ImScsiOpenDiskByDeviceNumber(create_data.Fields.DeviceNumber, portNumber, diskNumber); + if disk <> INVALID_HANDLE_VALUE then Break; + //printf("Disk not attached yet, waiting... %c\r", NextWaitChar(&wait_char)); + + event := ImScsiRescanScsiAdapterAsync(TRUE); + Sleep(200); + + if event = 0 then Sleep(200) + else + begin + while WaitForSingleObject(event, 200) = WAIT_TIMEOUT do + begin + // printf("Disk not attached yet, waiting... %c\r", NextWaitChar(&wait_char)); + end; + CloseHandle(event); + end; + end; + CloseHandle(disk); + + devPath:='\\?\PhysicalDrive' + IntToStr(diskNumber); + config.diskNumber:=diskNumber; + disk := CreateFile(PAnsiChar(devPath), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + if disk = INVALID_HANDLE_VALUE then + begin + dw:=GetLastError; + OutputDebugString(PAnsiChar('Error reopening for writing ' + devPath + ': ' + SysErrorMessage(dw))); + raise ERamDiskError.Create(RamNotAccessible); + end; + + disk_attributes.Version:=SizeOf(disk_attributes); + disk_attributes.AttributesMask := DISK_ATTRIBUTE_OFFLINE; + if not DeviceIoControl(disk, IOCTL_DISK_SET_DISK_ATTRIBUTES, @disk_attributes, sizeof(disk_attributes), NIL, 0, dw, NIL) + And (GetLastError <> ERROR_INVALID_FUNCTION) then + begin + OutputDebugString('Cannot set disk in writable online mode'); + end; + DeviceIoControl(disk, FSCTL_ALLOW_EXTENDED_DASD_IO, NIL, 0, NIL, 0, dw, NIL); + + disk_size := 0; + mustFormat:=True; + if DeviceIoControl(disk, IOCTL_DISK_GET_LENGTH_INFO, NIL, 0, @disk_size, sizeof(disk_size), dw, NIL) then + begin + if disk_size <> config.size then + begin + OutputDebugString(PAnsiChar('Disk ' + devPath + ' has unexpected size: ' + IntToStr(disk_size))); + mustFormat := False; + end; + end + else if GetLastError <> ERROR_INVALID_FUNCTION then + begin + dw:=GetLastError; + OutputDebugString(PAnsiChar('Can not query size of disk ' + devPath + ': ' + SysErrorMessage(dw))); + mustFormat := False; + end; + if mustFormat then + begin + rand_seed := GetTickCount(); + while true do + begin + ZeroMemory(@drive_layout,SizeOf(drive_layout)); + drive_layout.Signature := RtlRandom(@rand_seed); + drive_layout.PartitionCount := 1; + drive_layout.PartitionEntry[0].StartingOffset.QuadPart := 1048576; + drive_layout.PartitionEntry[0].PartitionLength.QuadPart := + create_data.Fields.DiskSize - + drive_layout.PartitionEntry[0].StartingOffset.QuadPart; + drive_layout.PartitionEntry[0].PartitionNumber := 1; + drive_layout.PartitionEntry[0].PartitionType := PARTITION_IFS; + drive_layout.PartitionEntry[0].BootIndicator := TRUE; + drive_layout.PartitionEntry[0].RecognizedPartition := TRUE; + drive_layout.PartitionEntry[0].RewritePartition := TRUE; + + if DeviceIoControl(disk, IOCTL_DISK_SET_DRIVE_LAYOUT, @drive_layout, sizeof(drive_layout), NIL, 0, dw, NIL) then Break; + if GetLastError <> ERROR_WRITE_PROTECT then + begin + CloseHandle(disk); + Raise ERamDiskError.Create(RamCantFormat); + end; + + //printf("Disk not yet ready, waiting... %c\r", NextWaitChar(&wait_char)); + + ZeroMemory(@disk_attributes, sizeof(disk_attributes)); + disk_attributes.AttributesMask := DISK_ATTRIBUTE_OFFLINE or DISK_ATTRIBUTE_READ_ONLY; + + if Not DeviceIoControl(disk, IOCTL_DISK_SET_DISK_ATTRIBUTES, @disk_attributes, sizeof(disk_attributes), NIL, 0, dw, NIL) then Sleep(400) + else Sleep(0); + end; + end; + + if not DeviceIoControl(disk, IOCTL_DISK_UPDATE_PROPERTIES, NIL, 0, NIL, 0, dw, NIL) + And (GetLastError <> ERROR_INVALID_FUNCTION) then OutputDebugString('Error updating disk properties'); + CloseHandle(disk); + start_time := GetTickCount(); + formatDone := false; + numVolumes:=0; + while true do + begin + volume := FindFirstVolume(volumeName, Length(volumeName)); + if volume = INVALID_HANDLE_VALUE then + begin + OutputDebugString('Error enumerating disk volumes'); + raise ERamDiskError.Create(RamCantEnumDrives); + End; + + MountPoint:=config.letter+':\'; + mountList:=TStringList.Create; + try + repeat + volumeName[48] := #0; + volHandle := CreateFile(volumeName, 0, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + if volHandle = INVALID_HANDLE_VALUE then Continue; + if not ImScsiVolumeUsesDisk(volHandle, diskNumber) then + begin + CloseHandle(volHandle); + continue; + end; + + CloseHandle(volHandle); + Inc(numVolumes); + + volHandle := CreateFile(volumeName, GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + if volHandle = INVALID_HANDLE_VALUE then OutputDebugString('Error opening volume in read/write mode') + else + begin + if Not DeviceIoControl(volHandle, IOCTL_VOLUME_ONLINE, NIL, 0, NIL, 0, dw, NIL) then + begin + OutputDebugString('Error setting volume in online mode'); + end; + CloseHandle(volHandle); + end; + + if mustFormat then + begin + formatDone := true; + if ShowProgress then ShowInfo('Formatting ...'); + // https://wreckorwalker.wordpress.com/2014/06/30/how-to-format-a-raw-disk-in-windows-by-c/ + // https://webcache.googleusercontent.com/search?q=cache:SY0k8D6vIxIJ:https://msmania.wordpress.com/tag/ivdsdisk/+&cd=21&hl=bg&ct=clnk&gl=bg + // we use the undocumented FMIFS.DLL instead of Format.COM or VDS or WMI or ShFormatDrive - it always takes at least 5 seconds + formatDriveName:=volumeName; + FormatEx(PWideChar(formatDriveName),FMIFS_HARDDISK,'NTFS','RAMDISK',True,4096,@FormatCallBack); + if ShowProgress then HideInfo; + end; + + volumeName[48] := '\'; + if Not GetVolumePathNamesForVolumeName(volumeName, mountName, Length(mountName), dw) then + begin + OutputDebugString('Error enumerating mount points'); + continue; + end; + + mount_point_found := false; + for i:=Low(mountName) to High(mountName) do + If mountName[i] = #0 then mountName[i] := #13; + mountList.Text:=mountName; + for i:=0 to mountList.Count-1 do + begin + if mountList[i] = '' then Break; + if CompareText(mountPoint,mountList[i])<>0 then + begin + if Not DeleteVolumeMountPoint(PAnsiChar(mountList[i])) then + begin + dw:=GetLastError; + OutputDebugString(PAnsiChar('Error removing old mount point "'+mountList[i]+'": ' + SysErrorMessage(dw))); + end; + end + else + begin + mount_point_found := true; + // ImScsiOemPrintF(stdout, " Mounted at %1!ws!", mnt); + end; + end; + if (MountPoint <> '') and ((MountPoint <> '#:\') or not mount_point_found) then + begin + if MountPoint = '#:\' then + begin + MountPoint[1] := ImDiskFindFreeDriveLetter(); + if MountPoint[1] = #0 then raise ERamDiskError.Create(RamNoFreeLetter) + Else config.letter:=MountPoint[1]; + end; + if not SetVolumeMountPoint(PAnsiChar(MountPoint), volumeName) then + begin + dw:=GetLastError; + OutputDebugString(PAnsiChar('Error setting volume ' + volumeName + ' mount point to ' + MountPoint + ' : ' + SysErrorMessage(dw))); + end + else Break; + //MountPoint := ''; + end; + Until not FindNextVolume(volume, volumeName, Length(volumeName)); + finally + mountList.Free; + end; + FindVolumeClose(volume); + + if formatDone or (numVolumes > 0) then break; + if not mustFormat and ((GetTickCount() - start_time) > 3000) then + begin + OutputDebugString('No volumes attached. Disk could be offline or not partitioned.'); + break; + end; + + //printf("Volume not yet attached, waiting... %c\r", NextWaitChar(&wait_char)); + Sleep(200); + end; + LoadRamDisk(config); + Result:=True; +end; + +end. diff --git a/RamDetect.pas b/RamDetect.pas new file mode 100644 index 0000000..1ec436f --- /dev/null +++ b/RamDetect.pas @@ -0,0 +1,112 @@ +unit RamDetect; + +interface + +uses Windows, SysUtils, Definitions; + +function GetRamDisk(var existing:TRamDisk): Boolean; + +implementation + +Uses RamVolume; + +procedure RtlInitUnicodeString(DestinationString: PUnicodeString; SourceString: LPWSTR); stdcall; external 'ntdll.dll'; +function NtClose(_Handle: THandle): NTSTATUS; stdcall; external 'ntdll.dll'; + +Function GetRamDisk(var existing:TRamDisk):Boolean; +var + device: TDeviceNumber; + address: TScsiAddress; + adapter: THandle; + config: TScsiDeviceConfig; +Begin + Result:=False; + // check for existing RAMdisk + adapter := ImScsiOpenScsiAdapter(address.PortNumber); + if adapter = INVALID_HANDLE_VALUE then Exit; + CloseHandle(adapter); + adapter := ImScsiOpenScsiAdapterByScsiPortNumber(address.PortNumber); + If adapter = INVALID_HANDLE_VALUE then Exit; + device.LongNumber := 0; + config.DeviceNumber:=device; + If not ImScsiQueryDevice(adapter, @config, SizeOf(TScsiDeviceConfig)) Then + Begin + // no such device + CloseHandle(adapter); + Exit; + end; + existing.size:=config.DiskSize; + // now enumerate disk volumes to find the drive letter + CloseHandle(adapter); + existing.letter:=GetRamDiskLetter(device,address.PortNumber,existing); + Result:=True; +end; +{ +Function ImScsiGetScsiAddressForDisk(Device:THandle; ScsiAddress:PScsiAddress):Boolean; +var + dw:DWORD; + deviceNumber:TStorageDeviceNumber; +Begin + Result:=False; + if DeviceIoControl(Device, IOCTL_STORAGE_GET_DEVICE_NUMBER, NIL, 0, @deviceNumber, sizeof(deviceNumber), dw, NIL) then + if (deviceNumber.DeviceType = FILE_DEVICE_DISK) and (deviceNumber.PartitionNumber > 0) then + Result:=DeviceIoControl(Device, IOCTL_SCSI_GET_ADDRESS, NIL, 0, ScsiAddress, sizeof(TScsiAddress), dw, NIL); +end; + +Function ImScsiGetScsiAddressesForVolume(Volume:THandle; ScsiAddresses:PArrayScsiAddress; itemCount:Cardinal; Var NeededItemCount:Cardinal):Boolean; +var + dw:DWORD; + i:DWORD; + disk:THandle; + address:TScsiAddress; + diskPath:string; + disk_extents:Array of TDiskExtent; +Begin + Result:=False; + SetLength(disk_extents,itemCount); + if not DeviceIoControl(Volume, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NIL, 0, + disk_extents, Length(disk_extents) * SizeOf(TDiskExtent), dw, NIL) then Exit; + NeededItemCount := 0; + i:=0; + While (i < itemCount) and (i * SizeOf(TDiskExtent) < dw) do + begin + diskPath:=Format('\\?\PhysicalDrive%u',[disk_extents[i].DiskNumber]); + disk := CreateFile(PAnsiChar(diskPath), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + + if disk = INVALID_HANDLE_VALUE Then Exit; + if not ImScsiGetScsiAddressForDisk(disk, @address) then + begin + CloseHandle(disk); + Exit; + end; + CloseHandle(disk); + + if NeededItemCount < itemCount then ScsiAddresses[NeededItemCount] := address; + Inc(NeededItemCount); + Inc(i); + end; + + if NeededItemCount > itemCount then + begin + // SetLastError(ERROR_MORE_DATA); + Exit; + end; + Result:=True; +end; + +Function ImScsiRemoveDeviceByNumber(adapter: THandle; var DeviceNumber:TDeviceNumber):Boolean; +var + dw: DWORD; + removeDev: TScsiRemoveDevice; +Begin + ImScsiInitializeSrbIoBlock(removeDev.SrbIoControl, sizeof(TScsiRemoveDevice), SMP_IMSCSI_REMOVE_DEVICE, 0); + removeDev.DeviceNumber := DeviceNumber; + if not ImScsiDeviceIoControl(Adapter, SMP_IMSCSI_REMOVE_DEVICE, removeDev.SrbIoControl, sizeof(removeDev), 0, dw) then + begin + // ImScsiMsgBoxLastError(hWnd, L"Error removing virtual disk:"); + Result:=False; + end + else Result:=True; +end; +} +end. diff --git a/RamRemove.pas b/RamRemove.pas new file mode 100644 index 0000000..264a01f --- /dev/null +++ b/RamRemove.pas @@ -0,0 +1,168 @@ +unit RamRemove; + +interface + +Uses Definitions; + +Function DetachRamDisk (Var existing:TRamDisk):Boolean; + +implementation + +uses SysUtils,Windows,Messages,RamSync; + +function OpenVolume(ADrive: char): THandle; +var + VolumeName: string; +begin + VolumeName := Format('\\.\%s:', [ADrive]); + Result := CreateFile(PChar(VolumeName), GENERIC_READ or GENERIC_WRITE, + FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); +end; + +function PreventRemovalOfVolume(AVolumeHandle: THandle; APreventRemoval: boolean): boolean; +var + BytesReturned: Cardinal; + PreventMediaRemoval: BOOL; +begin + PreventMediaRemoval := APreventRemoval; + Result := DeviceIoControl(AVolumeHandle, IOCTL_STORAGE_MEDIA_REMOVAL, + @PreventMediaRemoval, SizeOf(PreventMediaRemoval), nil, 0, BytesReturned, nil); +end; + +function AutoEjectVolume(AVolumeHandle: THandle): boolean; +var + BytesReturned: Cardinal; +begin + Result := DeviceIoControl(AVolumeHandle, IOCTL_STORAGE_EJECT_MEDIA, nil, 0, nil, 0, BytesReturned, nil); +end; + +Procedure ImDiskNotifyRemovePending(DriveLetter:WideChar); +var + dwp: DWORD; + devBroadcastVol: TDevBroadcastVolume; +Begin + devBroadcastVol.dbch_size:=SizeOf(devBroadcastVol); + devBroadcastVol.dbch_devicetype:=DBT_DEVTYP_VOLUME; + devBroadcastVol.dbcv_unitmask:=1 shl (Ord(DriveLetter) - Ord('A')); + + SendMessageTimeout(HWND_BROADCAST, + WM_DEVICECHANGE, + DBT_DEVICEQUERYREMOVE, + Integer(@devBroadcastVol), + SMTO_BLOCK or SMTO_ABORTIFHUNG, + 4000, + dwp); + + SendMessageTimeout(HWND_BROADCAST, + WM_DEVICECHANGE, + DBT_DEVICEREMOVEPENDING, + Integer(@devBroadcastVol), + SMTO_BLOCK or SMTO_ABORTIFHUNG, + 4000, + dwp); +end; + +Function ImScsiRemoveDeviceByNumber(hWnd, adapter: THandle; DeviceNumber: TDeviceNumber):Boolean; +Var + dw: DWORD; + remove_device: TScsiRemoveDevice; +begin + ImScsiInitializeSrbIoBlock(remove_device.SrbIoControl, sizeof(TScsiRemoveDevice), SMP_IMSCSI_REMOVE_DEVICE, 0); + remove_device.DeviceNumber := DeviceNumber; + + if Not ImScsiDeviceIoControl(Adapter, SMP_IMSCSI_REMOVE_DEVICE, remove_device.SrbIoControl, sizeof(remove_device), 0, dw) then + begin + //ImScsiMsgBoxLastError(hWnd, L"Error removing virtual disk:"); + Result:=FALSE; + End + else Result:=TRUE; +end; + +Function DetachRamDisk(var existing:TRamDisk):Boolean; +var + device,adapter: THandle; + tmp: Integer; + dw: DWORD; + deviceNumber: TDeviceNumber; + portNumber: Byte; + forceDismount: Boolean; +Begin + Result:=False; + If existing.letter = #0 Then + Begin + adapter := ImScsiOpenScsiAdapter(portNumber); + if adapter = INVALID_HANDLE_VALUE then + begin + dw:=GetLastError; + if dw = ERROR_FILE_NOT_FOUND then OutputDebugString('Arsenal Driver not installed') + else OutputDebugString(PAnsiChar(SysErrorMessage(dw))); + raise ERamDiskError.Create(RamNotInstalled); + end; + deviceNumber.LongNumber:=IMSCSI_ALL_DEVICES; + if not ImScsiRemoveDeviceByNumber(0, adapter, DeviceNumber) then + begin + dw:=GetLastError; + if dw = ERROR_FILE_NOT_FOUND then + begin + OutputDebugString('No devices found'); + Exit; + end + else + begin + OutputDebugString(PAnsiChar(SysErrorMessage(dw))); + Exit; + end; + end; + Result:=True; + Exit; + end; + if existing.synchronize And (existing.persistentFolder<>'') then SaveRamDisk(existing); + forceDismount:=False; + device := OpenVolume(existing.letter); + if device = INVALID_HANDLE_VALUE then + begin + case GetLastError of + ERROR_INVALID_PARAMETER: + // "This version of Windows only supports drive letters as mount points.\n" + // "Windows 2000 or higher is required to support subdirectory mount points.\n", + Exit; + ERROR_INVALID_FUNCTION: + // "Mount points are only supported on NTFS volumes.\n", + Exit; + ERROR_NOT_A_REPARSE_POINT, + ERROR_DIRECTORY, + ERROR_DIR_NOT_EMPTY: + // ImScsiOemPrintF(stderr, "Not a mount point: '%1!ws!'", MountPoint); + Exit; + else + tmp:=GetLastError; + raise Exception.Create(SysErrorMessage(tmp)); + end; + End; + // Notify processes that this device is about to be removed. + ImDiskNotifyRemovePending(WideChar(existing.letter)); + FlushFileBuffers(device); + + // Locking volume + try + if Not DeviceIoControl(device, FSCTL_LOCK_VOLUME, NIL, 0, NIL, 0, dw, NIL) then forceDismount := TRUE; + // Unmounting filesystem + try + if DeviceIoControl(device, FSCTL_DISMOUNT_VOLUME, NIL, 0, NIL, 0, dw, NIL) then + begin + if forceDismount then DeviceIoControl(device, FSCTL_LOCK_VOLUME, NIL, 0, NIL, 0, dw, NIL); + // Set prevent removal to false and eject the volume + if PreventRemovalOfVolume(device, FALSE) then AutoEjectVolume(device); + Result:=True; + end; + finally + DeviceIoControl(device, FSCTL_UNLOCK_VOLUME, NIL, 0, NIL, 0, dw, NIL); + End; + finally + CloseHandle(device); + end; + RestoreTempFolder(WideChar(existing.letter)); // MUST be before UpdateDismounted because it will clear the Letter +end; + +end. + \ No newline at end of file diff --git a/RamService.cfg b/RamService.cfg new file mode 100644 index 0000000..224f349 --- /dev/null +++ b/RamService.cfg @@ -0,0 +1,38 @@ +-$A8 +-$B- +-$C+ +-$D+ +-$E- +-$F- +-$G+ +-$H+ +-$I+ +-$J- +-$K- +-$L+ +-$M- +-$N+ +-$O+ +-$P+ +-$Q- +-$R- +-$S- +-$T- +-$U- +-$V+ +-$W- +-$X+ +-$YD +-$Z1 +-cg +-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +-H+ +-W+ +-M +-$M16384,1048576 +-K$00400000 +-LE"c:\program files (x86)\borland\delphi7\..\Bpl" +-LN"c:\program files (x86)\borland\delphi7\..\Bpl" +-w-UNSAFE_TYPE +-w-UNSAFE_CODE +-w-UNSAFE_CAST diff --git a/RamService.dof b/RamService.dof new file mode 100644 index 0000000..8550fed --- /dev/null +++ b/RamService.dof @@ -0,0 +1,623 @@ +[FileVersion] +Version=7.0 +[Compiler] +A=8 +B=0 +C=1 +D=1 +E=0 +F=0 +G=1 +H=1 +I=1 +J=0 +K=0 +L=1 +M=0 +N=1 +O=1 +P=1 +Q=0 +R=0 +S=0 +T=0 +U=0 +V=1 +W=0 +X=1 +Y=1 +Z=1 +ShowHints=1 +ShowWarnings=1 +UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +NamespacePrefix= +SymbolDeprecated=1 +SymbolLibrary=1 +SymbolPlatform=1 +UnitLibrary=1 +UnitPlatform=1 +UnitDeprecated=1 +HResultCompat=1 +HidingMember=1 +HiddenVirtual=1 +Garbage=1 +BoundsError=1 +ZeroNilCompat=1 +StringConstTruncated=1 +ForLoopVarVarPar=1 +TypedConstVarPar=1 +AsgToTypedConst=1 +CaseLabelRange=1 +ForVariable=1 +ConstructingAbstract=1 +ComparisonFalse=1 +ComparisonTrue=1 +ComparingSignedUnsigned=1 +CombiningSignedUnsigned=1 +UnsupportedConstruct=1 +FileOpen=1 +FileOpenUnitSrc=1 +BadGlobalSymbol=1 +DuplicateConstructorDestructor=1 +InvalidDirective=1 +PackageNoLink=1 +PackageThreadVar=1 +ImplicitImport=1 +HPPEMITIgnored=1 +NoRetVal=1 +UseBeforeDef=1 +ForLoopVarUndef=1 +UnitNameMismatch=1 +NoCFGFileFound=1 +MessageDirective=1 +ImplicitVariants=1 +UnicodeToLocale=1 +LocaleToUnicode=1 +ImagebaseMultiple=1 +SuspiciousTypecast=1 +PrivatePropAccessor=1 +UnsafeType=0 +UnsafeCode=0 +UnsafeCast=0 +[Linker] +MapFile=0 +OutputObjs=0 +ConsoleApp=1 +DebugInfo=0 +RemoteSymbols=0 +MinStackSize=16384 +MaxStackSize=1048576 +ImageBase=4194304 +ExeDescription= +[Directories] +OutputDir= +UnitOutputDir= +PackageDLLOutputDir= +PackageDCPOutputDir= +SearchPath= +Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;vcldb;dsnapcon;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;dclOfficeXP;localizer7;EmbeddedWebBrowser_D7;EzBasic;EzSpecials;TMSUnicodeD7;EzPlanIT;KGrid_R7;tb2k_d7;RVHTMLD7;dclusr;rxctl;kprocs7;Misc;TBX_D7;llPDFLibD7;frxe7;frx7;frxDB7;frxTee7;fs7;fsTee7;NiceGridD7;TBXTaskBar_D7;TwoDesk_D7R;vc2;xhCntrls70;xhStd70;xhChart70;xhExport70;RaizeComponentsVcl;HotKeyMan;siplib7;kbmMemRunD7Pro;OverbyteIcsD7Run;NativeExcelD7;SpTBXTaskBar_D7;SpTBXLib_d7;RVword;tntExtendedEditors;VirtualTreesD7;VSTEditors;VirtualShellToolsD7;EasyListviewD7;GLvis;KZ;prgInternet6;XLS_ReadWrite;sgGrpVw7;zDesign7;EhLib70;GR32_DSGN_D7;GR32_D7;NxTBX;NxCollectionRun;NxCommonRun;clinetsuited7;EJ100R70;CodeSiteLoggingVcl;CodeSiteDBToolsVcl +Conditionals= +DebugSourceDirs= +UsePackages=0 +[Parameters] +RunParams= +HostApplication= +Launcher= +UseLauncher=0 +DebugCWD= +[Language] +ActiveLang= +ProjectLang= +RootDir=C:\Program Files (x86)\Borland\Delphi7\Bin\ +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=0 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1026 +CodePage=1251 +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.0 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= +[Excluded Packages] +C:\Program Files (x86)\Borland\Delphi7\Bin\indy70.bpl=Internet Direct (Indy) for D7 +c:\Program Files (x86)\Borland\Bpl\kctrls6.bpl=KStringGrid component +[Exception Log] +EurekaLog Version=6105 +Activate=0 +Activate Handle=1 +Save Log File=1 +Foreground Tab=0 +Freeze Activate=0 +Freeze Timeout=60 +SMTP From=eurekalog@email.com +SMTP Host= +SMTP Port=25 +SMTP UserID= +SMTP Password= +Append to Log=0 +TerminateBtn Operation=2 +Errors Number=32 +Errors Terminate=3 +Email Address= +Email Object= +Email Send Options=0 +Output Path= +Encrypt Password= +AutoCloseDialogSecs=0 +WebSendMode=0 +SupportULR= +HTMLLayout Count=15 +HTMLLine0="%3Chtml%3E" +HTMLLine1=" %3Chead%3E" +HTMLLine2=" %3C/head%3E" +HTMLLine3=" %3Cbody TopMargin=10 LeftMargin=10%3E" +HTMLLine4=" %3Ctable width="100%%" border="0"%3E" +HTMLLine5=" %3Ctr%3E" +HTMLLine6=" %3Ctd nowrap%3E" +HTMLLine7=" %3Cfont face="Lucida Console, Courier" size="2"%3E" +HTMLLine8=" %3C%%HTML_TAG%%%3E" +HTMLLine9=" %3C/font%3E" +HTMLLine10=" %3C/td%3E" +HTMLLine11=" %3C/tr%3E" +HTMLLine12=" %3C/table%3E" +HTMLLine13=" %3C/body%3E" +HTMLLine14="%3C/html%3E" +AutoCrashOperation=2 +AutoCrashNumber=10 +AutoCrashMinutes=1 +WebURL= +WebUserID= +WebPassword= +WebPort=0 +AttachedFiles= +ProxyURL= +ProxyUser= +ProxyPassword= +ProxyPort=8080 +TrakerUser= +TrakerPassword= +TrakerAssignTo= +TrakerProject= +TrakerCategory= +TrakerTrialID= +ZipPassword= +PreBuildEvent= +PostSuccessfulBuildEvent= +PostFailureBuildEvent= +ExceptionDialogType=2 +Count=0 +EMail Message Line Count=0 +loNoDuplicateErrors=0 +loAppendReproduceText=0 +loDeleteLogAtVersionChange=0 +loAddComputerNameInLogFileName=0 +loSaveModulesAndProcessesSections=1 +loSaveAssemblerAndCPUSections=1 +soAppStartDate=1 +soAppName=1 +soAppVersionNumber=1 +soAppParameters=1 +soAppCompilationDate=1 +soAppUpTime=1 +soExcDate=1 +soExcAddress=1 +soExcModuleName=1 +soExcModuleVersion=1 +soExcType=1 +soExcMessage=1 +soExcID=1 +soExcCount=1 +soExcStatus=1 +soExcNote=1 +soUserID=1 +soUserName=1 +soUserEmail=1 +soUserPrivileges=1 +soUserCompany=1 +soActCtlsFormClass=1 +soActCtlsFormText=1 +soActCtlsControlClass=1 +soActCtlsControlText=1 +soCmpName=1 +soCmpTotalMemory=1 +soCmpFreeMemory=1 +soCmpTotalDisk=1 +soCmpFreeDisk=1 +soCmpSysUpTime=1 +soCmpProcessor=1 +soCmpDisplayMode=1 +soCmpDisplayDPI=1 +soCmpVideoCard=1 +soCmpPrinter=1 +soOSType=1 +soOSBuildN=1 +soOSUpdate=1 +soOSLanguage=1 +soOSCharset=1 +soNetIP=1 +soNetSubmask=1 +soNetGateway=1 +soNetDNS1=1 +soNetDNS2=1 +soNetDHCP=1 +soCustomData=1 +sndShowSendDialog=1 +sndShowSuccessFailureMsg=0 +sndSendEntireLog=0 +sndSendXMLLogCopy=0 +sndSendScreenshot=1 +sndUseOnlyActiveWindow=0 +sndSendLastHTMLPage=1 +sndSendInSeparatedThread=0 +sndAddDateInFileName=0 +sndAddComputerNameInFileName=0 +edoSendErrorReportChecked=1 +edoAttachScreenshotChecked=1 +edoShowCopyToClipOption=1 +edoShowDetailsButton=1 +edoShowInDetailedMode=0 +edoShowInTopMostMode=0 +edoUseEurekaLogLookAndFeel=0 +edoShowSendErrorReportOption=1 +edoShowAttachScreenshotOption=1 +edoShowCustomButton=0 +csoShowDLLs=1 +csoShowBPLs=1 +csoShowBorlandThreads=1 +csoShowWindowsThreads=1 +csoDoNotStoreProcNames=0 +boPauseBorlandThreads=0 +boDoNotPauseMainThread=0 +boPauseWindowsThreads=0 +boUseMainModuleOptions=1 +boCopyLogInCaseOfError=1 +boSaveCompressedCopyInCaseOfError=0 +boHandleSafeCallExceptions=1 +boCallRTLExceptionEvent=0 +boCatchHandledExceptions=0 +loCatchLeaks=0 +loGroupsSonLeaks=1 +loHideBorlandLeaks=1 +loFreeAllLeaks=1 +loCatchLeaksExceptions=1 +cfoReduceFileSize=1 +cfoCheckFileCorruption=0 +cfoUseEL7=0 +Count mtInformationMsgCaption=1 +mtInformationMsgCaption0="Information." +Count mtQuestionMsgCaption=1 +mtQuestionMsgCaption0="Question." +Count mtErrorMsgCaption=1 +mtErrorMsgCaption0="Error." +Count mtDialog_Caption=1 +mtDialog_Caption0="Error occurred" +Count mtDialog_ErrorMsgCaption=2 +mtDialog_ErrorMsgCaption0="An error has occurred during program execution." +mtDialog_ErrorMsgCaption1="Please read the following information for further details." +Count mtDialog_GeneralCaption=1 +mtDialog_GeneralCaption0="General" +Count mtDialog_GeneralHeader=1 +mtDialog_GeneralHeader0="General Information" +Count mtDialog_CallStackCaption=1 +mtDialog_CallStackCaption0="Call Stack" +Count mtDialog_CallStackHeader=1 +mtDialog_CallStackHeader0="Call Stack Information" +Count mtDialog_ModulesCaption=1 +mtDialog_ModulesCaption0="Modules" +Count mtDialog_ModulesHeader=1 +mtDialog_ModulesHeader0="Modules Information" +Count mtDialog_ProcessesCaption=1 +mtDialog_ProcessesCaption0="Processes" +Count mtDialog_ProcessesHeader=1 +mtDialog_ProcessesHeader0="Processes Information" +Count mtDialog_AsmCaption=1 +mtDialog_AsmCaption0="Assembler" +Count mtDialog_AsmHeader=1 +mtDialog_AsmHeader0="Assembler Information" +Count mtDialog_CPUCaption=1 +mtDialog_CPUCaption0="CPU" +Count mtDialog_CPUHeader=1 +mtDialog_CPUHeader0="CPU Information" +Count mtDialog_OKButtonCaption=1 +mtDialog_OKButtonCaption0="%26OK" +Count mtDialog_TerminateButtonCaption=1 +mtDialog_TerminateButtonCaption0="%26Terminate" +Count mtDialog_RestartButtonCaption=1 +mtDialog_RestartButtonCaption0="%26Restart" +Count mtDialog_DetailsButtonCaption=1 +mtDialog_DetailsButtonCaption0="%26Details" +Count mtDialog_CustomButtonCaption=1 +mtDialog_CustomButtonCaption0="%26Help" +Count mtDialog_SendMessage=1 +mtDialog_SendMessage0="%26Send this error via Internet" +Count mtDialog_ScreenshotMessage=1 +mtDialog_ScreenshotMessage0="%26Attach a Screenshot image" +Count mtDialog_CopyMessage=1 +mtDialog_CopyMessage0="%26Copy to Clipboard" +Count mtDialog_SupportMessage=1 +mtDialog_SupportMessage0="Go to the Support Page" +Count mtMSDialog_ErrorMsgCaption=1 +mtMSDialog_ErrorMsgCaption0="The application has encountered a problem. We are sorry for the inconvenience." +Count mtMSDialog_RestartCaption=1 +mtMSDialog_RestartCaption0="Restart application." +Count mtMSDialog_TerminateCaption=1 +mtMSDialog_TerminateCaption0="Terminate application." +Count mtMSDialog_PleaseCaption=1 +mtMSDialog_PleaseCaption0="Please tell us about this problem." +Count mtMSDialog_DescriptionCaption=1 +mtMSDialog_DescriptionCaption0="We have created an error report that you can send to us. We will treat this report as confidential and anonymous." +Count mtMSDialog_SeeDetailsCaption=1 +mtMSDialog_SeeDetailsCaption0="To see what data the error report contains," +Count mtMSDialog_SeeClickCaption=1 +mtMSDialog_SeeClickCaption0="click here." +Count mtMSDialog_HowToReproduceCaption=1 +mtMSDialog_HowToReproduceCaption0="What were you doing when the problem happened (optional)?" +Count mtMSDialog_EmailCaption=1 +mtMSDialog_EmailCaption0="Email address (optional):" +Count mtMSDialog_SendButtonCaption=1 +mtMSDialog_SendButtonCaption0="%26Send Error Report" +Count mtMSDialog_NoSendButtonCaption=1 +mtMSDialog_NoSendButtonCaption0="%26Don't Send" +Count mtLog_AppHeader=1 +mtLog_AppHeader0="Application" +Count mtLog_AppStartDate=1 +mtLog_AppStartDate0="Start Date" +Count mtLog_AppName=1 +mtLog_AppName0="Name/Description" +Count mtLog_AppVersionNumber=1 +mtLog_AppVersionNumber0="Version Number" +Count mtLog_AppParameters=1 +mtLog_AppParameters0="Parameters" +Count mtLog_AppCompilationDate=1 +mtLog_AppCompilationDate0="Compilation Date" +Count mtLog_AppUpTime=1 +mtLog_AppUpTime0="Up Time" +Count mtLog_ExcHeader=1 +mtLog_ExcHeader0="Exception" +Count mtLog_ExcDate=1 +mtLog_ExcDate0="Date" +Count mtLog_ExcAddress=1 +mtLog_ExcAddress0="Address" +Count mtLog_ExcModuleName=1 +mtLog_ExcModuleName0="Module Name" +Count mtLog_ExcModuleVersion=1 +mtLog_ExcModuleVersion0="Module Version" +Count mtLog_ExcType=1 +mtLog_ExcType0="Type" +Count mtLog_ExcMessage=1 +mtLog_ExcMessage0="Message" +Count mtLog_ExcID=1 +mtLog_ExcID0="ID" +Count mtLog_ExcCount=1 +mtLog_ExcCount0="Count" +Count mtLog_ExcStatus=1 +mtLog_ExcStatus0="Status" +Count mtLog_ExcNote=1 +mtLog_ExcNote0="Note" +Count mtLog_UserHeader=1 +mtLog_UserHeader0="User" +Count mtLog_UserID=1 +mtLog_UserID0="ID" +Count mtLog_UserName=1 +mtLog_UserName0="Name" +Count mtLog_UserEmail=1 +mtLog_UserEmail0="Email" +Count mtLog_UserCompany=1 +mtLog_UserCompany0="Company" +Count mtLog_UserPrivileges=1 +mtLog_UserPrivileges0="Privileges" +Count mtLog_ActCtrlsHeader=1 +mtLog_ActCtrlsHeader0="Active Controls" +Count mtLog_ActCtrlsFormClass=1 +mtLog_ActCtrlsFormClass0="Form Class" +Count mtLog_ActCtrlsFormText=1 +mtLog_ActCtrlsFormText0="Form Text" +Count mtLog_ActCtrlsControlClass=1 +mtLog_ActCtrlsControlClass0="Control Class" +Count mtLog_ActCtrlsControlText=1 +mtLog_ActCtrlsControlText0="Control Text" +Count mtLog_CmpHeader=1 +mtLog_CmpHeader0="Computer" +Count mtLog_CmpName=1 +mtLog_CmpName0="Name" +Count mtLog_CmpTotalMemory=1 +mtLog_CmpTotalMemory0="Total Memory" +Count mtLog_CmpFreeMemory=1 +mtLog_CmpFreeMemory0="Free Memory" +Count mtLog_CmpTotalDisk=1 +mtLog_CmpTotalDisk0="Total Disk" +Count mtLog_CmpFreeDisk=1 +mtLog_CmpFreeDisk0="Free Disk" +Count mtLog_CmpSystemUpTime=1 +mtLog_CmpSystemUpTime0="System Up Time" +Count mtLog_CmpProcessor=1 +mtLog_CmpProcessor0="Processor" +Count mtLog_CmpDisplayMode=1 +mtLog_CmpDisplayMode0="Display Mode" +Count mtLog_CmpDisplayDPI=1 +mtLog_CmpDisplayDPI0="Display DPI" +Count mtLog_CmpVideoCard=1 +mtLog_CmpVideoCard0="Video Card" +Count mtLog_CmpPrinter=1 +mtLog_CmpPrinter0="Printer" +Count mtLog_OSHeader=1 +mtLog_OSHeader0="Operating System" +Count mtLog_OSType=1 +mtLog_OSType0="Type" +Count mtLog_OSBuildN=1 +mtLog_OSBuildN0="Build #" +Count mtLog_OSUpdate=1 +mtLog_OSUpdate0="Update" +Count mtLog_OSLanguage=1 +mtLog_OSLanguage0="Language" +Count mtLog_OSCharset=1 +mtLog_OSCharset0="Charset" +Count mtLog_NetHeader=1 +mtLog_NetHeader0="Network" +Count mtLog_NetIP=1 +mtLog_NetIP0="IP Address" +Count mtLog_NetSubmask=1 +mtLog_NetSubmask0="Submask" +Count mtLog_NetGateway=1 +mtLog_NetGateway0="Gateway" +Count mtLog_NetDNS1=1 +mtLog_NetDNS10="DNS 1" +Count mtLog_NetDNS2=1 +mtLog_NetDNS20="DNS 2" +Count mtLog_NetDHCP=1 +mtLog_NetDHCP0="DHCP" +Count mtLog_CustInfoHeader=1 +mtLog_CustInfoHeader0="Custom Information" +Count mtCallStack_Address=1 +mtCallStack_Address0="Address" +Count mtCallStack_Name=1 +mtCallStack_Name0="Module" +Count mtCallStack_Unit=1 +mtCallStack_Unit0="Unit" +Count mtCallStack_Class=1 +mtCallStack_Class0="Class" +Count mtCallStack_Procedure=1 +mtCallStack_Procedure0="Procedure/Method" +Count mtCallStack_Line=1 +mtCallStack_Line0="Line" +Count mtCallStack_MainThread=1 +mtCallStack_MainThread0="Main" +Count mtCallStack_ExceptionThread=1 +mtCallStack_ExceptionThread0="Exception Thread" +Count mtCallStack_RunningThread=1 +mtCallStack_RunningThread0="Running Thread" +Count mtCallStack_CallingThread=1 +mtCallStack_CallingThread0="Calling Thread" +Count mtCallStack_ThreadID=1 +mtCallStack_ThreadID0="ID" +Count mtCallStack_ThreadPriority=1 +mtCallStack_ThreadPriority0="Priority" +Count mtCallStack_ThreadClass=1 +mtCallStack_ThreadClass0="Class" +Count mtCallStack_LeakCaption=1 +mtCallStack_LeakCaption0="Memory Leak" +Count mtCallStack_LeakData=1 +mtCallStack_LeakData0="Data" +Count mtCallStack_LeakType=1 +mtCallStack_LeakType0="Type" +Count mtCallStack_LeakSize=1 +mtCallStack_LeakSize0="Total size" +Count mtCallStack_LeakCount=1 +mtCallStack_LeakCount0="Count" +Count mtSendDialog_Caption=1 +mtSendDialog_Caption0="Send." +Count mtSendDialog_Message=1 +mtSendDialog_Message0="Message" +Count mtSendDialog_Resolving=1 +mtSendDialog_Resolving0="Resolving DNS..." +Count mtSendDialog_Login=1 +mtSendDialog_Login0="Login..." +Count mtSendDialog_Connecting=1 +mtSendDialog_Connecting0="Connecting with server..." +Count mtSendDialog_Connected=1 +mtSendDialog_Connected0="Connected with server." +Count mtSendDialog_Sending=1 +mtSendDialog_Sending0="Sending message..." +Count mtSendDialog_Sent=1 +mtSendDialog_Sent0="Message sent." +Count mtSendDialog_SelectProject=1 +mtSendDialog_SelectProject0="Select project..." +Count mtSendDialog_Searching=1 +mtSendDialog_Searching0="Searching..." +Count mtSendDialog_Modifying=1 +mtSendDialog_Modifying0="Modifying..." +Count mtSendDialog_Disconnecting=1 +mtSendDialog_Disconnecting0="Disconnecting..." +Count mtSendDialog_Disconnected=1 +mtSendDialog_Disconnected0="Disconnected." +Count mtReproduceDialog_Caption=1 +mtReproduceDialog_Caption0="Request" +Count mtReproduceDialog_Request=1 +mtReproduceDialog_Request0="Please describe the steps to reproduce the error:" +Count mtReproduceDialog_OKButtonCaption=1 +mtReproduceDialog_OKButtonCaption0="%26OK" +Count mtModules_Handle=1 +mtModules_Handle0="Handle" +Count mtModules_Name=1 +mtModules_Name0="Name" +Count mtModules_Description=1 +mtModules_Description0="Description" +Count mtModules_Version=1 +mtModules_Version0="Version" +Count mtModules_Size=1 +mtModules_Size0="Size" +Count mtModules_LastModified=1 +mtModules_LastModified0="Modified" +Count mtModules_Path=1 +mtModules_Path0="Path" +Count mtProcesses_ID=1 +mtProcesses_ID0="ID" +Count mtProcesses_Name=1 +mtProcesses_Name0="Name" +Count mtProcesses_Description=1 +mtProcesses_Description0="Description" +Count mtProcesses_Version=1 +mtProcesses_Version0="Version" +Count mtProcesses_Memory=1 +mtProcesses_Memory0="Memory" +Count mtProcesses_Priority=1 +mtProcesses_Priority0="Priority" +Count mtProcesses_Threads=1 +mtProcesses_Threads0="Threads" +Count mtProcesses_Path=1 +mtProcesses_Path0="Path" +Count mtCPU_Registers=1 +mtCPU_Registers0="Registers" +Count mtCPU_Stack=1 +mtCPU_Stack0="Stack" +Count mtCPU_MemoryDump=1 +mtCPU_MemoryDump0="Memory Dump" +Count mtSend_SuccessMsg=1 +mtSend_SuccessMsg0="The message was sent successfully." +Count mtSend_FailureMsg=1 +mtSend_FailureMsg0="Sorry, sending the message didn't work." +Count mtSend_BugClosedMsg=2 +mtSend_BugClosedMsg0="These BUG is just closed." +mtSend_BugClosedMsg1="Contact the program support to obtain an update." +Count mtSend_UnknownErrorMsg=1 +mtSend_UnknownErrorMsg0="Unknown error." +Count mtSend_InvalidLoginMsg=1 +mtSend_InvalidLoginMsg0="Invalid login request." +Count mtSend_InvalidSearchMsg=1 +mtSend_InvalidSearchMsg0="Invalid search request." +Count mtSend_InvalidSelectionMsg=1 +mtSend_InvalidSelectionMsg0="Invalid selection request." +Count mtSend_InvalidInsertMsg=1 +mtSend_InvalidInsertMsg0="Invalid insert request." +Count mtSend_InvalidModifyMsg=1 +mtSend_InvalidModifyMsg0="Invalid modify request." +Count mtFileCrackedMsg=2 +mtFileCrackedMsg0="This file is cracked." +mtFileCrackedMsg1="The application will be closed." +Count mtException_LeakMultiFree=1 +mtException_LeakMultiFree0="Multi Free memory leak." +Count mtException_LeakMemoryOverrun=1 +mtException_LeakMemoryOverrun0="Memory Overrun leak." +Count mtException_AntiFreeze=1 +mtException_AntiFreeze0="The application seems to be frozen." +Count mtInvalidEmailMsg=1 +mtInvalidEmailMsg0="Invalid email." +TextsCollection=English + + diff --git a/RamService.dpr b/RamService.dpr new file mode 100644 index 0000000..ff14668 --- /dev/null +++ b/RamService.dpr @@ -0,0 +1,15 @@ +program RamService; + +{$R 'manifest.res' 'manifest.rc'} + +uses + SvcMgr, + SrvMain in 'SrvMain.pas' {ArsenalRamDisk: TServiceArsenal}; + +{$R *.RES} + +begin + Application.Initialize; + Application.CreateForm(TArsenalRamDisk, ArsenalRamDisk); + Application.Run; +end. diff --git a/RamService.manifest b/RamService.manifest new file mode 100644 index 0000000..ccc3aab --- /dev/null +++ b/RamService.manifest @@ -0,0 +1,13 @@ + + + + Arsenal RAM-disk service + + + + + + + + + \ No newline at end of file diff --git a/RamService.res b/RamService.res new file mode 100644 index 0000000..2fddc33 Binary files /dev/null and b/RamService.res differ diff --git a/RamSetup.pas b/RamSetup.pas new file mode 100644 index 0000000..43bc857 --- /dev/null +++ b/RamSetup.pas @@ -0,0 +1,125 @@ +unit RamSetup; + +interface + +Function ImScsiRescanScsiAdapterAsync(AsyncFlag:Boolean):THandle; + +implementation + +uses Windows,SysUtils,Classes; + +const + CfgMgrDllName = 'cfgmgr32.dll'; + SetupApiModuleName = 'SETUPAPI.DLL'; + WT_EXECUTEINPERSISTENTTHREAD = $00000080; + CR_SUCCESS = $00000000; + CM_GETIDLIST_FILTER_SERVICE = $00000002; + +type + DEVINST = DWORD; + DEVINSTID_A = PAnsiChar; + RETURN_TYPE = DWORD; + CONFIGRET = RETURN_TYPE; + TThreadStartFunc = Function (Event:THandle):DWORD; Stdcall; + +function QueueUserWorkItem (func: TThreadStartFunc; Context: Pointer; Flags: DWORD): BOOL; stdcall; external kernel32; +function CM_Locate_DevNode(var dnDevInst: DEVINST; pDeviceID: DEVINSTID_A; ulFlags: ULONG): CONFIGRET; stdcall; external CfgMgrDllName name 'CM_Locate_DevNodeA'; +function CM_Reenumerate_DevNode(var dnDevInst: DEVINST; ulFlags: ULONG): CONFIGRET; stdcall; external CfgMgrDllName; +function CM_Get_Device_ID_List(const pszFilter: PAnsiChar; Buffer: PAnsiChar; BufferLen: ULONG; ulFlags: ULONG): CONFIGRET; stdcall; External CfgMgrDllName name 'CM_Get_Device_ID_ListA'; +function CM_Get_Device_ID_List_Size(var ulLen: ULONG; const pszFilter: PAnsiChar; ulFlags: ULONG): CONFIGRET; stdcall; External CfgMgrDllName name 'CM_Get_Device_ID_List_SizeA'; + +Function ImScsiScanForHardwareChanges(rootid:DEVINSTID_A = Nil; flags:DWORD = 0):DWORD; +Var + dev_inst: DEVINST; + status: DWORD; +begin + status := CM_Locate_DevNode(dev_inst, rootid, 0); + if status <> CR_SUCCESS then + begin + OutputDebugString(PAnsiChar('Error scanning for hardware changes: $' + IntToHex(status,8))); + Result:=status; + end + else Result:=CM_Reenumerate_DevNode(dev_inst, flags); +end; + +Function ImScsiScanForHardwareChangesThread(Event:THandle):DWORD; Stdcall; +begin + ImScsiScanForHardwareChanges; + SetEvent(Event); + Result:=0; +end; + +function ImScsiAllocateDeviceInstanceListForService(service:string;var instances:PAnsiChar):Integer; +var + length,status:DWORD; +Begin + length:=0; + Result:=0; + status := CM_Get_Device_ID_List_Size(length, PAnsiChar(service), CM_GETIDLIST_FILTER_SERVICE); + if status = CR_SUCCESS then + begin + instances := Pointer(LocalAlloc(LMEM_FIXED, sizeof(Char) * length)); + if Not Assigned(instances) then Exit; + status := CM_Get_Device_ID_List(PAnsiChar(service), instances, length, CM_GETIDLIST_FILTER_SERVICE); + if status <> CR_SUCCESS then + begin + LocalFree(Cardinal(instances)); + //ImScsiDebugMessage(L"Error enumerating instances for service %1!ws!: %2!#x!", service, status); + End + Else Result:=length; + end; +end; + +Function ImScsiRescanScsiAdapter:Boolean; +var + i,length:Integer; + hwinstances:PAnsiChar; + status: DWORD; +Begin + hwinstances := NIL; + Result:=False; + Try + length:=ImScsiAllocateDeviceInstanceListForService('phdskmnt', hwinstances); + if length <= 1 Then Exit; + i:=0; + while i < length do + begin + if hwinstances + i = '' Then Continue; + status := ImScsiScanForHardwareChanges(hwinstances + i, 0); + if status = CR_SUCCESS then Result:=True + else + begin + // ImScsiDebugMessage(L"Rescanning of %1 failed: %2!#x!", hwinstances, status); + end; + Inc(i,1 + StrLen(hwinstances + i)); + end; + Finally + LocalFree(Cardinal(hwinstances)); + end; +end; + +Function ImScsiRescanScsiAdapterThread(Event:THandle):DWORD; Stdcall; +begin + ImScsiRescanScsiAdapter; + SetEvent(Event); + Result:=0; +end; + +Function ImScsiRescanScsiAdapterAsync(AsyncFlag:Boolean):THandle; +begin + Result := CreateEvent(NIL, TRUE, FALSE, NIL); + if Result <> 0 then + begin + if AsyncFlag then + begin + if Not QueueUserWorkItem(ImScsiRescanScsiAdapterThread, Pointer(Result), WT_EXECUTEINPERSISTENTTHREAD) then + begin + CloseHandle(Result); + Result:=0; + end; + end + else ImScsiRescanScsiAdapterThread(Result); + end; +end; + +end. diff --git a/RamSync.pas b/RamSync.pas new file mode 100644 index 0000000..d44103a --- /dev/null +++ b/RamSync.pas @@ -0,0 +1,312 @@ +unit RamSync; + +interface + +Uses Definitions; + +procedure LoadRamDisk(Var config:TRamDisk); +procedure SaveRamDisk(Var existing:TRamDisk); +procedure RestoreTempFolder(letter:WideChar); + +implementation + +uses SysUtils,Windows,TntRegistry,TntSysUtils,TntClasses,Junctions; + +const + DIR_ATTR = FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_REPARSE_POINT; + +type + TStrArray = Array of WideString; + TPathList = Array Of TStrArray; + +procedure CopyTime(const src,dest:WideString); +var + hDir:THandle; + creationTime,accessTime,writeTime:TFileTime; +Begin + hDir := CreateFileW(PWideChar(src), 0, FILE_SHARE_READ, NIL, OPEN_EXISTING, 0, 0); + if hDir <> INVALID_HANDLE_VALUE Then + begin + GetFileTime(hDir,@creationTime,@accessTime,@writeTime); + CloseHandle(hDir); + hDir := CreateFileW(PWideChar(dest), GENERIC_WRITE, FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + if hDir <> INVALID_HANDLE_VALUE Then + begin + SetFileTime(hDir,@creationTime,@accessTime,@writeTime); + CloseHandle(hDir); + end; + end; +end; + +procedure TreeCopy(const src,dest:WideString); +var + SR: TSearchRecW; + junction,current,source: WideString; +Begin + if WideFindFirst(src+'*.*',faAnyFile,SR)<>0 then Exit; + repeat + if (SR.Name <> '.') and (SR.Name <> '..') then + begin + //Application.ProcessMessages; + current:=dest + SR.Name; + source:=src + SR.Name; + if (SR.Attr and faDirectory) <> 0 then + begin + WideCreateDir(current); + // check for junction point + if (GetFileAttributesW(PWideChar(source)) and DIR_ATTR) = DIR_ATTR Then + Begin + junction:=GetSymLinkTarget(source); + If junction<>'' Then + Begin + CreateJunction(current, junction); + CopyTime(source,current); + Continue; + end; + end; + TreeCopy(src + SR.Name + '\', dest + SR.Name + '\'); + CopyTime(source,current); + end + else + Begin + CopyFileW(PWideChar(source), PWideChar(current),False); // we don't care if it is a symlink + CopyTime(source,current); + End; + end; + Until WideFindNext(SR) <> 0; + WideFindClose(SR); +end; + +procedure DelTree(const path:String); +var + SR: TSearchRec; +Begin + if FindFirst(path+'*.*',faAnyFile,SR)<>0 then Exit; + Repeat + if (SR.Name <> '.') and (SR.Name <> '..') then + begin + if (SR.Attr and faDirectory) <> 0 then + Begin + DelTree(path + SR.Name + '\'); + RemoveDir(path + SR.Name); + end + else SysUtils.DeleteFile(path + SR.Name); + end; + Until FindNext(SR) <> 0; + SysUtils.FindClose(SR); + RemoveDir(path); +end; + +Procedure LoadRamDisk(Var config:TRamDisk); +Var + reg: TTntRegistry; + tempDir:String; +Begin + If (config.persistentFolder<>'') And DirectoryExists(config.persistentFolder) Then TreeCopy(WideIncludeTrailingPathDelimiter(config.persistentFolder),config.letter+':\'); + If config.useTemp Then + Begin + tempDir:=config.letter+':\TEMP'; + if CreateDir(tempDir) Then + Begin + reg:=Nil; + Try + reg:=TTntRegistry.Create(KEY_WRITE); + reg.RootKey:=HKEY_LOCAL_MACHINE; + if Reg.OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', True) then + Begin + reg.WriteExpandString('TMP',tempDir); + reg.WriteExpandString('TEMP',tempDir); + end; + reg.CloseKey; + + reg.RootKey:=HKEY_CURRENT_USER; + if Reg.OpenKey('Environment', True) then + Begin + reg.WriteExpandString('TMP',tempDir); + reg.WriteExpandString('TEMP',tempDir); + end; + reg.CloseKey; + finally + reg.Free; + end; + end; + end; + // remove $RECYCLE.BIN + DelTree(config.letter+':\$RECYCLE.BIN\'); +end; + +procedure RestoreTempFolder(letter:WideChar); +Var + reg: TTntRegistry; + tmpFolder, tempFolder: String; + tmp:WideString; +Begin + reg:=Nil; + try + reg:=TTntRegistry.Create(KEY_ALL_ACCESS); + // read defaults + reg.RootKey:=HKEY_USERS; + if Reg.OpenKey('.DEFAULT\Environment', False) then + Begin + tmpFolder:=reg.ReadString('TMP'); + tempFolder:=reg.ReadString('TEMP'); + end; + reg.CloseKey; + // set active values + reg.RootKey:=HKEY_LOCAL_MACHINE; + if Reg.OpenKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', True) then + Begin + // restore default only if current setting was using the just unmounted Ramdisk + tmp:=WideUpperCase(reg.ReadString('TMP')); + If (tmp<>'')And(tmp[1] = letter) then reg.WriteExpandString('TMP',tmpFolder); + tmp:=WideUpperCase(reg.ReadString('TEMP')); + If (tmp<>'')and(tmp[1] = letter) then reg.WriteExpandString('TEMP',tempFolder); + end; + reg.CloseKey; + + reg.RootKey:=HKEY_CURRENT_USER; + if Reg.OpenKey('Environment', True) then + Begin + tmp:=WideUpperCase(reg.ReadString('TMP')); + If (tmp<>'')and(tmp[1] = letter) then reg.WriteExpandString('TMP',tmpFolder); + tmp:=WideUpperCase(reg.ReadString('TEMP')); + If (tmp<>'')and(tmp[1] = letter) then reg.WriteExpandString('TEMP',tempFolder); + end; + reg.CloseKey; + finally + reg.Free; + end; +end; + +Function NewerSource(const src,dest:WideString):Boolean; +var + hDir:THandle; + srcCreation,srcAccess,srcModify,destCreation,destAccess,destModify:TFileTime; +Begin + Result:=False; + hDir := CreateFileW(PWideChar(src), 0, FILE_SHARE_READ, NIL, OPEN_EXISTING, 0, 0); + if hDir <> INVALID_HANDLE_VALUE Then + begin + GetFileTime(hDir,@srcCreation,@srcAccess,@srcModify); + CloseHandle(hDir); + hDir := CreateFileW(PWideChar(dest), 0, FILE_SHARE_READ, NIL, OPEN_EXISTING, 0, 0); + if hDir <> INVALID_HANDLE_VALUE Then + begin + GetFileTime(hDir,@destCreation,@destAccess,@destModify); + CloseHandle(hDir); + //-1, Source is older than Destination + //0, Source is the same age as Destination + //+1 Source is younger than Destination + Result:=(CompareFileTime(srcModify,destModify)>0) or (CompareFileTime(srcCreation,destCreation)>0); + end + Else Result:=True; // destination probably does not exist + end; +end; + +// copy from RAM-disk to the persistent folder, excluding disabled paths +procedure TreeSave(const src,dest:WideString;excluded:TTntStringList); +var + SR: TSearchRecW; + junction,current,source: WideString; +Begin + if WideFindFirst(src+'*.*',faAnyFile,SR)<>0 then Exit; + repeat + if (SR.Name <> '.') and (SR.Name <> '..') then + begin + //Application.ProcessMessages; + current:=dest + SR.Name; + source:=src + SR.Name; + if (SR.Attr and faDirectory) <> 0 then + begin + if Assigned(excluded) And (excluded.IndexOf(WideUpperCase(SR.Name)) <> -1) then Continue; + WideCreateDir(current); + // check for junction point + if (GetFileAttributesW(PWideChar(source)) and DIR_ATTR) = DIR_ATTR Then + Begin + junction:=GetSymLinkTarget(source); + If junction<>'' Then + Begin + CreateJunction(current, junction); + Continue; + end; + end; + TreeSave(source + '\', current + '\',Nil); + end + else + Begin + if NewerSource(source,current) then CopyFileW(PWideChar(source), PWideChar(current),False); // overwrite existing + End; + end; + Until WideFindNext(SR) <> 0; + WideFindClose(SR); +end; + +// delete from persistent folder items which are no longer present on the RAM-disk +procedure TreeDelete(const src,dest:WideString;excluded:TTntStringList); +var + SR: TSearchRecW; +Begin + if WideFindFirst(src+'*.*',faAnyFile,SR)<>0 then Exit; + repeat + if (SR.Name <> '.') and (SR.Name <> '..') then + begin + //Application.ProcessMessages; + if (SR.Attr and faDirectory) <> 0 then + begin + if Assigned(excluded) And (excluded.IndexOf(WideUpperCase(SR.Name)) <> -1) then Continue; + TreeDelete(src + SR.Name + '\', dest + SR.Name + '\',Nil); + if not DirectoryExists(dest + SR.Name) then WideRemoveDir(src + SR.Name); + end + else + Begin + if Not FileExists(dest + SR.Name) Then WideDeleteFile(src + SR.Name); + End; + end; + Until WideFindNext(SR) <> 0; + WideFindClose(SR); +end; + +Procedure SplitPath(const path:WideString;var list:TStrArray); +var + oldPos,newPos,k:Integer; +Begin + SetLength(List,Length(path)); + k:=0; + oldPos:=1; + Repeat + newPos:=WidePosEx('\',path,oldPos); + if newPos=0 then list[k]:=Copy(path,oldPos,MaxInt) + Else + Begin + list[k]:=Copy(path,oldPos,newPos); + oldPos:=newPos; + end; + Inc(k); + Until newPos=0; + SetLength(list,k); +end; + +Procedure SaveRamDisk(Var existing:TRamDisk); +var + list:TTntStringList; +Begin + if DirectoryExists(existing.persistentFolder) then + Begin + list:=Nil; + try + list:=TTntStringList.Create; + list.Text:=WideUpperCase(existing.excludedList); + list.Add('TEMP'); // always exclude TEMP folder and system folders + list.Add('$RECYCLE.BIN'); + list.Add('System Volume Information'); + // first we persist RAM-disk, excluding disabled paths + TreeSave(existing.letter+':\',WideIncludeTrailingPathDelimiter(existing.persistentFolder),list); + // then we delete the data that is not present on the RAM-disk + if existing.deleteOld then TreeDelete(WideIncludeTrailingPathDelimiter(existing.persistentFolder),existing.letter+':\',list); + Finally + list.Free; + end; + end; +end; + +end. diff --git a/RamVolume.pas b/RamVolume.pas new file mode 100644 index 0000000..5baf70a --- /dev/null +++ b/RamVolume.pas @@ -0,0 +1,161 @@ +unit RamVolume; + +interface + +uses Windows,Definitions; + +function GetRamDiskLetter(device:TDeviceNumber;portNumber:Cardinal;Var existing:TRamDisk): Char; +Function ImScsiOpenDiskByDeviceNumber(DeviceNumber: TDeviceNumber; PortNumber: DWORD; var DiskNumber: Integer):THandle; + +implementation + +uses Classes,StrUtils,SysUtils; + +function FindFirstVolume(lpszVolumeName: LPSTR; cchBufferLength: DWORD): THANDLE; stdcall; External kernel32 name 'FindFirstVolumeA'; +function FindNextVolume(hFindVolume: THANDLE; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; External kernel32 name 'FindNextVolumeA'; +function FindVolumeClose(hFindVolume: THANDLE): BOOL; stdcall; External kernel32; +function GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames: LPCSTR; cchBufferLength: DWORD; var lpcchReturnLength: DWORD): BOOL; stdcall; External kernel32 name 'GetVolumePathNamesForVolumeNameA'; + +Function ImScsiOpenDiskByDeviceNumber(DeviceNumber: TDeviceNumber; PortNumber: DWORD; var DiskNumber: Integer):THandle; +Const + disk_prefix: WideString = 'PhysicalDrive'; +var + dosdevs: string; + disk, adapter: THandle; + disk_number: Integer; + dw: DWORD; + dev_path: WideString; + config:TScsiDeviceConfig; + i, len: Integer; + devices: TStringList; + address: TScsiAddress; + device_number: TStorageDeviceNumber; + disk_size: Int64; +Begin + SetLength(dosDevs, MAX_DOS_NAMES); + disk_number:= -1; + Result:=INVALID_HANDLE_VALUE; + len:=QueryDosDevice(NIL, PAnsiChar(dosdevs), Length(dosdevs)); + // ImScsiDebugMessage(L"Error opening SCSI port %1!i!: %2!ws!", PortNumber & 0xFF, (LPCWSTR)errmsg); + if len=0 then Exit; + + adapter := ImScsiOpenScsiAdapterByScsiPortNumber(PortNumber); + if adapter = INVALID_HANDLE_VALUE then Exit; + + config.DeviceNumber := DeviceNumber; + If not ImScsiQueryDevice(adapter, @config, SizeOf(TScsiDeviceConfig)) Then + begin + CloseHandle(adapter); + Exit; + end; + CloseHandle(adapter); + + for i:=1 to len Do + if dosDevs[i] = #0 then dosDevs[i]:= #13; + devices:=Nil; + Try + devices:=TStringList.Create; + devices.Text:=dosDevs; + for i:=0 to devices.Count-1 do + Begin + if LeftStr(devices[i],Length(disk_prefix)) <> disk_prefix Then Continue; + if not TryStrToInt(Copy(devices[i],Length(disk_prefix)+1,10), disk_number) then continue; + dev_path := '\\?\' + devices[i]; + disk := CreateFileW(PWideChar(dev_path), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + if disk = INVALID_HANDLE_VALUE then Continue; + if DeviceIoControl(disk, IOCTL_SCSI_GET_ADDRESS, NIL, 0, @address, sizeof(address), dw, NIL) then + Begin + if ((address.PortNumber = PortNumber) and + (address.PathId = DeviceNumber.PathId) and + (address.TargetId = DeviceNumber.TargetId) and + (address.Lun = DeviceNumber.Lun)) then + Begin + if DeviceIoControl(disk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NIL, 0, @device_number, sizeof(device_number), dw, NIL) then + Begin + if ((device_number.DeviceNumber = DWORD(disk_number)) and + (device_number.DeviceType = FILE_DEVICE_DISK) and + (device_number.PartitionNumber = 0)) then + Begin + DeviceIoControl(disk, FSCTL_ALLOW_EXTENDED_DASD_IO, NIL, 0, NIL, 0, dw, NIL); + disk_size := 0; + if DeviceIoControl(disk, IOCTL_DISK_GET_LENGTH_INFO, NIL, 0, @disk_size, sizeof(disk_size), dw, NIL) then + begin + if disk_size = config.DiskSize then + Begin + DiskNumber := disk_number; + Result:=disk; + Exit; + end; + end + end; + end; + end; + end + else Case GetLastError of + ERROR_INVALID_PARAMETER, + ERROR_INVALID_FUNCTION, + ERROR_NOT_SUPPORTED, + ERROR_IO_DEVICE: break; + end; + CloseHandle(disk); + end; + Finally + devices.Free; + end; +end; + +Function GetRamDiskLetter(device:TDeviceNumber;portNumber:Cardinal;Var existing:TRamDisk):Char; +var + adapter, volHandle, volume: THandle; + tmp: DWORD; + address: TScsiAddress; + device_number: TStorageDeviceNumber; + volumeName: Array[0..49] of AnsiChar; + mountName: Array[0..250] Of AnsiChar; +Begin + Result:=#0; + adapter:= ImScsiOpenDiskByDeviceNumber(device, PortNumber, existing.diskNumber); + if adapter <> INVALID_HANDLE_VALUE then + begin + volume := FindFirstVolume(volumeName, Length(volumeName)); + if volume <> INVALID_HANDLE_VALUE then + begin + repeat + volumeName[48] := #0; + volHandle:= CreateFileA(volumeName, 0, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0); + volumeName[48] := '\'; + + if volHandle = INVALID_HANDLE_VALUE then break; + if DeviceIoControl(volHandle, IOCTL_SCSI_GET_ADDRESS, NIL, 0, @address, sizeof(address), tmp, NIL) then + Begin + if ((address.PortNumber = portNumber) and + (address.PathId = device.PathId) and + (address.TargetId = device.TargetId) and + (address.Lun = device.Lun)) then + Begin + if DeviceIoControl(volHandle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NIL, 0, @device_number, sizeof(device_number), tmp, NIL) then + Begin + if (device_number.DeviceNumber = DWORD(existing.diskNumber)) and + (device_number.DeviceType = FILE_DEVICE_DISK) and + (device_number.PartitionNumber > 0) then + Begin + if GetVolumePathNamesForVolumeName(volumeName, mountName, Length(mountName), tmp) then + begin + CloseHandle(volHandle); + existing.volumeName:=volumeName; + Result:=Char(mountName[0]); // mountName is array of ASCIIZ, ending with empty ASCIIZ + Break; + end; + end; + end; + end; + end; + CloseHandle(volHandle); + until not FindNextVolume(volume, volumeName, Length(volumeName)); + FindVolumeClose(volume); + end; + end; +end; + +end. + \ No newline at end of file diff --git a/RamdiskUI.cfg b/RamdiskUI.cfg new file mode 100644 index 0000000..de8bb16 --- /dev/null +++ b/RamdiskUI.cfg @@ -0,0 +1,38 @@ +-$A8 +-$B- +-$C+ +-$D+ +-$E- +-$F- +-$G+ +-$H+ +-$I+ +-$J+ +-$K- +-$L+ +-$M- +-$N+ +-$O- +-$P+ +-$Q- +-$R- +-$S- +-$T+ +-$U- +-$V+ +-$W- +-$X+ +-$YD +-$Z1 +-cg +-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +-H+ +-W+ +-M +-$M16384,1048576 +-K$00400000 +-LE"c:\program files (x86)\borland\delphi7\..\Bpl" +-LN"c:\program files (x86)\borland\delphi7\..\Bpl" +-w-UNSAFE_TYPE +-w-UNSAFE_CODE +-w-UNSAFE_CAST diff --git a/RamdiskUI.dof b/RamdiskUI.dof new file mode 100644 index 0000000..7ceb7f2 --- /dev/null +++ b/RamdiskUI.dof @@ -0,0 +1,623 @@ +[FileVersion] +Version=7.0 +[Compiler] +A=8 +B=0 +C=1 +D=1 +E=0 +F=0 +G=1 +H=1 +I=1 +J=1 +K=0 +L=1 +M=0 +N=1 +O=0 +P=1 +Q=0 +R=0 +S=0 +T=1 +U=0 +V=1 +W=0 +X=1 +Y=1 +Z=1 +ShowHints=1 +ShowWarnings=1 +UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +NamespacePrefix= +SymbolDeprecated=1 +SymbolLibrary=1 +SymbolPlatform=1 +UnitLibrary=1 +UnitPlatform=1 +UnitDeprecated=1 +HResultCompat=1 +HidingMember=1 +HiddenVirtual=1 +Garbage=1 +BoundsError=1 +ZeroNilCompat=1 +StringConstTruncated=1 +ForLoopVarVarPar=1 +TypedConstVarPar=1 +AsgToTypedConst=1 +CaseLabelRange=1 +ForVariable=1 +ConstructingAbstract=1 +ComparisonFalse=1 +ComparisonTrue=1 +ComparingSignedUnsigned=1 +CombiningSignedUnsigned=1 +UnsupportedConstruct=1 +FileOpen=1 +FileOpenUnitSrc=1 +BadGlobalSymbol=1 +DuplicateConstructorDestructor=1 +InvalidDirective=1 +PackageNoLink=1 +PackageThreadVar=1 +ImplicitImport=1 +HPPEMITIgnored=1 +NoRetVal=1 +UseBeforeDef=1 +ForLoopVarUndef=1 +UnitNameMismatch=1 +NoCFGFileFound=1 +MessageDirective=1 +ImplicitVariants=1 +UnicodeToLocale=1 +LocaleToUnicode=1 +ImagebaseMultiple=1 +SuspiciousTypecast=1 +PrivatePropAccessor=1 +UnsafeType=0 +UnsafeCode=0 +UnsafeCast=0 +[Linker] +MapFile=0 +OutputObjs=0 +ConsoleApp=1 +DebugInfo=0 +RemoteSymbols=0 +MinStackSize=16384 +MaxStackSize=1048576 +ImageBase=4194304 +ExeDescription= +[Directories] +OutputDir= +UnitOutputDir= +PackageDLLOutputDir= +PackageDCPOutputDir= +SearchPath= +Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;vcldb;dsnapcon;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;dclOfficeXP;localizer7;EmbeddedWebBrowser_D7;EzBasic;EzSpecials;TMSUnicodeD7;EzPlanIT;KGrid_R7;tb2k_d7;RVHTMLD7;dclusr;rxctl;kprocs7;Misc;TBX_D7;llPDFLibD7;frxe7;frx7;frxDB7;frxTee7;fs7;fsTee7;NiceGridD7;TBXTaskBar_D7;TwoDesk_D7R;vc2;xhCntrls70;xhStd70;xhChart70;xhExport70;RaizeComponentsVcl;HotKeyMan;siplib7;kbmMemRunD7Pro;OverbyteIcsD7Run;NativeExcelD7;SpTBXTaskBar_D7;SpTBXLib_d7;RVword;tntExtendedEditors;VirtualTreesD7;VSTEditors;VirtualShellToolsD7;EasyListviewD7;GLvis;KZ;prgInternet6;XLS_ReadWrite;sgGrpVw7;zDesign7;EhLib70;GR32_DSGN_D7;GR32_D7;NxTBX;NxCollectionRun;NxCommonRun;clinetsuited7;EJ100R70;CodeSiteLoggingVcl;CodeSiteDBToolsVcl +Conditionals= +DebugSourceDirs= +UsePackages=0 +[Parameters] +RunParams= +HostApplication= +Launcher= +UseLauncher=0 +DebugCWD= +[Language] +ActiveLang= +ProjectLang= +RootDir=C:\Program Files (x86)\Borland\Delphi7\Bin\ +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=0 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1026 +CodePage=1251 +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.0 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= +[Excluded Packages] +c:\Program Files (x86)\Borland\Bpl\prgInternet6.bpl=Progsan Internet Components +c:\Program Files (x86)\Borland\Bpl\kctrls6.bpl=KStringGrid component +[Exception Log] +EurekaLog Version=6105 +Activate=0 +Activate Handle=1 +Save Log File=1 +Foreground Tab=0 +Freeze Activate=0 +Freeze Timeout=60 +SMTP From=eurekalog@email.com +SMTP Host= +SMTP Port=25 +SMTP UserID= +SMTP Password= +Append to Log=0 +TerminateBtn Operation=2 +Errors Number=32 +Errors Terminate=3 +Email Address= +Email Object= +Email Send Options=0 +Output Path= +Encrypt Password= +AutoCloseDialogSecs=0 +WebSendMode=0 +SupportULR= +HTMLLayout Count=15 +HTMLLine0="%3Chtml%3E" +HTMLLine1=" %3Chead%3E" +HTMLLine2=" %3C/head%3E" +HTMLLine3=" %3Cbody TopMargin=10 LeftMargin=10%3E" +HTMLLine4=" %3Ctable width="100%%" border="0"%3E" +HTMLLine5=" %3Ctr%3E" +HTMLLine6=" %3Ctd nowrap%3E" +HTMLLine7=" %3Cfont face="Lucida Console, Courier" size="2"%3E" +HTMLLine8=" %3C%%HTML_TAG%%%3E" +HTMLLine9=" %3C/font%3E" +HTMLLine10=" %3C/td%3E" +HTMLLine11=" %3C/tr%3E" +HTMLLine12=" %3C/table%3E" +HTMLLine13=" %3C/body%3E" +HTMLLine14="%3C/html%3E" +AutoCrashOperation=2 +AutoCrashNumber=10 +AutoCrashMinutes=1 +WebURL= +WebUserID= +WebPassword= +WebPort=0 +AttachedFiles= +ProxyURL= +ProxyUser= +ProxyPassword= +ProxyPort=8080 +TrakerUser= +TrakerPassword= +TrakerAssignTo= +TrakerProject= +TrakerCategory= +TrakerTrialID= +ZipPassword= +PreBuildEvent= +PostSuccessfulBuildEvent= +PostFailureBuildEvent= +ExceptionDialogType=2 +Count=0 +EMail Message Line Count=0 +loNoDuplicateErrors=0 +loAppendReproduceText=0 +loDeleteLogAtVersionChange=0 +loAddComputerNameInLogFileName=0 +loSaveModulesAndProcessesSections=1 +loSaveAssemblerAndCPUSections=1 +soAppStartDate=1 +soAppName=1 +soAppVersionNumber=1 +soAppParameters=1 +soAppCompilationDate=1 +soAppUpTime=1 +soExcDate=1 +soExcAddress=1 +soExcModuleName=1 +soExcModuleVersion=1 +soExcType=1 +soExcMessage=1 +soExcID=1 +soExcCount=1 +soExcStatus=1 +soExcNote=1 +soUserID=1 +soUserName=1 +soUserEmail=1 +soUserPrivileges=1 +soUserCompany=1 +soActCtlsFormClass=1 +soActCtlsFormText=1 +soActCtlsControlClass=1 +soActCtlsControlText=1 +soCmpName=1 +soCmpTotalMemory=1 +soCmpFreeMemory=1 +soCmpTotalDisk=1 +soCmpFreeDisk=1 +soCmpSysUpTime=1 +soCmpProcessor=1 +soCmpDisplayMode=1 +soCmpDisplayDPI=1 +soCmpVideoCard=1 +soCmpPrinter=1 +soOSType=1 +soOSBuildN=1 +soOSUpdate=1 +soOSLanguage=1 +soOSCharset=1 +soNetIP=1 +soNetSubmask=1 +soNetGateway=1 +soNetDNS1=1 +soNetDNS2=1 +soNetDHCP=1 +soCustomData=1 +sndShowSendDialog=1 +sndShowSuccessFailureMsg=0 +sndSendEntireLog=0 +sndSendXMLLogCopy=0 +sndSendScreenshot=1 +sndUseOnlyActiveWindow=0 +sndSendLastHTMLPage=1 +sndSendInSeparatedThread=0 +sndAddDateInFileName=0 +sndAddComputerNameInFileName=0 +edoSendErrorReportChecked=1 +edoAttachScreenshotChecked=1 +edoShowCopyToClipOption=1 +edoShowDetailsButton=1 +edoShowInDetailedMode=0 +edoShowInTopMostMode=0 +edoUseEurekaLogLookAndFeel=0 +edoShowSendErrorReportOption=1 +edoShowAttachScreenshotOption=1 +edoShowCustomButton=0 +csoShowDLLs=1 +csoShowBPLs=1 +csoShowBorlandThreads=1 +csoShowWindowsThreads=1 +csoDoNotStoreProcNames=0 +boPauseBorlandThreads=0 +boDoNotPauseMainThread=0 +boPauseWindowsThreads=0 +boUseMainModuleOptions=1 +boCopyLogInCaseOfError=1 +boSaveCompressedCopyInCaseOfError=0 +boHandleSafeCallExceptions=1 +boCallRTLExceptionEvent=0 +boCatchHandledExceptions=0 +loCatchLeaks=0 +loGroupsSonLeaks=1 +loHideBorlandLeaks=1 +loFreeAllLeaks=1 +loCatchLeaksExceptions=1 +cfoReduceFileSize=1 +cfoCheckFileCorruption=0 +cfoUseEL7=0 +Count mtInformationMsgCaption=1 +mtInformationMsgCaption0="Information." +Count mtQuestionMsgCaption=1 +mtQuestionMsgCaption0="Question." +Count mtErrorMsgCaption=1 +mtErrorMsgCaption0="Error." +Count mtDialog_Caption=1 +mtDialog_Caption0="Error occurred" +Count mtDialog_ErrorMsgCaption=2 +mtDialog_ErrorMsgCaption0="An error has occurred during program execution." +mtDialog_ErrorMsgCaption1="Please read the following information for further details." +Count mtDialog_GeneralCaption=1 +mtDialog_GeneralCaption0="General" +Count mtDialog_GeneralHeader=1 +mtDialog_GeneralHeader0="General Information" +Count mtDialog_CallStackCaption=1 +mtDialog_CallStackCaption0="Call Stack" +Count mtDialog_CallStackHeader=1 +mtDialog_CallStackHeader0="Call Stack Information" +Count mtDialog_ModulesCaption=1 +mtDialog_ModulesCaption0="Modules" +Count mtDialog_ModulesHeader=1 +mtDialog_ModulesHeader0="Modules Information" +Count mtDialog_ProcessesCaption=1 +mtDialog_ProcessesCaption0="Processes" +Count mtDialog_ProcessesHeader=1 +mtDialog_ProcessesHeader0="Processes Information" +Count mtDialog_AsmCaption=1 +mtDialog_AsmCaption0="Assembler" +Count mtDialog_AsmHeader=1 +mtDialog_AsmHeader0="Assembler Information" +Count mtDialog_CPUCaption=1 +mtDialog_CPUCaption0="CPU" +Count mtDialog_CPUHeader=1 +mtDialog_CPUHeader0="CPU Information" +Count mtDialog_OKButtonCaption=1 +mtDialog_OKButtonCaption0="%26OK" +Count mtDialog_TerminateButtonCaption=1 +mtDialog_TerminateButtonCaption0="%26Terminate" +Count mtDialog_RestartButtonCaption=1 +mtDialog_RestartButtonCaption0="%26Restart" +Count mtDialog_DetailsButtonCaption=1 +mtDialog_DetailsButtonCaption0="%26Details" +Count mtDialog_CustomButtonCaption=1 +mtDialog_CustomButtonCaption0="%26Help" +Count mtDialog_SendMessage=1 +mtDialog_SendMessage0="%26Send this error via Internet" +Count mtDialog_ScreenshotMessage=1 +mtDialog_ScreenshotMessage0="%26Attach a Screenshot image" +Count mtDialog_CopyMessage=1 +mtDialog_CopyMessage0="%26Copy to Clipboard" +Count mtDialog_SupportMessage=1 +mtDialog_SupportMessage0="Go to the Support Page" +Count mtMSDialog_ErrorMsgCaption=1 +mtMSDialog_ErrorMsgCaption0="The application has encountered a problem. We are sorry for the inconvenience." +Count mtMSDialog_RestartCaption=1 +mtMSDialog_RestartCaption0="Restart application." +Count mtMSDialog_TerminateCaption=1 +mtMSDialog_TerminateCaption0="Terminate application." +Count mtMSDialog_PleaseCaption=1 +mtMSDialog_PleaseCaption0="Please tell us about this problem." +Count mtMSDialog_DescriptionCaption=1 +mtMSDialog_DescriptionCaption0="We have created an error report that you can send to us. We will treat this report as confidential and anonymous." +Count mtMSDialog_SeeDetailsCaption=1 +mtMSDialog_SeeDetailsCaption0="To see what data the error report contains," +Count mtMSDialog_SeeClickCaption=1 +mtMSDialog_SeeClickCaption0="click here." +Count mtMSDialog_HowToReproduceCaption=1 +mtMSDialog_HowToReproduceCaption0="What were you doing when the problem happened (optional)?" +Count mtMSDialog_EmailCaption=1 +mtMSDialog_EmailCaption0="Email address (optional):" +Count mtMSDialog_SendButtonCaption=1 +mtMSDialog_SendButtonCaption0="%26Send Error Report" +Count mtMSDialog_NoSendButtonCaption=1 +mtMSDialog_NoSendButtonCaption0="%26Don't Send" +Count mtLog_AppHeader=1 +mtLog_AppHeader0="Application" +Count mtLog_AppStartDate=1 +mtLog_AppStartDate0="Start Date" +Count mtLog_AppName=1 +mtLog_AppName0="Name/Description" +Count mtLog_AppVersionNumber=1 +mtLog_AppVersionNumber0="Version Number" +Count mtLog_AppParameters=1 +mtLog_AppParameters0="Parameters" +Count mtLog_AppCompilationDate=1 +mtLog_AppCompilationDate0="Compilation Date" +Count mtLog_AppUpTime=1 +mtLog_AppUpTime0="Up Time" +Count mtLog_ExcHeader=1 +mtLog_ExcHeader0="Exception" +Count mtLog_ExcDate=1 +mtLog_ExcDate0="Date" +Count mtLog_ExcAddress=1 +mtLog_ExcAddress0="Address" +Count mtLog_ExcModuleName=1 +mtLog_ExcModuleName0="Module Name" +Count mtLog_ExcModuleVersion=1 +mtLog_ExcModuleVersion0="Module Version" +Count mtLog_ExcType=1 +mtLog_ExcType0="Type" +Count mtLog_ExcMessage=1 +mtLog_ExcMessage0="Message" +Count mtLog_ExcID=1 +mtLog_ExcID0="ID" +Count mtLog_ExcCount=1 +mtLog_ExcCount0="Count" +Count mtLog_ExcStatus=1 +mtLog_ExcStatus0="Status" +Count mtLog_ExcNote=1 +mtLog_ExcNote0="Note" +Count mtLog_UserHeader=1 +mtLog_UserHeader0="User" +Count mtLog_UserID=1 +mtLog_UserID0="ID" +Count mtLog_UserName=1 +mtLog_UserName0="Name" +Count mtLog_UserEmail=1 +mtLog_UserEmail0="Email" +Count mtLog_UserCompany=1 +mtLog_UserCompany0="Company" +Count mtLog_UserPrivileges=1 +mtLog_UserPrivileges0="Privileges" +Count mtLog_ActCtrlsHeader=1 +mtLog_ActCtrlsHeader0="Active Controls" +Count mtLog_ActCtrlsFormClass=1 +mtLog_ActCtrlsFormClass0="Form Class" +Count mtLog_ActCtrlsFormText=1 +mtLog_ActCtrlsFormText0="Form Text" +Count mtLog_ActCtrlsControlClass=1 +mtLog_ActCtrlsControlClass0="Control Class" +Count mtLog_ActCtrlsControlText=1 +mtLog_ActCtrlsControlText0="Control Text" +Count mtLog_CmpHeader=1 +mtLog_CmpHeader0="Computer" +Count mtLog_CmpName=1 +mtLog_CmpName0="Name" +Count mtLog_CmpTotalMemory=1 +mtLog_CmpTotalMemory0="Total Memory" +Count mtLog_CmpFreeMemory=1 +mtLog_CmpFreeMemory0="Free Memory" +Count mtLog_CmpTotalDisk=1 +mtLog_CmpTotalDisk0="Total Disk" +Count mtLog_CmpFreeDisk=1 +mtLog_CmpFreeDisk0="Free Disk" +Count mtLog_CmpSystemUpTime=1 +mtLog_CmpSystemUpTime0="System Up Time" +Count mtLog_CmpProcessor=1 +mtLog_CmpProcessor0="Processor" +Count mtLog_CmpDisplayMode=1 +mtLog_CmpDisplayMode0="Display Mode" +Count mtLog_CmpDisplayDPI=1 +mtLog_CmpDisplayDPI0="Display DPI" +Count mtLog_CmpVideoCard=1 +mtLog_CmpVideoCard0="Video Card" +Count mtLog_CmpPrinter=1 +mtLog_CmpPrinter0="Printer" +Count mtLog_OSHeader=1 +mtLog_OSHeader0="Operating System" +Count mtLog_OSType=1 +mtLog_OSType0="Type" +Count mtLog_OSBuildN=1 +mtLog_OSBuildN0="Build #" +Count mtLog_OSUpdate=1 +mtLog_OSUpdate0="Update" +Count mtLog_OSLanguage=1 +mtLog_OSLanguage0="Language" +Count mtLog_OSCharset=1 +mtLog_OSCharset0="Charset" +Count mtLog_NetHeader=1 +mtLog_NetHeader0="Network" +Count mtLog_NetIP=1 +mtLog_NetIP0="IP Address" +Count mtLog_NetSubmask=1 +mtLog_NetSubmask0="Submask" +Count mtLog_NetGateway=1 +mtLog_NetGateway0="Gateway" +Count mtLog_NetDNS1=1 +mtLog_NetDNS10="DNS 1" +Count mtLog_NetDNS2=1 +mtLog_NetDNS20="DNS 2" +Count mtLog_NetDHCP=1 +mtLog_NetDHCP0="DHCP" +Count mtLog_CustInfoHeader=1 +mtLog_CustInfoHeader0="Custom Information" +Count mtCallStack_Address=1 +mtCallStack_Address0="Address" +Count mtCallStack_Name=1 +mtCallStack_Name0="Module" +Count mtCallStack_Unit=1 +mtCallStack_Unit0="Unit" +Count mtCallStack_Class=1 +mtCallStack_Class0="Class" +Count mtCallStack_Procedure=1 +mtCallStack_Procedure0="Procedure/Method" +Count mtCallStack_Line=1 +mtCallStack_Line0="Line" +Count mtCallStack_MainThread=1 +mtCallStack_MainThread0="Main" +Count mtCallStack_ExceptionThread=1 +mtCallStack_ExceptionThread0="Exception Thread" +Count mtCallStack_RunningThread=1 +mtCallStack_RunningThread0="Running Thread" +Count mtCallStack_CallingThread=1 +mtCallStack_CallingThread0="Calling Thread" +Count mtCallStack_ThreadID=1 +mtCallStack_ThreadID0="ID" +Count mtCallStack_ThreadPriority=1 +mtCallStack_ThreadPriority0="Priority" +Count mtCallStack_ThreadClass=1 +mtCallStack_ThreadClass0="Class" +Count mtCallStack_LeakCaption=1 +mtCallStack_LeakCaption0="Memory Leak" +Count mtCallStack_LeakData=1 +mtCallStack_LeakData0="Data" +Count mtCallStack_LeakType=1 +mtCallStack_LeakType0="Type" +Count mtCallStack_LeakSize=1 +mtCallStack_LeakSize0="Total size" +Count mtCallStack_LeakCount=1 +mtCallStack_LeakCount0="Count" +Count mtSendDialog_Caption=1 +mtSendDialog_Caption0="Send." +Count mtSendDialog_Message=1 +mtSendDialog_Message0="Message" +Count mtSendDialog_Resolving=1 +mtSendDialog_Resolving0="Resolving DNS..." +Count mtSendDialog_Login=1 +mtSendDialog_Login0="Login..." +Count mtSendDialog_Connecting=1 +mtSendDialog_Connecting0="Connecting with server..." +Count mtSendDialog_Connected=1 +mtSendDialog_Connected0="Connected with server." +Count mtSendDialog_Sending=1 +mtSendDialog_Sending0="Sending message..." +Count mtSendDialog_Sent=1 +mtSendDialog_Sent0="Message sent." +Count mtSendDialog_SelectProject=1 +mtSendDialog_SelectProject0="Select project..." +Count mtSendDialog_Searching=1 +mtSendDialog_Searching0="Searching..." +Count mtSendDialog_Modifying=1 +mtSendDialog_Modifying0="Modifying..." +Count mtSendDialog_Disconnecting=1 +mtSendDialog_Disconnecting0="Disconnecting..." +Count mtSendDialog_Disconnected=1 +mtSendDialog_Disconnected0="Disconnected." +Count mtReproduceDialog_Caption=1 +mtReproduceDialog_Caption0="Request" +Count mtReproduceDialog_Request=1 +mtReproduceDialog_Request0="Please describe the steps to reproduce the error:" +Count mtReproduceDialog_OKButtonCaption=1 +mtReproduceDialog_OKButtonCaption0="%26OK" +Count mtModules_Handle=1 +mtModules_Handle0="Handle" +Count mtModules_Name=1 +mtModules_Name0="Name" +Count mtModules_Description=1 +mtModules_Description0="Description" +Count mtModules_Version=1 +mtModules_Version0="Version" +Count mtModules_Size=1 +mtModules_Size0="Size" +Count mtModules_LastModified=1 +mtModules_LastModified0="Modified" +Count mtModules_Path=1 +mtModules_Path0="Path" +Count mtProcesses_ID=1 +mtProcesses_ID0="ID" +Count mtProcesses_Name=1 +mtProcesses_Name0="Name" +Count mtProcesses_Description=1 +mtProcesses_Description0="Description" +Count mtProcesses_Version=1 +mtProcesses_Version0="Version" +Count mtProcesses_Memory=1 +mtProcesses_Memory0="Memory" +Count mtProcesses_Priority=1 +mtProcesses_Priority0="Priority" +Count mtProcesses_Threads=1 +mtProcesses_Threads0="Threads" +Count mtProcesses_Path=1 +mtProcesses_Path0="Path" +Count mtCPU_Registers=1 +mtCPU_Registers0="Registers" +Count mtCPU_Stack=1 +mtCPU_Stack0="Stack" +Count mtCPU_MemoryDump=1 +mtCPU_MemoryDump0="Memory Dump" +Count mtSend_SuccessMsg=1 +mtSend_SuccessMsg0="The message was sent successfully." +Count mtSend_FailureMsg=1 +mtSend_FailureMsg0="Sorry, sending the message didn't work." +Count mtSend_BugClosedMsg=2 +mtSend_BugClosedMsg0="These BUG is just closed." +mtSend_BugClosedMsg1="Contact the program support to obtain an update." +Count mtSend_UnknownErrorMsg=1 +mtSend_UnknownErrorMsg0="Unknown error." +Count mtSend_InvalidLoginMsg=1 +mtSend_InvalidLoginMsg0="Invalid login request." +Count mtSend_InvalidSearchMsg=1 +mtSend_InvalidSearchMsg0="Invalid search request." +Count mtSend_InvalidSelectionMsg=1 +mtSend_InvalidSelectionMsg0="Invalid selection request." +Count mtSend_InvalidInsertMsg=1 +mtSend_InvalidInsertMsg0="Invalid insert request." +Count mtSend_InvalidModifyMsg=1 +mtSend_InvalidModifyMsg0="Invalid modify request." +Count mtFileCrackedMsg=2 +mtFileCrackedMsg0="This file is cracked." +mtFileCrackedMsg1="The application will be closed." +Count mtException_LeakMultiFree=1 +mtException_LeakMultiFree0="Multi Free memory leak." +Count mtException_LeakMemoryOverrun=1 +mtException_LeakMemoryOverrun0="Memory Overrun leak." +Count mtException_AntiFreeze=1 +mtException_AntiFreeze0="The application seems to be frozen." +Count mtInvalidEmailMsg=1 +mtInvalidEmailMsg0="Invalid email." +TextsCollection=English + + diff --git a/RamdiskUI.dpr b/RamdiskUI.dpr new file mode 100644 index 0000000..e66b194 --- /dev/null +++ b/RamdiskUI.dpr @@ -0,0 +1,15 @@ +program RamdiskUI; + +{$R 'manifest.res' 'manifest.rc'} + +uses + Forms, + Main in 'Main.pas' {frmUI}; +{$R *.res} + +begin + Application.Initialize; + Application.Title := 'RAMdisk'; + Application.CreateForm(TfrmUI, frmUI); + Application.Run; +end. diff --git a/RamdiskUI.res b/RamdiskUI.res new file mode 100644 index 0000000..80b045b Binary files /dev/null and b/RamdiskUI.res differ diff --git a/SrvMain.dfm b/SrvMain.dfm new file mode 100644 index 0000000..e98c34e --- /dev/null +++ b/SrvMain.dfm @@ -0,0 +1,15 @@ +object ArsenalRamDisk: TArsenalRamDisk + OldCreateOrder = False + AllowPause = False + DisplayName = 'Arsenal RAM-disk' + WaitHint = 8000 + AfterInstall = ServiceAfterInstall + OnExecute = ServiceExecute + OnShutdown = ServiceShutdown + OnStart = ServiceStart + OnStop = ServiceStop + Left = 263 + Top = 110 + Height = 150 + Width = 215 +end diff --git a/SrvMain.pas b/SrvMain.pas new file mode 100644 index 0000000..9474395 --- /dev/null +++ b/SrvMain.pas @@ -0,0 +1,129 @@ +unit SrvMain; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs; + +type + TArsenalRamDisk = class(TService) + procedure ServiceAfterInstall(Sender: TService); + procedure ServiceExecute(Sender: TService); + procedure ServiceShutdown(Sender: TService); + procedure ServiceStart(Sender: TService; var Started: Boolean); + procedure ServiceStop(Sender: TService; var Stopped: Boolean); + private + { Private declarations } + public + function GetServiceController: TServiceController; override; + { Public declarations } + end; + +var + ArsenalRamDisk: TArsenalRamDisk; + +implementation + +{$R *.DFM} + +Uses TntRegistry,Definitions,RamCreate,RamRemove; + +Var + config:TRamDisk; + +procedure LoadSettings; +var + reg: TTntRegistry; +Begin + reg:=TTntRegistry.Create(KEY_READ); + Try + reg.RootKey:=HKEY_LOCAL_MACHINE; + if Reg.OpenKey('SYSTEM\CurrentControlSet\Services\ArsenalRamDisk', False) then + begin + If Reg.ValueExists('DiskSize') then + Begin + config.size:=StrToInt64(reg.ReadString('DiskSize')); + end; + if reg.ValueExists('DriveLetter') Then + Begin + config.letter:=Char(reg.ReadString('DriveLetter')[1]); + end; + if reg.ValueExists('LoadContent') Then + Begin + config.persistentFolder:=reg.ReadString('LoadContent'); + end; + if reg.ValueExists('ExcludeFolders') Then + Begin + config.excludedList:=reg.ReadString('ExcludeFolders'); + end; + if reg.ValueExists('UseTempFolder') Then + Begin + config.useTemp:=reg.ReadBool('UseTempFolder'); + end; + if reg.ValueExists('SyncContent') Then + Begin + config.synchronize:=reg.ReadBool('SyncContent'); + end; + if reg.ValueExists('DeleteOld') Then + Begin + config.deleteOld:=reg.ReadBool('DeleteOld'); + end; + Reg.CloseKey; + end; + Finally + reg.Free; + End; +end; + +procedure ServiceController(CtrlCode: DWord); stdcall; +begin + ArsenalRamDisk.Controller(CtrlCode); +end; + +function TArsenalRamDisk.GetServiceController: TServiceController; +begin + Result := ServiceController; +end; + +procedure TArsenalRamDisk.ServiceAfterInstall(Sender: TService); +var + reg:TTntRegistry; +begin + Reg := TTntRegistry.Create(KEY_READ or KEY_WRITE); + try + Reg.RootKey := HKEY_LOCAL_MACHINE; + if Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\' + Name, false) then + begin + Reg.WriteString('Description', DisplayName); + Reg.CloseKey; + end; + finally + Reg.Free; + end; + +end; + +procedure TArsenalRamDisk.ServiceExecute(Sender: TService); +begin + while not Terminated do ServiceThread.ProcessRequests(True); +end; + +procedure TArsenalRamDisk.ServiceShutdown(Sender: TService); +begin + DetachRamDisk(config); +end; + +procedure TArsenalRamDisk.ServiceStart(Sender: TService; var Started: Boolean); +begin + LoadSettings; + if (config.size<>0) then + if CreateRamDisk(config,False) Then Started:=True; +end; + +procedure TArsenalRamDisk.ServiceStop(Sender: TService; var Stopped: Boolean); +begin + if config.letter <> #0 then + If DetachRamDisk(config) then Stopped:=True; +end; + +end. diff --git a/VD.ico b/VD.ico new file mode 100644 index 0000000..13b3006 Binary files /dev/null and b/VD.ico differ diff --git a/manifest.rc b/manifest.rc new file mode 100644 index 0000000..32f455b --- /dev/null +++ b/manifest.rc @@ -0,0 +1 @@ +1 24 "RamService.manifest" diff --git a/manifest.res b/manifest.res new file mode 100644 index 0000000..e362c2b Binary files /dev/null and b/manifest.res differ