Can't get BuildExplicitAccessWithName API to work in 64-bit VB.Net

graye
graye used Ask the Experts™
on
I've tried every conceivable P/Invoke signatures to both the API and 2 strutures and I still can't get BuildExplicitAccessWithName API to work when compiled against the "AnyCPU" or "x64" target.

Help!

BTW: The code below works just fine when compiled against the "x86" target
Imports System.Runtime.InteropServices
 
Module Module1
 
    Private Const CONTAINER_INHERIT_ACE As Integer = &H2
    Private Const OBJECT_INHERIT_ACE As Integer = &H1
    Private Const SET_ACCESS As Integer = &H2
 
    Private Const SYNCHRONIZE As Integer = &H100000
    Private Const READ_CONTROL As Integer = &H20000
    Private Const WRITE_DAC As Integer = &H40000
    Private Const WRITE_OWNER As Integer = &H80000
    Private Const STANDARD_RIGHTS_READ As Integer = (READ_CONTROL)
    Private Const STANDARD_RIGHTS_WRITE As Integer = (READ_CONTROL)
    Private Const DELETE As Integer = &H10000
    Private Const FILE_DELETE_CHILD As Integer = &H40
    Private Const FILE_ALL_ACCESS As Integer = &HF0000 Or SYNCHRONIZE Or &H1FF
 
    'typedef struct _TRUSTEE {
    '  PTRUSTEE pMultipleTrustee;
    '  MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
    '  TRUSTEE_FORM TrusteeForm;
    '  TRUSTEE_TYPE TrusteeType;
    '  LPTSTR ptstrName;
    '} TRUSTEE, *PTRUSTEE;
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Public Structure TRUSTEE
        Dim pMultipleTrustee As IntPtr
        Dim MultipleTrusteeOperation As Integer
        Dim TrusteeForm As Integer
        Dim TrusteeType As Integer
        Dim ptstrName As String
    End Structure
 
    'typedef struct _EXPLICIT_ACCESS {
    '  DWORD grfAccessPermissions;
    '  ACCESS_MODE grfAccessMode;
    '  DWORD grfInheritance;
    '  TRUSTEE Trustee;
    '} EXPLICIT_ACCESS, *PEXPLICIT_ACCESS;
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Public Structure EXPLICIT_ACCESS
        Dim grfAccessPermissions As Integer
        Dim grfAccessMode As Integer
        Dim grfInheritance As Integer
        Dim Trustee As TRUSTEE
    End Structure
 
    'VOID BuildExplicitAccessWithName(
    '  PEXPLICIT_ACCESS pExplicitAccess,
    '  LPTSTR pTrusteeName,
    '  DWORD AccessPermissions,
    '  ACCESS_MODE AccessMode,
    '  DWORD Inheritance
    ');
    Declare Auto Sub BuildExplicitAccessWithName Lib "AdvAPI32.DLL" ( _
        ByRef pExplicitAccess As EXPLICIT_ACCESS, _
        ByVal pTrusteeName As String, _
        ByVal AccessPermissions As Integer, _
        ByVal AccessMode As Integer, _
        ByVal Inheritance As Integer _
    )
 
    Sub Main()
        Dim ea As New EXPLICIT_ACCESS
 
        Console.WriteLine("starting")
        BuildExplicitAccessWithName(ea, "Users", FILE_ALL_ACCESS, SET_ACCESS, CONTAINER_INHERIT_ACE Or OBJECT_INHERIT_ACE)
        Console.WriteLine("finished")
        Console.WriteLine("ea.Trustee.ptstrName='" & ea.Trustee.ptstrName & "'")
 
        Console.ReadLine()
    End Sub
 
End Module

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Corey ScheichDeveloper

Commented:
It appears that the API you are calling connects to an x32 process.  Is there any need for it to run as a 64 bit process?  A 32 bit process will run the same on a 64 and a 32 bit machine.   There are many reasons you may want it as a 64 bit process (RAM usage, Making API calls to another 64 bit process).


If you actually need to run as a x64 process it requires remoting to call 32bit API.  I would suggest an abstraction class that makes all the 32 bit calls on the 32 bit side of the fence and passes simple data types to the 64bit process.  I found this blog that lays out how to use IPC remoting the example is in c# but could be easily translated to vb.net using one of the many free translators out there.

http://weblogs.asp.net/israelio/archive/2005/01/04/346180.aspx

a translator

http://www.developerfusion.com/tools/convert/csharp-to-vb/

Commented:
I do not see how the code is connecting to an x32 process.  The call to BuildExplicitAccessWithName should work the same from either an x64 or x86 application.  Like graye, I have tried everything I know to get the call to work as an x64 bit application.

Having to make some progress, I decided to go with a x86 build.  However, I ran in to other APIs that I need to use that are unique to x64.

Commented:
I was doing some more research--I hate it when I get something to work--and found a note on pinvoke.net on the EXPLICT_ACCESS structure that said Pack:=4 does not work on an x64 bit system.  

See http://www.pinvoke.net/default.aspx/Structures/EXPLICIT_ACCESS.html

I changed the Pack:=4 to Pack:=0 on both the EXPLICIT_ACCESS and TRUSTEE structures and the application doesn't crash any more.

The code does not appear to work (I haven't researched why yet), but we may be on to something.
      <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, Pack:=0)> _
      Private Structure EXPLICIT_ACCESS
         Private grfAccessPermissions As Integer
         Private grfAccessMode As Integer
         Private grfInheritance As Integer
         <MarshalAs(UnmanagedType.Struct)> Private Trustee As TRUSTEE
      End Structure
      <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, Pack:=0)> _
      Private Structure TRUSTEE
         Private pMultipleTrustee As Integer ' must be null, so no need for IntPtr
         Private MultipleTrusteeOperation As Integer
         Private TrusteeForm As Integer
         Private TrusteeType As Integer
         Private ptstrName As String
      End Structure

Open in new window

CompTIA Network+

Prepare for the CompTIA Network+ exam by learning how to troubleshoot, configure, and manage both wired and wireless networks.

Author

Commented:
Yeah, I'm the one who intially put the API signatures on the P/Invoke wiki  (with the incorrect Pack:=4 and the pMultipleTrustee as Integer)
My example here has the corrected signatures.   I'll try the <MarshalAs(UnmanagedType.Struct)>  attribute and see what I can get out of it
From what I can tell, the 64-bit version of the API doesn't terminate the ptstrName string value with a null.   So, I think I'm gonna submit this as a bug to Microsoft.

Commented:
I can get it to do something.  Taking what you just wrote (ptstrName not being null terminated) with what I've seen, I think a bug report is justified.

When I run my test code that denies terminate to the current user for a process (graye helped me figure that out in a previous Experts Exchange question), as x86, it works.  When I run the code as x64 (outside of the Visual Studio environment, compiled as either debug or release), the username parameter of the API call is ignored and "BUILTIN" is used.  While this works for my purposes (for version 1 of my app), I will get to get this figured out sooner or later.

If I run the x64 bit code from within Visual Studio, the call works (no win32 error) but the the EA does not appear to be valid.  

Commented:
Okay...this is getting stranger.

If my test application starts in Sub Main, the call fails.  If the startup object is Form1, the call works.  I have duplicated this on two different computers (both running Vista x64).

I do not know what I did, but I can no longer duplicate my previous post.

Wierd.

Commented:
Me again....

I'm also getting different results between Release and Debug modes.
Corey ScheichDeveloper

Commented:
What about using Run as Admin on vista 64?
what is the trust level of the project?

Author

Commented:
Nope, UAC is off

Commented:
I was wrong about it acting differently between debug and release modes.  I did a step-by-step compare between and found that debug had optimizations turned off (the default) while release had it turn on (again, the default).

If I turn optimizations off, it does not crash.

So, I am where we started.  
* On an x86 system (XP and Windows 7) in debug or release with optimizations off, it appears to work.
* On a x64 system  (Vista) in debug or release with optimizations off, it does not work--best I can tell it is not returning an DACL or Owner (I'm haven't played with groups or SACLs)

BTW, I am compiling for "AnyCPU".  I may have been seeing some different results if I compiled for x86 or x64 and tested on the appropriate OSs.  

Unless there is a significant bug as it relates to x64 bit systems, I believe that something is wrong with the API signatures or structure layout.  Like graye, I've tried darn near everything combination with no real luck.

I've included the code that works (at least for me) below.  It is not very different from grayes.  
      <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, Pack:=0)> _
      Private Structure EXPLICIT_ACCESS
         Public grfAccessPermissions As Integer
         Public grfAccessMode As Integer
         Public grfInheritance As Integer
         <MarshalAs(UnmanagedType.Struct)> Public Trustee As TRUSTEE
      End Structure
      <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto, Pack:=0)> _
      Private Structure TRUSTEE
         Public pMultipleTrustee As Integer ' must be null, so no need for IntPtr
         Public MultipleTrusteeOperation As Integer
         Public TrusteeForm As Integer
         Public TrusteeType As Integer
         Public ptstrName As String
      End Structure
 
 
      <Security.Permissions.SecurityPermission(Security.Permissions.SecurityAction.Assert)> _
      Private Declare Auto Sub BuildExplicitAccessWithName Lib "AdvAPI32.DLL" ( _
         ByRef pExplicitAccess As EXPLICIT_ACCESS, _
         ByVal pTrusteeName As String, _
         ByVal AccessPermissions As Integer, _
         ByVal AccessMode As Short, _
         ByVal Inheritance As Integer)
 
 
Sub Main()
 
         Dim myEA As New EXPLICIT_ACCESS
 
         ' Build an explicit access structure
         BuildExplicitAccessWithName(myEA, UserName, iPerm, AccessMode.DENY_ACCESS, 0)   'CONTAINER_INHERIT_ACE Or OBJECT_INHERIT_ACE
 
End sub

Open in new window

Commented:
OK... it's time to close this question out.   Here is the latest evidence that there is a bug.
Notice, that I've switched to using a pointer (to eliminate the problem of the wrong signature for the structures).  I also, ignore the structure and look at the bytes returned.   The problem is that the pointer to the string value is truncated to 32-bits.  
I'm sending this to Microsoft as a bug

Imports System.Runtime.InteropServices
 
Module Module1
 
    Private Const CONTAINER_INHERIT_ACE As Integer = &H2
    Private Const OBJECT_INHERIT_ACE As Integer = &H1
    Private Const SET_ACCESS As Integer = &H2
 
    Private Const SYNCHRONIZE As Integer = &H100000
    Private Const READ_CONTROL As Integer = &H20000
    Private Const WRITE_DAC As Integer = &H40000
    Private Const WRITE_OWNER As Integer = &H80000
    Private Const STANDARD_RIGHTS_READ As Integer = (READ_CONTROL)
    Private Const STANDARD_RIGHTS_WRITE As Integer = (READ_CONTROL)
    Private Const DELETE As Integer = &H10000
    Private Const FILE_DELETE_CHILD As Integer = &H40
    Private Const FILE_ALL_ACCESS As Integer = &HF0000 Or SYNCHRONIZE Or &H1FF
 
    'typedef struct _TRUSTEE {
    '  PTRUSTEE pMultipleTrustee;
    '  MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
    '  TRUSTEE_FORM TrusteeForm;
    '  TRUSTEE_TYPE TrusteeType;
    '  LPTSTR ptstrName;
    '} TRUSTEE, *PTRUSTEE;
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Public Structure TRUSTEE
        Dim pMultipleTrustee As IntPtr
        Dim MultipleTrusteeOperation As Integer
        Dim TrusteeForm As Integer
        Dim TrusteeType As Integer
        'Dim ptstrName As String
        Dim ptstrName As IntPtr
    End Structure
 
    'typedef struct _EXPLICIT_ACCESS {
    '  DWORD grfAccessPermissions;
    '  ACCESS_MODE grfAccessMode;
    '  DWORD grfInheritance;
    '  TRUSTEE Trustee;
    '} EXPLICIT_ACCESS, *PEXPLICIT_ACCESS;
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
    Public Structure EXPLICIT_ACCESS
        Dim grfAccessPermissions As Integer
        Dim grfAccessMode As Integer
        Dim grfInheritance As Integer
        Dim Trustee As TRUSTEE
    End Structure
 
    'VOID BuildExplicitAccessWithName(
    '  PEXPLICIT_ACCESS pExplicitAccess,
    '  LPTSTR pTrusteeName,
    '  DWORD AccessPermissions,
    '  ACCESS_MODE AccessMode,
    '  DWORD Inheritance
    ');
    Declare Auto Sub BuildExplicitAccessWithName Lib "AdvAPI32.DLL" ( _
        ByVal pExplicitAccess As IntPtr, _
        ByVal pTrusteeName As String, _
        ByVal AccessPermissions As Integer, _
        ByVal AccessMode As Integer, _
        ByVal Inheritance As Integer _
    )
 
    Sub Main()
        Dim ea As New EXPLICIT_ACCESS
        Dim p As IntPtr
 
        ' allocate a chunk of memory that *way* over the requirement
        p = Marshal.AllocHGlobal(256)
        Console.WriteLine("starting")
        BuildExplicitAccessWithName(p, "Users", FILE_ALL_ACCESS, SET_ACCESS, CONTAINER_INHERIT_ACE Or OBJECT_INHERIT_ACE)
        Console.WriteLine("finished")
 
        ' cast it back to the structure to see if things line up
        ea = CType(Marshal.PtrToStructure(p, GetType(EXPLICIT_ACCESS)), EXPLICIT_ACCESS)
        Console.WriteLine("ea.grfAccessPermissions=" & ea.grfAccessPermissions)
        Console.WriteLine("ea.grfAccessMode=" & ea.grfAccessMode)
        Console.WriteLine("ea.grfInheritance=" & ea.grfInheritance)
        Console.WriteLine("ea.Trustee.pMultipleTrustee=" & ea.Trustee.pMultipleTrustee)
        Console.WriteLine("ea.Trustee.MultipleTrusteeOperation=" & ea.Trustee.MultipleTrusteeOperation)
        Console.WriteLine("ea.Trustee.TrusteeForm=" & ea.Trustee.TrusteeForm)
        Console.WriteLine("ea.Trustee.TrusteeType=" & ea.Trustee.TrusteeType)
        'Console.WriteLine("ea.Trustee.ptstrName='" & ea.Trustee.ptstrName & "'")
        Console.WriteLine("ea.Trustee.ptstrName=" & ea.Trustee.ptstrName)
 
        ' ignore the structure and look at the raw data
        For i As Integer = 0 To 47
            Debug.WriteLine("i=" & i & ", byte=" & Hex(Marshal.ReadByte(p, i)))
            If i Mod 4 = 3 Then
                Debug.WriteLine("")
            End If
        Next
 
        ' OK... the pointer that holds the string has been truncated... it only has 32-bits populated
        Dim buf() As Byte = BitConverter.GetBytes(ea.Trustee.ptstrName)
        For Each b As Byte In buf
            Console.Write("{0:X2} ", b)
        Next
 
        Console.ReadLine()
    End Sub
 
End Module

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial