DeviceIOControl works but output buffer contains all zeros

G

Guest

I am trying to query the change journal using the deviceIOControl API. The API doesn't return an error, but all of the values in the output buffer are zero, and they shouldn't be. My code is below. I have also tried specifying different pack values in my USN_JOURNAL_DATA structure definition but this didn't change anything. Any help would be greatly appreciated

Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const OPEN_EXISTING = 3
Private Const METHOD_BUFFERED = &H0
Private Const FILE_DEVICE_FILE_SYSTEM = &H9
Private Const FILE_ANY_ACCESS = &H0
Private Const FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Public Structure USN_JOURNAL_DATA
Public UsnJournalID As Long
Public FirstUsn As Int64
Public NextUsn As Int64
Public LowestValidUsn As Int64
Public MaxUsn As Int64
Public MaximumSize As Long
Public AllocationDelta As Long
End Structure

Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal DesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long

Declare Auto Function DeviceIoControl Lib "kernel32.dll" (ByVal hDevice As Long, ByVal dwIoControlCode As Integer, ByVal lpInBuffer As Integer, ByVal nInBufferSize As Integer, <MarshalAs(UnmanagedType.Struct)> ByRef lpOutBuffer As USN_JOURNAL_DATA, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Long


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim FSCTL_QUERY_USN_JOURNAL As Long = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 61, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
Dim aHandle As Long
Dim anObject As Long
Dim byteBack As Long
Dim ujd As USN_JOURNAL_DATA

aHandle = CreateFile("\\.\I:", 0&, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0&, 0&)
anObject = DeviceIoControl(aHandle, FSCTL_QUERY_USN_JOURNAL, 0, 0, ujd, Marshal.SizeOf(ujd), byteBack, 0)
If anObject = 0 Then
MsgBox(Marshal.GetLastWin32Error.ToString & Marshal.GetHRForLastWin32Error.ToString)
Else
MsgBox(ujd.UsnJournalID.ToString)
MsgBox(ujd.UsnJournalID)
MsgBox(ujd.FirstUsn)
MsgBox(ujd.NextUsn)
MsgBox(ujd.MaxUsn)
MsgBox(ujd.LowestValidUsn)
MsgBox(ujd.AllocationDelta)
MsgBox(ujd.MaximumSize)
End If
End Sub

Public Function CTL_CODE(ByVal DeviceType As Integer, ByVal Func As Integer, ByVal Method As Integer, ByVal Access As Integer) As Long
Return (DeviceType << 16) Or (Access << 14) Or (Func << 2) Or Method
End Function
 
H

Herfried K. Wagner [MVP]

* "=?Utf-8?B?UGl4aWU=?= said:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Public Structure USN_JOURNAL_DATA
Public UsnJournalID As Long
Public FirstUsn As Int64
Public NextUsn As Int64
Public LowestValidUsn As Int64
Public MaxUsn As Int64
Public MaximumSize As Long
Public AllocationDelta As Long
End Structure

Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal DesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long

Declare Auto Function DeviceIoControl Lib "kernel32.dll" (ByVal hDevice As Long, ByVal dwIoControlCode As Integer, ByVal lpInBuffer As Integer, ByVal nInBufferSize As Integer, <MarshalAs(UnmanagedType.Struct)> ByRef lpOutBuffer As USN_JOURNAL_DATA, ByVal nOutBufferSize As Integer, ByRef lpBytesReturned As Integer, ByVal lpOverlapped As Integer) As Long

Notice that 'Long' is a 64-bit datatype in .NET, but 'DWORD' is 32-bit.
You will have to change some of the 'As Long' to 'As Int32'.
 
Joined
Oct 20, 2005
Messages
2
Reaction score
0
Supplementary extension

Thanks for the code which was helpful for me to translate (to VB6) and get started.

I can not read the records as the DeviceIoControl function always returns the error "The supplied user buffer is not valid for the requested operation.". I have tried creating the buffer in every way I can conceive of (local, global, module variables and heap) but can't see what is going wrong. A pointer to get me started again would be great.

Thanks,
Bruce

Code:
Private Declare Function DeviceIoControlA Lib "kernel32.dll" Alias "DeviceIoControl" (ByVal hDevice As Long, ByVal dwIoControlCode As Long, lpInBuffer As Any, ByVal nInBufferSize As Long, ByVal lpOutBuffer As Long, ByVal nOutBufferSize As Long, ByRef lpBytesReturned As Long, lpOverlapped As OVERLAPPED) As Long

Private Type USN
    Lo As Long
    Hi As Long
End Type

Private Type CJDataType
    NextUsn As USN
    CJData(USN_PAGE_SIZE - 8) As Byte
End Type
Private CJData As CJDataType

Private Type READ_USN_JOURNAL_DATA
    StartUsn As USN
    ReasonMask As USN_REASONS
    ReturnOnlyOnClose As Boolean
    Timeout As Int64
    BytesToWaitFor As Int64
    UsnJournalID As Int64
End Type

Private Sub Form_Load()
Dim FSCTL_QUERY_USN_JOURNAL As Long
Dim FSCTL_READ_USN_JOURNAL As Long
Dim hCJ As Long
Dim ret As Long
Dim BytesReturned As Long
Dim ujd As USN_JOURNAL_DATA
Dim rujd As READ_USN_JOURNAL_DATA
Dim dPtr As Long, hHeap As Long
Dim CJData As CJDataType

    FSCTL_QUERY_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 61, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
    FSCTL_READ_USN_JOURNAL = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_ANY_ACCESS)
    
    hHeap = GetProcessHeap()
    If hHeap = 0 Then Exit Sub
    dPtr = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS Or HEAP_ZERO_MEMORY, USN_PAGE_SIZE)
    If dPtr = 0 Then
       Debug.Print "memory allocation failed!"
       Exit Sub
    Else
        Debug.Print Hex(dPtr) & " " & VarPtr(CJData)
        Debug.Print HeapSize(hHeap, 0, dPtr)
    End If
    
    hCJ = CreateFile("\\.\C:", GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0&, 0&)
    
    ' Recall change cournal statistics
    ret = DeviceIoControl(hCJ, FSCTL_QUERY_USN_JOURNAL, 0, 0, ujd, Len(ujd), BytesReturned, olData)
    If ret = 0 Or BytesReturned <> Len(ujd) Then
        MsgBox WinAPIError
    Else
        BytesReturned = 0
        rujd.UsnJournalID = ujd.UsnJournalID
        rujd.StartUsn = ujd.FirstUsn
        rujd.ReasonMask = USN_MASK_ALL_REASONS ' Get every record
        'rujd.ReturnOnlyOnClose = False
        Do
            ' Get some records from the journal
            'ret = DeviceIoControl(hCJ, FSCTL_READ_USN_JOURNAL, rujd, Len(rujd), CJData, USN_PAGE_SIZE, BytesReturned, olData)
            ret = DeviceIoControlA(hCJ, FSCTL_READ_USN_JOURNAL, rujd, Len(rujd), dPtr, USN_PAGE_SIZE, BytesReturned, olData)
            If ret = 0 Or BytesReturned <= Len(rujd) Then
                Debug.Print WinAPIError()
                Exit Do
            End If
            Stop
        Loop While True
    End If
    ret = HeapFree(hHeap, 0, dPtr)
    CloseHandle hCJ
End Sub
 
Joined
Oct 20, 2005
Messages
2
Reaction score
0
Solved - similar problem

Solved it myself after leaving it for another couple of hours. Boolean's must only be 2 bytes long, making the input length incorrect but the error message focused my attention on what wasn't being returned when I should have been looking at what was sent to DeviceIoCtrl!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top