none
Can't get unmaged type ByValArray to compile RRS feed

  • Question

  • I have to add some privileges to my process token, so I tried this code [VB.Net]. The location of the problem is "ByValArray" near the bottom.

     <StructLayout(LayoutKind.Sequential)> Private Structure LUID
    
      Dim LowPart As Int32
    
      Dim HighPart As Int32
    
     End Structure
    
    
    
     <StructLayout(LayoutKind.Sequential)> Private Structure LUID_AND_ATTRIBUTES
    
      Dim pLuid As LUID
    
      Dim Attributes As Int32
    
     End Structure
    
    
    
     <StructLayout(LayoutKind.Sequential)> Private Structure TOKEN_PRIVILEGES
    
      Public PrivilegeCount As Int32
    
      <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> Public Privileges() As LUID_AND_ATTRIBUTES
    
     End Structure
    
    
    
    
    ANYSIZE_ARRAY is a Const defined higher up as having a value of 1.

    My problem:

    • It won't compile in a release build. The compiler fails with "Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."
    • It will compile in a debug build, but it won't run very far: it fails with an exception saying it can't load the type that corresponds to the class these declarations are in (the type is given as project-root-namespace.classname), at entry of the first function that uses something in that class.
    • When I change "ByValArray" to "SafeArray" both these problems disappear, it will compile and run, but (of course) the call to AdjustTokenPrivileges where I pass it fails with "invalid argument".
    • Making it an LPArray (or anything else I tried) also compiles and runs, but (again expected) it will tell you that it can't marshal the Privileges field because it has to be marshaled as either a SafeArray or a ByValArray.

    Already tried:

    • Because my day-to-day machine is a Windows 7 64 bit with VS2010 without SP1, tried it on an XP 32 bit with VS2010 with SP1.
      Project properties were set to build for X86 platform both times, both gave the exact same error.
    • Followed a suggestion I found somewhere on the web, to delete the bin and obj folders and recompile: no change.
    • Found nearly identical code at http://www.pinvoke.net/default.aspx/advapi32/adjusttokenprivileges.html?diff=y
      Copied the declaration of the TOKEN_PRIVILEGES structure I found there into my own code and made the rest fit it: doesn't make any difference.

    BTW, the class contains nothing but structure declarations, API function declarations, and a few shared (static, for non-VB-ers) wrapper functions around the rest.

    • Edited by lucvdv Monday, March 21, 2011 3:06 PM
    Monday, March 21, 2011 2:52 PM

Answers

  •  

    We may need to refine the definition of TOKEN_PRIVILEGES struct, remove brackets of its Privileges field, something like:

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure TOKEN_PRIVILEGES

            Public PrivilegeCount As UInt32

            <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _

            Public Privileges As LUID_AND_ATTRIBUTES

        End Structure


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by eryang Monday, April 11, 2011 3:16 AM
    Tuesday, March 29, 2011 2:04 AM
  • Hi lucvdv,

    I did a test according to the sample given by Pinvoke.NET site, but it works well on my computer (Win7 32bit, VS2008 sp1), here is my test code, you may have a try:

    It is a simple VB Console application, which contains two files: Module1.vb and NativeAPI.vb

    ' FileName: NativeAPI.vb

     

    Imports System.Runtime.InteropServices

     

    Public Class NativeAPI

     

        Const ANYSIZE_ARRAY As Integer = 1

        Const TOKEN_QUERY As Integer = &H8

        Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20

        Const SE_SHUTDOWN_NAME As String = "SeShutdownPrivilege"

        Const SE_PRIVILEGE_ENABLED As Integer = &H2

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure LUID

            Dim LowPart As UInt32

            Dim HighPart As UInt32

        End Structure

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure LUID_AND_ATTRIBUTES

            Dim pLuid As LUID

            Dim Attributes As UInt32

        End Structure

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure TOKEN_PRIVILEGES

            Public PrivilegeCount As UInt32

            <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _

            Public Privileges() As LUID_AND_ATTRIBUTES

        End Structure

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function LookupPrivilegeValue( _

         ByVal lpSystemName As String, _

         ByVal lpName As String, _

         ByRef lpLuid As LUID _

          ) As Boolean

        End Function

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function OpenProcessToken( _

         ByVal ProcessHandle As IntPtr, _

         ByVal DesiredAccess As Integer, _

         ByRef TokenHandle As IntPtr _

          ) As Boolean

        End Function

     

        <DllImport("kernel32.dll", SetLastError:=True)> _

        Public Shared Function CloseHandle(ByVal hHandle As IntPtr) As Boolean

        End Function

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function AdjustTokenPrivileges( _

           ByVal TokenHandle As IntPtr, _

           ByVal DisableAllPrivileges As Boolean, _

           ByRef NewState As TOKEN_PRIVILEGES, _

           ByVal BufferLength As Integer, _

           ByRef PreviousState As TOKEN_PRIVILEGES, _

           ByRef ReturnLength As IntPtr _

         ) As Boolean

        End Function

     

    End Class

     

     

    ' FileName: Module1.vb

     

    Module Module1

     

        Sub Main()

     

            ' For test purpose, I mock those parameters.

            Dim tokenHandle As IntPtr = IntPtr.Zero

            Dim disableAllPrivileges As Boolean = False

            Dim newState As NativeAPI.TOKEN_PRIVILEGES = New NativeAPI.TOKEN_PRIVILEGES()

            Dim bufferLength As Integer = 100

            Dim previousState As NativeAPI.TOKEN_PRIVILEGES = New NativeAPI.TOKEN_PRIVILEGES()

            Dim returnLength As IntPtr = IntPtr.Zero

     

            ' here the AdjustTokenPrivileges function returns False.

            Dim result = NativeAPI.AdjustTokenPrivileges(tokenHandle, disableAllPrivileges, newState, bufferLength, previousState, returnLength)

     

        End Sub

     

    End Module


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by eryang Monday, April 11, 2011 3:16 AM
    Tuesday, March 22, 2011 8:49 AM

All replies

  • Is it just me, or doesn't IE9 like code sections in posts over here?  ;)

     

    Monday, March 21, 2011 2:59 PM
  • Hi lucvdv,

    I did a test according to the sample given by Pinvoke.NET site, but it works well on my computer (Win7 32bit, VS2008 sp1), here is my test code, you may have a try:

    It is a simple VB Console application, which contains two files: Module1.vb and NativeAPI.vb

    ' FileName: NativeAPI.vb

     

    Imports System.Runtime.InteropServices

     

    Public Class NativeAPI

     

        Const ANYSIZE_ARRAY As Integer = 1

        Const TOKEN_QUERY As Integer = &H8

        Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20

        Const SE_SHUTDOWN_NAME As String = "SeShutdownPrivilege"

        Const SE_PRIVILEGE_ENABLED As Integer = &H2

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure LUID

            Dim LowPart As UInt32

            Dim HighPart As UInt32

        End Structure

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure LUID_AND_ATTRIBUTES

            Dim pLuid As LUID

            Dim Attributes As UInt32

        End Structure

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure TOKEN_PRIVILEGES

            Public PrivilegeCount As UInt32

            <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _

            Public Privileges() As LUID_AND_ATTRIBUTES

        End Structure

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function LookupPrivilegeValue( _

         ByVal lpSystemName As String, _

         ByVal lpName As String, _

         ByRef lpLuid As LUID _

          ) As Boolean

        End Function

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function OpenProcessToken( _

         ByVal ProcessHandle As IntPtr, _

         ByVal DesiredAccess As Integer, _

         ByRef TokenHandle As IntPtr _

          ) As Boolean

        End Function

     

        <DllImport("kernel32.dll", SetLastError:=True)> _

        Public Shared Function CloseHandle(ByVal hHandle As IntPtr) As Boolean

        End Function

     

        <DllImport("advapi32.dll", SetLastError:=True)> _

        Public Shared Function AdjustTokenPrivileges( _

           ByVal TokenHandle As IntPtr, _

           ByVal DisableAllPrivileges As Boolean, _

           ByRef NewState As TOKEN_PRIVILEGES, _

           ByVal BufferLength As Integer, _

           ByRef PreviousState As TOKEN_PRIVILEGES, _

           ByRef ReturnLength As IntPtr _

         ) As Boolean

        End Function

     

    End Class

     

     

    ' FileName: Module1.vb

     

    Module Module1

     

        Sub Main()

     

            ' For test purpose, I mock those parameters.

            Dim tokenHandle As IntPtr = IntPtr.Zero

            Dim disableAllPrivileges As Boolean = False

            Dim newState As NativeAPI.TOKEN_PRIVILEGES = New NativeAPI.TOKEN_PRIVILEGES()

            Dim bufferLength As Integer = 100

            Dim previousState As NativeAPI.TOKEN_PRIVILEGES = New NativeAPI.TOKEN_PRIVILEGES()

            Dim returnLength As IntPtr = IntPtr.Zero

     

            ' here the AdjustTokenPrivileges function returns False.

            Dim result = NativeAPI.AdjustTokenPrivileges(tokenHandle, disableAllPrivileges, newState, bufferLength, previousState, returnLength)

     

        End Sub

     

    End Module


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by eryang Monday, April 11, 2011 3:16 AM
    Tuesday, March 22, 2011 8:49 AM
  • I compiles and works here too, in VS2010.

    I copied the code that won't compile from my own project into a new class file in this test project, changed the Main function to use that version, and it still doesn't work.  I get this when the app is started in the debugger, before any code is executed:

    TypeLoadException was unhandled
    
    
    
    Could not load 
    
     type 'TestPrivileges.Win32Module+TOKEN_PRIVILEGES'
    
     from assembly 'TestPrivileges, Version=1.0.0.0,
    
     Culture=neutral, PublicKeyToken=null'.

    The urgency is gone at this side because I rewrote the app to circumvent the problem, but I'm still interested in knowing the reason.

    The app is an update installer that upgrades an internal application along with its database, etc.  One of the things it has to do is load registry hives of certain users that are currently not logged in, add a key, and unload them again.  Instead of getting the privileges itself, the app now uses reg.exe to load and unload hives.

    This code was supposed to enable the backup/restore privileges to enable hive loading and unloading (Nothing changed except for the Private's that I made Public's for this test):

    Imports System.Runtime.InteropServices
    
    
    
    Class Win32Module
    
    
    
     Public Const ANYSIZE_ARRAY = 1
    
     Public Const TOKEN_ADJUST_PRIVLEGES = &H20
    
     Public Const TOKEN_QUERY = &H8
    
     Public Const SE_PRIVILEGE_ENABLED = &H2
    
     Public Const HKEY_USERS As Int32 = &H80000003
    
     Public Const SE_RESTORE_NAME = "SeRestorePrivilege"
    
     Public Const SE_BACKUP_NAME = "SeBackupPrivilege"
    
    
    
     <StructLayout(LayoutKind.Sequential)> Public Structure LUID
    
      Dim LowPart As Int32
    
      Dim HighPart As Int32
    
     End Structure
    
    
    
     <StructLayout(LayoutKind.Sequential)> Public Structure LUID_AND_ATTRIBUTES
    
      Dim Luid As LUID
    
      Dim Attributes As Int32
    
     End Structure
    
    
    
     <StructLayout(LayoutKind.Sequential)> Public Structure TOKEN_PRIVILEGES
    
      Public PrivilegeCount As Int32
    
      <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _
    
      Public Privileges() As LUID_AND_ATTRIBUTES
    
     End Structure
    
    
    
     Public Declare Auto Function GetCurrentProcess Lib "kernel32" () As IntPtr
    
    
    
     Public Declare Auto Function OpenProcessToken Lib "advapi32.dll" _
    
      (ByVal ProcessHandle As IntPtr, _
    
       ByVal DesiredAccess As Int32, _
    
       ByVal TokenHandle As Int32) _
    
      As Int32
    
    
    
     Public Declare Auto Function LookupPrivilegeValue Lib "advapi32.dll" _
    
      (ByVal lpSystemName As String, _
    
       ByVal lpName As String, _
    
       ByRef lpLuid As LUID) _
    
      As Int32
    
    
    
     Public Declare Auto Function AdjustTokenPrivileges Lib "advapi32.dll" _
    
      (ByVal TokenHandle As Int32, _
    
       ByVal DisableAllPrivileges As Int32, _
    
       ByRef NewState As TOKEN_PRIVILEGES, _
    
       ByVal BufferLength As Int32, _
    
       ByRef PreviousState As TOKEN_PRIVILEGES, _
    
       ByVal ReturnLength As Int32) _
    
      As Int32
    
    
    
     Public Declare Auto Function RegLoadKey Lib "advapi32.dll" _
    
      (ByVal hKey As Int32, _
    
       ByVal lpSubKey As String, _
    
       ByVal lpFile As String) _
    
      As Int32
    
    
    
     Public Declare Auto Function RegUnLoadKey Lib "advapi32.dll" _
    
      (ByVal hKey As Int32, _
    
       ByVal lpSubKey As String) _
    
      As Int32
    
    
    
     Public Shared MyToken As Int32
    
     Public Shared TP As TOKEN_PRIVILEGES
    
    
    
     Public Shared Initialized As Boolean = False
    
    
    
     Public Shared Sub Initialize()
    
      Dim Retval As Int32
    
      Dim RestoreLuid As New LUID
    
      Dim BackupLuid As New LUID
    
    
    
      Retval = OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVLEGES _
    
       Or TOKEN_QUERY, MyToken)
    
      '  If Retval = 0 Then MsgBox("OpenProcess: " & Err.LastDllError)
    
    
    
      Retval = LookupPrivilegeValue("", SE_RESTORE_NAME, RestoreLuid)
    
      '  If Retval = 0 Then MsgBox("LookupPrivileges: " & Err.LastDllError)
    
    
    
      Retval = LookupPrivilegeValue("", SE_BACKUP_NAME, BackupLuid)
    
      '  If Retval = 0 Then MsgBox("LookupPrivileges: " & Retval)
    
    
    
      TP.PrivilegeCount = 2
    
      ReDim TP.Privileges(1)
    
      TP.Privileges(0).Luid = RestoreLuid
    
      TP.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
    
      TP.Privileges(1).Luid = BackupLuid
    
      TP.Privileges(1).Attributes = SE_PRIVILEGE_ENABLED
    
    
    
      Retval = AdjustTokenPrivileges(MyToken, 0, TP, Len(TP), Nothing, 0&)
    
      '  If Retval = 0 Then MsgBox("AdjustTokenPrivileges: " & Err.LastDllError)
    
    
    
      Initialized = True
    
     End Sub
    
    
    
     Public Shared Function LoadRegistryKey(ByVal FilePath As String, ByVal KeyName As String) As Int32
    
      If Not Initialized Then Initialize()
    
      Return RegLoadKey(HKEY_USERS, KeyName, FilePath)
    
     End Function
    
    
    
     Public Shared Function UnloadRegistryKey(ByVal KeyName As String) As Int32
    
      If Not Initialized Then Initialize()
    
      Return RegUnLoadKey(HKEY_USERS, KeyName)
    
     End Function
    
    
    
     Public Shared Sub UnInitialize()
    
      If Initialized Then
    
       AdjustTokenPrivileges(MyToken, vbTrue, TP, Len(TP), Nothing, 0&)
    
       Initialized = False
    
      End If
    
     End Sub
    
    
    
    
    • Edited by lucvdv Wednesday, March 23, 2011 9:57 AM
    Wednesday, March 23, 2011 8:07 AM
  • BTW, I did try and replace the Int32's by UInt32's.  It makes no difference.

    For the rest I only see differences in the way DLL entry points are declared, but that shouldn't make any difference, the error clearly indicates the structure.

    ----

    Now tried in VS2008 too, still the same.

    I put up a screenshot at http://r-and-d.eurautomat.net/images/TypeLoadException.png

    The debugger was started by clicking the "step into" button, the exception occurred before it reached any code.

     

    Wednesday, March 23, 2011 8:11 AM
  •  

    I reproduced this issue with your code, but if I remove the declaration of TP field:

     

    Public Shared TP As TOKEN_PRIVILEGES

     

    It will work, you can have a try.

     

    However, I'm not sure about the reason, you may try this question at Visual Basic General forum where VB experts live in.


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Saturday, March 26, 2011 8:15 AM
  • Thanks.  I'll try to shorten the code to the minimum that exposes the problem and give it a try there.

    I noticed (thanks to your latest post) an error I made in the original code: the TP you removed should have been declared as "New".  Fixing that doesn't help with the original problem though, it still throws the same exception.

    Now I also noticed a missing 'New' in my code, but that wasn't it ;)

    ---

    I started reducing the code, and now I find that the error occurs as soon as an instance of TOKEN_PRIVILEGES is declared in both the main module and one in the win32 module.  Comment either of the 'Dim [...] As TOKEN_PRIVILEGES' lines out in the code below, and it works.

    Module Module1
    
      Sub Main()
        Dim newState As Win32Module.TOKEN_PRIVILEGES = New Win32Module.TOKEN_PRIVILEGES
      End Sub
    
    End Module
    
    Class Win32Module
    
      Public Const ANYSIZE_ARRAY = 1
      <StructLayout(LayoutKind.Sequential)> Public Structure LUID
        Dim LowPart As UInt32
        Dim HighPart As UInt32
      End Structure
    
      <StructLayout(LayoutKind.Sequential)> Public Structure LUID_AND_ATTRIBUTES
        Dim Luid As LUID
        Dim Attributes As UInt32
      End Structure
    
      <StructLayout(LayoutKind.Sequential)> Public Structure TOKEN_PRIVILEGES
        Public PrivilegeCount As UInt32
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _
        Public Privileges() As LUID_AND_ATTRIBUTES
      End Structure
    
      Public Shared TP As New TOKEN_PRIVILEGES
    
    End Class
    
    

     

    Monday, March 28, 2011 8:26 AM
  •  

    We may need to refine the definition of TOKEN_PRIVILEGES struct, remove brackets of its Privileges field, something like:

     

        <StructLayout(LayoutKind.Sequential)> _

        Public Structure TOKEN_PRIVILEGES

            Public PrivilegeCount As UInt32

            <MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)> _

            Public Privileges As LUID_AND_ATTRIBUTES

        End Structure


    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by eryang Monday, April 11, 2011 3:16 AM
    Tuesday, March 29, 2011 2:04 AM
  • The discussion has been continued in the VB.general forum, but it's beginning to look like that may not have been the best choice.

    The problem also manifests itself when the code is translated to C#.

    Something else that came out there: it's worse if the target framework is v2 (if v4 ever does it at all, of which I'm not certain).

     

    Wednesday, March 30, 2011 7:37 AM
  • Did you try remove brackets of Privileges field of TOKEN_PRIVILEGES struct, does it help?
    Eric Yang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, April 1, 2011 1:58 AM
  • Yes, it helps.
    Friday, April 1, 2011 6:03 AM