Seite 1 von 1

Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTENTS)

Verfasst: 25.04.2014 01:10
von Sundance
Hallo zusammen,

dies ist mein erster Post hier. Ich habe einige Jahre lang nur in AutoIt programmiert. Aber úmzusetzende Projekte sind immer komplexer geworden. Das lässt sich zwar auch meistens in AutoIt umsetzen, aber Performanceprobleme haben mich nach einer anderen Programmiersprache schauen lassen. Und nach langen hin und her habe ich mich für PureBasic entschieden. Es macht so einen Spaß damit zu programmieren. Es ist ähnlich wie AutoIt, aber wesentlich mächtiger. Nun sind seit den ersten Schritten zwei Wochen vergangen und ich habe nun ein Problem bezüglich eines DeviceIoControl aufrufes. Ich erhalte nicht die Informationen, die mir die Struktur eigentlich liefern sollte. Ich gehe schwer davon aus, dass ich ein Problem mit der Definition der Strukturen habe. Integer,Long oder doch quad oder sogar LARGE_INTEGER? :|
Und dann muss ich aufpassen ob ich den x86 Compiler unter 32 oder 64Bit ausführe. Puhhh.

Also hier mal mein Problem, in der Hoffnung das auch andere von einer Lösung profitieren können.

Hier nun ein Testprogramm. Es sollte das Laufwerk C: auslesen bzw. sagen auf welcher Platte die Partition liegt, welchen OffSet und welche Größe sie hat.

Code: Alles auswählen

OpenConsole()

#IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS=$560000

Structure t_DISK_EXTENT
	DiskNumber.l
	StartingOffset.q
	ExtentLength.q
EndStructure

Structure t_VOLUME_DISK_EXTENTS
	NumberOfDiskExtents.l
	Extents.t_DISK_EXTENT[32]  ; 32 just for having enough space.
EndStructure

; prototypes and procedure pre-definitions
; ----------------------------------------
Prototype GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint, lpszVolumeName, cchBufferLength)
Declare.s _getVolumeNameForVolumeMountPoint(lpszVolumeMountPoint$)
Declare _DeviceIoControl_IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS(sVolumeName.s, *VolumeDiskExtents.t_VOLUME_DISK_EXTENTS)
Declare.s GetLastErrorMessage(Error.i = $ABCDEF)

Define DriveLetter.s = "d:\"

; get VolumeName of driveletter c:
Define VolumeName.s = _getVolumeNameForVolumeMountPoint(DriveLetter)

If VolumeName = ""
	PrintN( "No VolumeName for driveletter '" + DriveLetter + "' found" )
; 	Input()
	End
Else
	PrintN( "Volumename of drive '" + DriveLetter + "' is '" + VolumeName + "'" )
EndIf

Define VDE.t_VOLUME_DISK_EXTENTS

_DeviceIoControl_IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS(VolumeName, @VDE)

PrintN( "Number of diskextents	: " + VDE\NumberOfDiskExtents )
PrintN( "Disk			: " + Str(VDE\Extents[0]\DiskNumber) )
PrintN( "Offset			: " + Str(VDE\Extents[0]\StartingOffset) )
PrintN( "Length			: " + Str(VDE\Extents[0]\ExtentLength) )

; Input()

Procedure _DeviceIoControl_IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS(VolumeName.s, *VolumeDiskExtents.t_VOLUME_DISK_EXTENTS)

	Protected iBytesReturned.i
	Protected Result.i, LastError.i
	Protected VDext.t_VOLUME_DISK_EXTENTS
	Protected *DE.t_DISK_EXTENT
	
	If Right(VolumeName,1) = "\" : VolumeName = RTrim(VolumeName,"\") : EndIf
	
	Protected hDevice = CreateFile_(VolumeName, #GENERIC_READ, #FILE_SHARE_READ|#FILE_SHARE_WRITE, 0, #OPEN_EXISTING, 0, 0)
	PrintN( "Volumehandle: " + hDevice + " (" + GetLastErrorMessage() + ")" )
	If hDevice > 0
		
		Result =		DeviceIoControl_(	hDevice,
		        		                 	#IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
		        		                 	#Null,
		        		                 	0,
		        		                 	@VDext,
		        		                 	SizeOf(VDext),
		        		                 	@iBytesReturned,
		        		                 	#Null)
		
		LastError = GetLastError_()
		PrintN( "Result of DeviceIoControl call: " + Result )
		If Not Result : PrintN( "LastError: " + GetLastErrorMessage(LastError) ) : PrintN( "" ) : EndIf
		CloseHandle_(hDevice)
		If LastError = #ERROR_INSUFFICIENT_BUFFER 
			PrintN( "Insufficient buffer." )
			PrintN( "Nothing returned." ) :	PrintN( "" )
		ElseIf LastError = 0
			PrintN( "Error calling DeviceIoControl!" ) : PrintN( "" )
		Else 
			PrintN( Str(iBytesReturned) + " bytes returned." )
		EndIf
		
		*DE = @VDext\Extents[0]
		
		With *VolumeDiskExtents
		
		\NumberOfDiskExtents = VDext\NumberOfDiskExtents
		\Extents[0]\DiskNumber = *DE\DiskNumber
		\Extents[0]\StartingOffset = *DE\StartingOffset
		\Extents[0]\ExtentLength = *DE\ExtentLength
		
		EndWith
		
	EndIf
		
EndProcedure

Procedure.s GetLastErrorMessage(Error.i = $ABCDEF)
  Protected *MemoryID,e$,Length
  If Error = $ABCDEF : Error = GetLastError_() : EndIf
  If Error
    *MemoryID = AllocateMemory(255)
    If *MemoryID
      Length = FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #Null, Error, 0, *MemoryID, 255, #Null)
      If Length > 1 ; Some error messages are "" + Chr (13) + Chr (10)... stoopid M$... :(
        e$ = PeekS(*MemoryID, Length - 2)
      Else
        e$ = "Unknown error!"
      EndIf
      FreeMemory(*MemoryID)
      ProcedureReturn e$
    Else
      ProcedureReturn "Error while decoding Error("+Str(Error)+")"
    EndIf
  Else
    ProcedureReturn "No error has occurred!"
  EndIf
EndProcedure 



Procedure.s _getVolumeNameForVolumeMountPoint(lpszVolumeMountPoint$)

	Protected lpszVolumeName$ = Space(255)
	Protected hLib
	
	hLib = OpenLibrary(#PB_Any, "Kernel32.dll")
	If hLib
	  ;Prototype GetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint, lpszVolumeName, cchBufferLength)
	  Define GetVolumeNameForVolumeMountPoint.GetVolumeNameForVolumeMountPoint = GetFunction(hLib,"GetVolumeNameForVolumeMountPointW")
	  If GetVolumeNameForVolumeMountPoint.GetVolumeNameForVolumeMountPoint = 0
	  	Debug ("Can't find GetVolumeNameForVolumeMountPointW")
	  	CloseLibrary(hLib)
	  	ProcedureReturn ""
	  EndIf
	  CloseLibrary(hLib)
	Else
		ProcedureReturn ""
	EndIf
		
	GetVolumeNameForVolumeMountPoint(@lpszVolumeMountPoint$, @lpszVolumeName$, 255)
	
	ProcedureReturn lpszVolumeName$
	
EndProcedure
Der Wert für NumberOfDiskExtents scheint in Ordnung zu sein aber die Werte aus der Teilstruktur t_DISK_EXTENT sind völlig daneben.

Hier mal ein Auszug aus den entsprechenden Teilen in der MSDN:

Code: Alles auswählen

typedef struct _VOLUME_DISK_EXTENTS {
  DWORD       NumberOfDiskExtents;
  DISK_EXTENT Extents[ANYSIZE_ARRAY];
} VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;

Code: Alles auswählen

typedef struct _DISK_EXTENT {
  DWORD         DiskNumber;
  LARGE_INTEGER StartingOffset;
  LARGE_INTEGER ExtentLength;
} DISK_EXTENT, *PDISK_EXTENT;

und hier der DeviceIoControl Aufruf:

Code: Alles auswählen


BOOL 
WINAPI 
DeviceIoControl( (HANDLE) hDevice,                     // handle to device
                 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, // dwIoControlCode
                 NULL,                                 // lpInBuffer
                 0,                                    // nInBufferSize
                 (LPVOID) lpOutBuffer,                 // output buffer
                 (DWORD) nOutBufferSize,               // size of output buffer
                 (LPDWORD) lpBytesReturned,            // number of bytes returned
                 (LPOVERLAPPED) lpOverlapped           // OVERLAPPED structure
);

Ich bin mir halt nicht sicher ob ich LARGE_INTEGER nehmen soll. Dann müsste ich mich unter einer 32Bit Umgebung doch mit den entsprechenden High/Low Werten befassen, oder?

So. Ich hoffe das ich alles verständlich erklärt habe. Falls ich was vergessen habe, bitte melden. Ich versuche immer erst ein Problem selber auf die Reihe zu bekommen, aber nach nun drei Tagen und ca. 20 Stunden vor dem Rechner bin ich etwas Ratlos.... :shock:


Viele Grüße
Sundance

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 15:55
von _JON_
Na dann erstmals herzlich willkommen hier.

Ändere mal das Alignment der Strukturen:

Code: Alles auswählen

Structure t_DISK_EXTENT Align #PB_Structure_AlignC 
  DiskNumber.l
  StartingOffset.q
  ExtentLength.q
EndStructure

Structure t_VOLUME_DISK_EXTENTS Align #PB_Structure_AlignC
   NumberOfDiskExtents.l
   Extents.t_DISK_EXTENT[32]  ; 32 just for having enough space.
EndStructure

PS. gibt es einen Grund warum Du den Volumennamen benutzt, wenn Du doch schon den Breitstellungspunkt (C:\) hast?

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 16:53
von Sundance
Hi Jon,

super vielen Dank für deine Antwort. Es hat tatsächlich am Alignment gelegen. Das lese mir mir gleich nochmal durch. Wann ich das setzen muss und wann nicht.
Also ich habe es jetzt mit der x86 Version des Compilers unter einem Win x64 compiliert und erhalte auch unter dem x64 OS ein richtiges ERgebnis. Das Kompilat auf einem x86 System liefert noch falsche Werte. Aber das liegt wohl am Quad und das ich das auf einem x64 System compiliere. Werde das später mal auf einem x32 compilieren.

Warum ich nicht direkt den Bereitstellungspunkt nehme? Das sieht natürlich im Beispielcode etwas unglücklich aus, aber in meinem Programm lege ich erst eine Volumeliste an. Diese beinhaltet dann alle möglich Volumes des Computers. Sei es hidden partitions, Bootpartitions, dnamische oder sTandardpartitions. So habe ich alles auf einen Blick und nehme dann die Volumes mit den entsprechendens DeviceIoControl Aufrufen 'auseinander' :-)

Ich werde berichten sobald ich das mal unter x32 compiliert habe!


Danke nochmals Jon!!

Viele Grüße
Sundance

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 17:08
von Sundance
So. Ich nochmal. Also ich konnte nicht warten und habe mich gleich mal an einen x32 Server angemeldet und das PRogramm unter x32 OS und x32 Compiler compiliert und siehe da, es liefert nun auch unte einem 32bit OS richtige Werte.

Das heißt also auch wenn ich unter einem 64Bit OS den 32Bit Compiler nutze ist das nicht wirklich ein 100% kompatibles 32Bit Produkt, da das OS die 64Bit Variablen nativ behandelt und deshalb 'anders' in das 32Bit Kompilat reinschreibt?
Kann ich das irgendwie ändern, so dass ich unter meinem 64Bit Hauptrechner auch reine 32Bit Programme schreiben kann?

Viele Grüße
Sundance

PS: Im Gegensatz zu AutoIt ist das wirklich schön und entspannend zu Programmieren. In AutoIt hätte ich mir damit die Finger gebrochen...

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 18:57
von ts-soft
Sundance hat geschrieben:Das heißt also auch wenn ich unter einem 64Bit OS den 32Bit Compiler nutze ist das nicht wirklich ein 100% kompatibles 32Bit Produkt, da das OS die 64Bit Variablen nativ behandelt und deshalb 'anders' in das 32Bit Kompilat reinschreibt?
Kann ich das irgendwie ändern, so dass ich unter meinem 64Bit Hauptrechner auch reine 32Bit Programme schreiben kann?
Das mit dem Alignment hat was mit den CallingConvention zu tun. C-Compiler optimieren die Strukturen meist autom., um das Programm
zu beschleunigen. Die Unterschiede sind also die Register und Fastcall bzw. Stdcall.

Nur deshalb werden die Strukturen anders behandelt. Hat also eher weniger mit Inkompatiblität zu tun.

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 19:24
von Sundance
Hi TS-Soft,

danke für deine Antwort. 'Inkompatibel' war sicher das falsche Wort. Was kann ich denn machen, damit der unter dem 64Bit OS mit dem 32Bit Compiler auch ein Code kompiliert wird, der dann auch auf einem 32Bit OS läuft. *grübel*

Danke nochmals
Sundance

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 19:30
von ts-soft
Das 32-Bit Programm gibt ohne Änderungen auf 64-Bit und 32-Bit OS dieselben Ergebnisse!

Einschränkungen gibt es nur bezüglich DLLs und Treibern. Ein 64-Bit OS kann nur 64-Bit Treiber nutzen.
Ein 64-Bit Programm kann nur 64-Bit DLLs laden und ein 32-Bit Programm kann nur 32-Bit DLLs laden.

Alles ein wenig verwirrend, vor allem wenn dann WOW64 sich noch einmischt, aber Dein Programm sollte
unverändert als 32-Bit Version unter beiden Bitbreiten des OS laufen.

// Nachtrag:
Für Handle und Pointer solltest Du Integer nutzen (das entspricht einem Long unter 32-Bit, bzw. einem Quad unter 64-Bit)!

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 19:33
von Sundance
Dankeee. :allright:
Dann checke ich das nochmals. Dann liegt der Fehler bei mir. Ich habe das auch so nicht nachvollziehen können warum der Output nicht funktionieren sollte.

Viele Grüße und Danke euch für die wertvolle Hilfe !!! Tolle Programmiersprache und anscheinend auch ein tolles Forum. Hoffe ich mal in Zukunft auch hier anderen weiterhelfen zu können. :)
Sundance

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 19:35
von ts-soft
Hab meinem letztem Posting noch was nachgetragen, was Dein Problem lösen sollte, wegen Integer!

Re: Disk Informationen abrufen (VOLUME_GET_VOLUME_DISK_EXTEN

Verfasst: 25.04.2014 19:47
von Sundance
Dank dir! Ich habe auch heute Nacht irgendwo im Forum eine Diskussion gelesen über Integer. Das man sie eher nutzen sollte als speziell Long, Byte... zu nutzen. Speicherplatz zu sparen macht an der Stelle nicht so viel Sinn.

Bis denne
Sundance