Autor Beitrag
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2008
Erhaltene Danke: 368

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Di 20.06.17 08:45 
Hallo Forum

Problemstellung:
Ich habe die WinAPI Funktion DeviceIoControl() ins Projekt aufgenommen und auch an mehreren Stellen in Nutzung.
Bis auf die folgende Stelle, hab' ich ansonsten kein Problem damit:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
        private bool IsDeviceDescripted(char cDrive, ref frFunc.STORAGE_DEVICE_DESCRIPTOR descriptor)
        {
            bool bResult = false;
            IntPtr hnd = OpenVolume(cDrive);  // Das Handle ist gültig

            if (hnd != IntPtr.Zero)
            {
                uint bytesReturned = 0;
                var query = new frFunc.STORAGE_PROPERTY_QUERY();
                int querySize = Marshal.SizeOf(query);
                IntPtr pQuery = Marshal.AllocHGlobal(querySize);
                int descriptorSize = Marshal.SizeOf(descriptor);
                IntPtr pDescriptor = Marshal.AllocHGlobal(descriptorSize);

                // bResult = 
                if (!frFunc.DeviceIoControl(hnd, frConst.IOCTL_STORAGE_QUERY_PROPERTY, // = 0x2D1400;
                                                 pQuery, querySize,
                                                 pDescriptor, descriptorSize,
                                                 ref bytesReturned, IntPtr.Zero))
                    System.Windows.Forms.MessageBox.Show(Marshal.GetLastWin32Error().ToString());
                    // Fehler 1: Unzulässige Funktion

                frFunc.CloseHandle(hnd);
                Marshal.FreeHGlobal(pQuery);
                Marshal.FreeHGlobal(pDescriptor);
            }
            return bResult;
        }

        public IntPtr OpenVolume(char cDrive)
        {
            string root = @"\\.\" + cDrive + ":";
            IntPtr hnd = frFunc.CreateFile(root, frConst.GENERIC_READ | frConst.GENERIC_WRITE,
                                           frConst.FILE_SHARE_READ | frConst.FILE_SHARE_WRITE,
                                           IntPtr.Zero, frConst.OPEN_EXISTING, 0, IntPtr.Zero);

            if ((uint)hnd == INVALID_HANDLE_VALUE) // = 0xFFFFFFFF;
                hnd = IntPtr.Zero;
            return hnd;
        }

Da so viele Konstanten und Funktionen darin involviert sind, und Copy&Paste der Fragmente es nicht gerade leserlicher machen würden, habe ich die ausgelagerte Klasse im Dateianhang dazugehängt.


Vielleicht kann sich das jemand anschauen und dem Fehler nachgehen?! :flehan:
Einloggen, um Attachments anzusehen!
_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3743
Erhaltene Danke: 762

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Di 20.06.17 10:24 
Hallo,

sehe ich das richtig, daß du die Query nicht befüllst (PropertyId, QueryType - entsprechend STORAGE_PROPERTY_QUERY (Structures))?

s.a. Beschreibung von lpInBuffer in IOCTL_STORAGE_QUERY_PROPERTY control code

Schau mal für ein Beispiel in Get Physical Drive Serial Number – Part 1 (besonders "2. Set the STORAGE_PROPERTY_QUERY input data structure.").

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2008
Erhaltene Danke: 368

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Di 20.06.17 11:05 
Danke, und stimmt, habe es wieder einmal vergessen zu befüllen. Wäre nicht passiert, wenn ich es aus'm Delphi Projekt abgeschrieben hätte:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
[DllImport("Kernel32.dll", SetLastError = false)]
public static extern void ZeroMemory(IntPtr Destination, int Length);
// ---

frFunc.ZeroMemory(pQuery, querySize);  
frFunc.ZeroMemory(pDescriptor, descriptorSize);

// if (!frFunc.DeviceIoControl( ... usw.

Das schöne ist, die Funktion liefert True, das unschöne ist, der Descriptor liefert in den OffSets 0. Muss ich mal schaun, warum.
Von deinem Link habe ich es damals nach Delphi übersetzt, kam aber drauf, dass ich den StorageHeader garnicht brauch, denn die Größe, die er wiedergibt, ist immer kleiner als die Größe (SizeOf(_descriptor)) des StorageDescriptor.
Es spart vielleicht etwas an Ressourcen ein, dafür muss 1x mehr DeviceIoControl() aufgerufen werden.

So funktioniert es bei mir in Delphi, und sollte entsprechend gut auch in C# funktionieren, was im Moment nicht der Fall ist:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
function TfrDrive.IsDeviceDescripted(cDrive: Char;
  var Descriptor: TStorageDeviceDescriptor): Boolean;
var
  bytesReturned: DWord;
  spQuery: TStoragePropertyQuery;
  hnd: THandle;
  b: Boolean;
begin
  b := false;
  bytesReturned := 0;
  ZeroMemory(@spQuery, SizeOf(spQuery));
  ZeroMemory(@Descriptor, SizeOf(Descriptor));

  hnd := OpenVolume(cDrive);
  if hnd <> 0 then
  begin
    b := DeviceIoControl(hnd, IOCTL_STORAGE_QUERY_PROPERTY,
                         @spQuery, SizeOf(spQuery),
                         @Descriptor, SizeOf(Descriptor),
                         bytesReturned, nil);
    CloseHandle(hnd);
  end;
  result := b;
end;

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2008
Erhaltene Danke: 368

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Di 20.06.17 22:59 
Ich habe die C# Methode ein wenig korrigiert und bekomm' in den Offsets auch Werte:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
private bool IsDeviceDescripted(char cDrive, ref frFunc.STORAGE_DEVICE_DESCRIPTOR descriptor) 

    bool bResult = false
    uint bytesReturned = 0
    IntPtr hnd = OpenVolume(cDrive); 
     
    if (hnd != IntPtr.Zero) 
    { 
        var query = new frFunc.STORAGE_PROPERTY_QUERY();  // { PropertyId = 0, QueryType = 0 }; 

        int querySize = Marshal.SizeOf(query); 
        IntPtr pQuery = Marshal.AllocHGlobal(querySize); 
        int descriptorSize = Marshal.SizeOf(descriptor); 
        IntPtr pDescriptor = Marshal.AllocHGlobal(descriptorSize); 
         
        Marshal.StructureToPtr(query, pQuery, false); 
        Marshal.StructureToPtr(descriptor, pDescriptor, false); 
         
        frFunc.ZeroMemory(pQuery, querySize); 
        frFunc.ZeroMemory(pDescriptor, descriptorSize); 
         
        bResult = frFunc.DeviceIoControl(hnd, frConst.IOCTL_STORAGE_QUERY_PROPERTY, 
                                         pQuery, querySize, pDescriptor, descriptorSize, 
                                         ref bytesReturned, IntPtr.Zero); 
                                         
        descriptor = (frFunc.STORAGE_DEVICE_DESCRIPTOR)Marshal.PtrToStructure(pDescriptor, typeof(frFunc.STORAGE_DEVICE_DESCRIPTOR)); 

        frFunc.CloseHandle(hnd); 
        Marshal.FreeHGlobal(pQuery); 
        Marshal.FreeHGlobal(pDescriptor); 
    } 
    return bResult; 
}

Die Werte sehen richtig aus, befinden sich aber irgendwie am falschen Platz.
Das sieht man ganz gut, wenn man das Attribut RawDeviceProperties[512] gegenüberstellt:

ausblenden volle Höhe Vergleich
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
                            Delphi            CSharp
Version                     40 (DWord)        40 (uint)
Size                        328 (DWord)       328 (uint)
DeviceType                  0 (Byte)          0 (byte)
DeviceTypeModifier          0 (Byte)          0 (byte)
RemovableMedia              False (Boolean)   True (bool)
CommandQueueing             True (Boolean)    True (bool)
VendorIdOffset              40 (DWord)        66 (uint)
ProductIdOffset             49 (DWord)        71 (uint)
ProductRevisionOffset       66 (DWord)        11 (uint)
SerialNumberOffset          71 (DWord)        0 (uint)
BusType                     11 (Byte)         0 (byte)
RawPropertiesLength         0 (DWord)         541152321 (uint)
RawDeviceProperties  
byte[512
-> Werte größer 0 bei 
                            ---------         [0] = 32
                            [4] = 65          [1] = 32
                            [5] = 84          [2] = 32
                            [6] = 65          [3] = 32
                            [7] = 32          ---------
                            [8] = 32          [5] = 87
                            [9] = 32          [6] = 68
                            [10] = 32         [7] = 67
                            [11] = 32         [8] = 32
                            ---------         [9] = 87
                            [13] = 87         [10] = 68
                            [14] = 68         [11] = 49
                            [15] = 67         [12] = 48
                            [16] = 32         [13] = 69
                            [17] = 87         [14] = 90
                            [18] = 68         [15] = 69 
                            [19] = 49         [16] = 88
                            [20] = 48         [17] = 45
                            [21] = 69         [18] = 48
                            [22] = 90         [19] = 48 
                            [23] = 69         [20] = 90
                            [24] = 88         --------- 
                            [25] = 45         [22] = 48
                            [26] = 48         [23] = 65 
                            [27] = 48         [24] = 56
                            [28] = 90         [25] = 48
                            ---------         ---------
                            [30] = 48         [27] = 32
                            [31] = 65         [28] = 32
                            [32] = 56         [29] = 32
                            [33] = 48         [30] = 32 
                            ---------         [31] = 32
                            [35] = 32         [32] = 87
                            [36] = 32         [33] = 68 
                            [37] = 32         [34] = 45
                            [38] = 32         [35] = 87
                            [39] = 32         [36] = 77
                            [40] = 87         [37] = 67
                            [41] = 68         [38] = 49
                            [42] = 45         [39] = 83
                            [43] = 87         [40] = 49
                            [44] = 77         [41] = 51
                            [45] = 67         [42] = 49
                            [46] = 49         [43] = 48
                            [47] = 83         [44] = 51
                            [48] = 49         [45] = 49
                            [49] = 51         [46] = 52
                            [50] = 49         ---------
                            [51] = 48
                            [52] = 51
                            [53] = 49
                            [54] = 52
                            ---------

Es ist um 8 Stellen/Bytes verschoben. Ist es auf die Größe von descriptor zurückzuführen, der den Wert 548 (Delphi) / 556 (C#) hat?
Die query ist bei beiden auf 12.
Und überhaupt: Wo kommt der Größenunterschied her, da die Defintion des STORAGE_DEVICE_DESCRIPTOR structs in beiden Sprachen identisch ist:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
STORAGE_DEVICE_DESCRIPTOR = record
  Version: DWord;
  Size: DWord;
  DeviceType: Byte;
  DeviceTypeModifier: Byte;
  RemovableMedia: Boolean;
  CommandQueueing: Boolean;
  VendorIdOffset: DWord;
  ProductIdOffset: DWord;
  ProductRevisionOffset: DWord;
  SerialNumberOffset: DWord;
  BusType: Byte;  // TStorageBusType;
  RawPropertiesLength: DWord;
  RawDeviceProperties: array[0..511of Byte;
end;

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
[StructLayout(LayoutKind.Sequential)] 
public struct STORAGE_DEVICE_DESCRIPTOR 

    public uint Version; 
    public uint Size; 
    public byte DeviceType; 
    public byte DeviceTypeModifier; 
    public bool RemovableMedia; 
    public bool CommandQueueing; 
    public uint VendorIdOffset; 
    public uint ProductIdOffset; 
    public uint ProductRevisionOffset; 
    public uint SerialNumberOffset; 
    public byte BusType; // STORAGE_BUS_TYPE 
    public uint RawPropertiesLength; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] 
    public byte[] RawDeviceProperties; 
}

Letzteres ist dem Dateianhang aus dem 1. Beitrag zu entnehmen.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3743
Erhaltene Danke: 762

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 21.06.17 08:16 
Schau dir mal genau die Werte bei dem Vergleich an (z.B. der Wert 11, in Delphi bei SerialNumberOffset, in C# aber bei ProductIdOffset)! Außerdem entspricht die Zahl 541152321 in Hex 0x20415441 (was wiederum 32 65 84 65 entspricht, also den bei Delphi ausgegeben Werten von RawDeviceProperties [3]-[6]).
Ich tippe also darauf, daß
ausblenden Delphi-Quelltext
1:
sizeof(Boolean)					
den Wert 1 hat, aber in C# per Default-Marshalling 4.

Probiere daher mal
ausblenden C#-Quelltext
1:
2:
3:
4:
[MarshalAs(UnmanagedType.U1)]
public bool RemovableMedia;
[MarshalAs(UnmanagedType.U1)]
public bool CommandQueueing;

s.a. Default Marshaling for Boolean Types

PS: Steht auch so in P/Invoke: STORAGE_DEVICE_DESCRIPTOR (Structures) ;-)

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2008
Erhaltene Danke: 368

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mi 21.06.17 08:52 
Hätte sein können, ist aber nicht so. Delphi und C# geben für sizeof(Boolean) = 1 Byte aus. Die Array-Größe im verlinkten Beitrag kommt mir viel zu klein vor mit 0x16 (22). Wenn es nach MSDN ginge, müsste es 1 lang sein.

Das Marshal-Attribut könnte ich setzen, es würde nur nichts bringen.

Nachtrag

Nach Setzen des Attributs [MarshalAs(UnmanagedType.U1)] sind die Werte zufriedenstellend.
Egal was ich vorhin schrieb, ich nehm's zurück. :mrgreen:

Das Problem ist somit gelöst, aber eins noch: Weisst du vielleicht, ob C#, ähnlich wie C++ (&) und Delphi (@), einen Adress-Operator hat?
Wenn es ginge, würde ich auf sowas wie: Marshal.AllocHGlobal(), Marshal.StructureToPtr(), Marshal.PtrToStructure(), Marshal.FreeHGlobal() gern verzichten.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 3743
Erhaltene Danke: 762

Win7
C++, C# (VS 2015/17)
BeitragVerfasst: Mi 21.06.17 10:07 
Die Array-Größe ist ja dynamisch (entsprechend RawPropertiesLength), daher ist es eigentlich egal, wie groß man das statische Array in der Struktur macht (kommt nur auf die Sprache an, wie diese damit umgehen kann).

Analog zu C++ kennt auch C# den address-of-Operator, aber dieser ist nur im unsafe-Kontext verwendbar. Für die Übergabe per Marshalling wirst du diesen aber nicht verwenden können.

Für diesen Beitrag haben gedankt: Frühlingsrolle
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4264
Erhaltene Danke: 851


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 21.06.17 10:26 
Die Adresse von irgendwas ist ja eigentlich auch nur glaubhaft für gepinnten/gefixten Speicher. Das wird sehr schnell sehr unschön.

Bei pinvoke klingt das auch falsch. Marshalling ist ja eher ein Kopiervorgang den ein Referenziervorgang. Es werden Daten aus dem unmanaged Memory in den managed Memory kopiert (oder halt umgekehrt). Eine gemeinsame Adresse von Caller und Callee die man sinnvoll teilen könnte gibt es nicht.

Für diesen Beitrag haben gedankt: Frühlingsrolle
Frühlingsrolle Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2008
Erhaltene Danke: 368

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mi 21.06.17 10:58 
Danke Th69, danke Ralf Jansen!

Jetzt habe ich einen besseren Eindruck davon, welche Schwierigkeiten ein Unmanaged Code in der .NET Umgebung verursachen kann und wie ich dem entgegenwirken soll. Das war eine gute Übung, wenn auch nicht gewollt.

Das Thema hat sich erledigt !!!

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)