Diagnosing AccessViolationException in optimized compiled code - vb.net

I have a large vb.net x86 project that is running in VS2015 and .Net 4.5.2
When it is compiled and run in debug without optimization then it works ok. However if I compile and run it in Release mode with optimization turned on then I get a variety of exceptions at the same innocuous line of code. I have tried debugging it in release mode but the breakpoints are unreliable. Also the very act of debugging it seems to modify the exception. Also if I change the code (for example putting a MsgBox in to display information) then the problem can go away. For example I changed an Arraylist to a List(Of Control) and the problem no longer occurred where it did before but now moved elsewhere.
I have received all of the following at different times:
AccessViolationException,
NullReferenceException (somewhere deep within .Net classes)
and FatalExecutionEngineError
The exception detail in the AccessViolationException tells nothing except that "this is often an indication that other memory is corrupt". The stack trace is meaningless and there is no description of what it thought was at the invalid memory address.
I also cannot find any meaningful detail about what Optimization in the compiler actually does - one solution might be to turn Optimization off but I don't understand what the benefit / negative effect is of doing this.
Is the Optimization unreliable? How can one possibly try and ascertain what is happening?
The only unmanaged code we use is some calls to get Icons related to file extensions - which are then cloned into managed objects and the unmanaged memory destroyed. This is pretty standard and the same API has been used since 1.1 and through 4.5.2 for 10 years without this occurring before.
I cannot create a small project that reproduces the issue
Here's the code we use for extracting icons as it's the only potential cause I have right now. It was borrowed from elsewhere and I can't really tell whether it's as good as it should be:
Public Class IconExtractor
<Flags()> Private Enum SHGFI
SmallIcon = &H1
LargeIcon = &H0
Icon = &H100
DisplayName = &H200
Typename = &H400
SysIconIndex = &H4000
UseFileAttributes = &H10
End Enum
<StructLayout(LayoutKind.Sequential)>
Private Structure SHFILEINFO
Public hIcon As IntPtr
Public iIcon As Integer
Public dwAttributes As Integer
<MarshalAs(UnmanagedType.LPStr, SizeConst:=260)> Public szDisplayName As String
<MarshalAs(UnmanagedType.LPStr, SizeConst:=80)> Public szTypeName As String
Public Sub New(ByVal B As Boolean)
hIcon = IntPtr.Zero
iIcon = 0
dwAttributes = 0
szDisplayName = vbNullString
szTypeName = vbNullString
End Sub
End Structure
Private Declare Auto Function SHGetFileInfo Lib "shell32" (
ByVal pszPath As String, ByVal dwFileAttributes As Integer,
ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As SHGFI) As Integer
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
Public Shared Sub GetIconsForFile(ByVal rstrFileName As String, ByRef rzSmallIcon As Icon, ByRef rzLargeIcon As Icon)
Dim zFileInfo As New SHFILEINFO(True)
Dim cbSizeInfo As Integer = Marshal.SizeOf(zFileInfo)
Dim flags As SHGFI = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.SmallIcon
SHGetFileInfo(rstrFileName, 256, zFileInfo, cbSizeInfo, flags)
' Use clone so we can destroy immediately
rzSmallIcon = DirectCast(Icon.FromHandle(zFileInfo.hIcon).Clone, Icon)
DestroyIcon(zFileInfo.hIcon)
zFileInfo = New SHFILEINFO(True)
cbSizeInfo = Marshal.SizeOf(zFileInfo)
flags = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.LargeIcon
SHGetFileInfo(rstrFileName, 256, zFileInfo, cbSizeInfo, flags)
' Use clone so we can destroy immediately
rzLargeIcon = DirectCast(Icon.FromHandle(zFileInfo.hIcon).Clone, Icon)
DestroyIcon(zFileInfo.hIcon)
End Sub
End Class

I stumbled across the solution to this by chance.
I was reading this documentation of SHGETFILEINFO
https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx
and found that it said in the remarks: You should call this function from a background thread. Failure to do so could cause the UI to stop responding
It isn't clear why you should call it from a background thread nor is it clear what "stop responding" might actually manifest itself as.
However it seemed this was fairly likely what was causing the problem and so I refactored to execute the api call under a separate thread. This has certainly seemed to work. Many of the examples on the internet of SHGETFILEINFO do not seem to consider the separate thread requirement.
I reproduce the whole refactored code here:
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Threading
''' <summary>
''' Retrieves the small and large icons registered for a filename based on the file's extension
''' </summary>
Public Class FileIcons
Private mFileName As String
Private mSmallIconHandle As IntPtr
Private mSmallIcon As Icon
Private mLargeIconHandle As IntPtr
Private mLargeIcon As Icon
Public Sub New(ByVal rFileName As String)
mFileName = rFileName
Dim t As New Thread(AddressOf GetIconsForFile)
t.SetApartmentState(ApartmentState.STA)
t.Start()
t.Join()
' Use clone so we can destroy immediately
mSmallIcon = DirectCast(Icon.FromHandle(mSmallIconHandle).Clone, Icon)
DestroyIcon(mSmallIconHandle)
' Use clone so we can destroy immediately
mLargeIcon = DirectCast(Icon.FromHandle(mLargeIconHandle).Clone, Icon)
DestroyIcon(mLargeIconHandle)
End Sub
Public ReadOnly Property SmallIcon As Icon
Get
Return mSmallIcon
End Get
End Property
Public ReadOnly Property LargeIcon As Icon
Get
Return mLargeIcon
End Get
End Property
Private Sub GetIconsForFile()
' Go and extract the small and large icons
' Full filename must be < MAX_PATH - which is 260 chars in .Net (apparently) though a file path/length of 256 also causes an error.
' Otherwise SHGetFileInfo gets nothing, Icon.FromHandle then gives "System.ArgumentException: The Win32 handle you passed to Icon is invalid or of the wrong type."
' This needs to be stopped in the calling code, or the resulting error trapped
Dim zFileInfo As New SHFILEINFO(True)
Dim cbSizeInfo As Integer = Marshal.SizeOf(zFileInfo)
Dim flags As SHGFI = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.SmallIcon
SHGetFileInfo(mFileName, 256, zFileInfo, cbSizeInfo, flags)
mSmallIconHandle = zFileInfo.hIcon
zFileInfo = New SHFILEINFO(True)
cbSizeInfo = Marshal.SizeOf(zFileInfo)
flags = SHGFI.Icon Or SHGFI.UseFileAttributes Or SHGFI.LargeIcon
SHGetFileInfo(mFileName, 256, zFileInfo, cbSizeInfo, flags)
mLargeIconHandle = zFileInfo.hIcon
End Sub
#Region "WinAPI"
<Flags()> Private Enum SHGFI
SmallIcon = &H1
LargeIcon = &H0
Icon = &H100
DisplayName = &H200
Typename = &H400
SysIconIndex = &H4000
UseFileAttributes = &H10
End Enum
<StructLayout(LayoutKind.Sequential)>
Private Structure SHFILEINFO
Public hIcon As IntPtr
Public iIcon As Integer
Public dwAttributes As Integer
<MarshalAs(UnmanagedType.LPStr, SizeConst:=260)> Public szDisplayName As String
<MarshalAs(UnmanagedType.LPStr, SizeConst:=80)> Public szTypeName As String
Public Sub New(ByVal B As Boolean)
hIcon = IntPtr.Zero
iIcon = 0
dwAttributes = 0
szDisplayName = vbNullString
szTypeName = vbNullString
End Sub
End Structure
Private Declare Auto Function SHGetFileInfo Lib "shell32" (
ByVal pszPath As String,
ByVal dwFileAttributes As Integer,
ByRef psfi As SHFILEINFO,
ByVal cbFileInfo As Integer,
ByVal uFlags As SHGFI) As Integer
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
#End Region
End Class

Related

How to copy multiple files/folders using single windows copy GUI in VB.Net

I am making an app in VB.Net that copies many files and folders to the same directory and I wish to use windows explorer for that (so the user has GUI and I do not have to worry about showing any errors or compare files).
So, if I do this for each file/folder:
My.Computer.FileSystem.CopyDirectory(source_path, target_path, FileIO.UIOption.AllDialogs)
My.Computer.FileSystem.CopyFile(source_path, target_path, FileIO.UIOption.AllDialogs)
It works correctly and shows this window:
Which is fine, however, if I have many files and/or folders and I loop through them and call commands above, they launch a new copy window for each file/folder, instead of launching a single GUI that combines them all, like so:
Is it possible to combine multiple files/folders copy process into a single windows explorer copy window GUI?
Thanks to #Jimi, I got pointed in the direction of SHFileOperations, so i figured out how to do this. I made a small class to do this:
Imports System.Runtime.InteropServices
Public Class NativeCopy
Private Enum FO_Func As Short
FO_COPY = &H2
FO_DELETE = &H3
FO_MOVE = &H1
FO_RENAME = &H4
End Enum
Private Structure SHFILEOPSTRUCT
Public hwnd As IntPtr
Public wFunc As FO_Func
<MarshalAs(UnmanagedType.LPWStr)>
Public pFrom As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pTo As String
Public fFlags As UShort
Public fAnyOperationsAborted As Boolean
Public hNameMappings As IntPtr
<MarshalAs(UnmanagedType.LPWStr)>
Public lpszProgressTitle As String
End Structure
<DllImport("shell32.dll", CharSet:=CharSet.Unicode)>
Private Shared Function SHFileOperation(
<[In]> ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
End Function
Private Shared _ShFile As SHFILEOPSTRUCT
Public Shared Sub Copy(ByVal sSource As List(Of String), ByVal sTarget As String)
_ShFile.wFunc = FO_Func.FO_COPY
_ShFile.pFrom = String.Join(vbNullChar, sSource) + vbNullChar
_ShFile.pTo = sTarget
SHFileOperation(_ShFile)
End Sub
End Class
To copy files and/or folders is as simple as this:
Dim copy_items_paths As List(Of String)
Dim target_path As String
NativeCopy.Copy(copy_items_paths, target_path)

vb.net Register Hotkey without a Form ? Can it be done ? (Using ApplicationContext maybe ?)

I am making a bare bone application and I would like to avoid adding a form class to my project.
Here is what I have done so far
First my new project is a "Empty Project (.NET framework"
Then I added a single empty class file
Then I added the system.windows.forms reference to my project
Lastly I add the following code
Imports System.Windows.Forms
Public Class AppCore
Inherits ApplicationContext
Shared Sub main()
Dim myAppCore As AppCore
myAppCore = New AppCore
System.Windows.Forms.Application.Run(myAppCore)
End Sub
End Class
From that point on, I have a barebone working app that does nothing but stays running forever.
Now I want to registers the keys combo "ALT+F6" and "ALT+F7"
I add the following code
Public Const MOD_CONTROL As Integer = &H11
Public Const MOD_SHIFT As Integer = &H10
Public Const MOD_ALT As Integer = &H1
Public Const WM_HOTKEY As Integer = &H312
Public Declare Function RegisterHotKey Lib "user32.dll" Alias "RegisterHotKey" (ByVal hwnd As IntPtr, ByVal id As Integer, ByVal fsModifiers As Integer, ByVal vk As Integer) As Integer
Public Declare Function UnregisterHotKey Lib "user32.dll" Alias "UnregisterHotKey" (ByVal hwnd As IntPtr, ByVal id As Integer) As Integer
Sub New()
RegisterHotKey(Me.Handle, 100, MOD_ALT, Keys.F6)
RegisterHotKey(Me.Handle, 200, MOD_ALT, Keys.F7)
End Sub
Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
MyBase.DefWndProc(m)
Dim x As Long
If m.Msg = WM_HOTKEY Then
Select Case CType(m.WParam, Integer)
Case 100
Beep()
Case 200
Beep()
End Select
End If
End Sub
This is where I run into trouble
First in Sub New(), the IDE is telling me that Handle is not part of appcore/applicationcontext
Second, I get the following error
At this point I am stuck !
How can I create hotkeys without adding a form ?
For DefWndProc, maybe I can get away with only removing the "Overrides" keywork and dropping "MyBase.DefWndProc(m)" ?
But I think the bigger problem is how to get a handle ?
Maybe I should look at the CreateWindow API ?
EDIT :
I have modified this project to include a new class of type NativeWindow
as follows
Imports System.Windows.Forms
Public Class clsHotkey
Inherits NativeWindow
Public Const WM_HOTKEY As Integer = &H312
Protected Overloads Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_HOTKEY Then
Select Case CType(m.WParam, Integer)
Case 100
Console.WriteLine("ID 100")
Case 200
Console.WriteLine("ID 200")
End Select
End If
End Sub
End Class
This provides the bare minimum to have a window handle for RegisterHotkey.
I have also modified the AppCore class to work with it.
It compiles and runs without error but the hotkeys do nothing
I believe this is because I have replaced the override keywork in the definition of the DefWndProc subroutine by overloads
If I try to use overrides, I get the following error
BC31086 'Protected Overrides Sub DefWndProc(ByRef m As Message)' cannot override 'Public Overloads Sub DefWndProc(ByRef m As Message)' because it is not declared 'Overridable'.
At this point I am stuck. I would rather not use a form class because of the added complexity (especially the addition of a designer file for it which will make manual compiling more complicated)
Is there a way to make it work with NativeWindow class ? Or some other alternative class that can obtain a window handle ?
Thanks !

VB.NET Display file icons from Network Paths with calling Shell

I have this program that shows files with its icons using a ListView and it works a little bit fine but there's a problem, some files(.exe, .docx etc...) don't show their right icon like this. how do I fix that?
This is how I call the Shell:
' declare the Win32 API function SHGetFileInfo'
Public Declare Auto Function SHGetFileInfo Lib "shell32.dll" (ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As Integer) As IntPtr
' declare some constants that SHGetFileInfo requires'
Public Const SHGFI_ICON As Integer = &H100
Public Const SHGFI_SMALLICON As Integer = &H1
' define the SHFILEINFO structure'
Structure SHFILEINFO
Public hIcon As IntPtr
Public iIcon As Integer
Public dwAttributes As Integer
<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=260)> _
Public szDisplayName As String
<Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=80)> _
Public szTypeName As String
End Structure
Function RetrieveShellIcon(ByVal argPath As String) As Image
Dim mShellFileInfo As SHFILEINFO
Dim mSmallImage As IntPtr
Dim mIcon As System.Drawing.Icon
Dim mCompositeImage As Image
mShellFileInfo = New SHFILEINFO
mShellFileInfo.szDisplayName = New String(Chr(0), 260)
mShellFileInfo.szTypeName = New String(Chr(0), 80)
mSmallImage = SHGetFileInfo(argPath, 0, mShellFileInfo, System.Runtime.InteropServices.Marshal.SizeOf(mShellFileInfo), SHGFI_ICON Or SHGFI_SMALLICON)
' create the icon from the icon handle'
Try
mIcon = System.Drawing.Icon.FromHandle(mShellFileInfo.hIcon)
mCompositeImage = mIcon.ToBitmap
Catch ex As Exception
' create a blank black bitmap to return'
mCompositeImage = New Bitmap(16, 16)
End Try
' return the composited image'
Return mCompositeImage
End Function
Function GetIcon(ByVal argFilePath As String) As Image
Dim mFileExtension As String = System.IO.Path.GetExtension(argFilePath)
' add the image if it doesn't exist'
If cIcons.ContainsKey(mFileExtension) = False Then
cIcons.Add(mFileExtension, RetrieveShellIcon(argFilePath))
End If
' return the image'
Return cIcons(mFileExtension)
End Function
and this is how I show file icons in my `ListView.
Sub lv1items()
Dim lvi As ListViewItem
Dim di As New DirectoryInfo(Form2.TextBox1.Text)
Dim exts As New List(Of String)
ImageList1.Images.Clear()
If di.Exists = False Then
MessageBox.Show("Source path is not found", "Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error)
Else
For Each fi As FileInfo In di.EnumerateFiles("*.*")
lvi = New ListViewItem
lvi.Text = fi.Name
lvi.SubItems.Add(((fi.Length / 1024)).ToString("0.00"))
lvi.SubItems.Add(fi.CreationTime.ToShortDateString)
If exts.Contains(fi.Extension) = False Then
Dim mShellIconManager As New Form1
For Each mFilePath As String In My.Computer.FileSystem.GetFiles(Form2.TextBox1.Text)
ImageList1.Images.Add(fi.Extension, GetIcon(mFilePath))
exts.Add(fi.Extension)
Next
End If
lvi.ImageKey = fi.Extension
ListView1.Items.Add(lvi)
Next
End If
End Sub
That appears to be a weird limitation of the .net implication
its really just making a call to shell32.dll
You should call the function in shell32 directly
something like this should work
<DllImport("shell32.dll")>
Private Shared Function ExtractAssociatedIcon(hInst As IntPtr, lpIconPath As StringBuilder, ByRef lpiIcon As UShort) As IntPtr
End Function
_
Dim handle As IntPtr = SafeNativeMethods.ExtractAssociatedIcon(New HandleRef(Nothing, IntPtr.Zero), iconPath, index)
If handle <> IntPtr.Zero Then
Return Icon.FromHandle(handle)
End If
The syntax might not be exactly correct, also there is a good blog post about how to pull that information from the registry (which won't always give you the correct answer, but its faster)
Building a Better ExtractIcon (he uses the SHGetFileInfo API in shell32.dll if that blog ever dies it will give people a place to start looking)

Error after converting to vb.net from C# [duplicate]

This question already has answers here:
VB.NET and sizeof
(3 answers)
Closed 8 years ago.
I am trying to convert the C# code given in this link. I got some errors after conversion, but i have corrected some. Still i get error for the line cbSize = sizeof(TOKEN_ELEVATION_TYPE)
The errors are:
'sizeof' is not declared. It may be inaccessible due to its protection level. D:\Desktop\WindowsApplication3\WindowsApplication3\Form1.vb 103 26 WindowsApplication3
'TOKEN_ELEVATION_TYPE' is a type and cannot be used as an expression. D:\Desktop\WindowsApplication3\WindowsApplication3\Form1.vb 103 33 WindowsApplication3
I tried using Len instead of sizeof, but the second error still exists. So can anyone help me to solve both errors. Below is the VB.NET code which has said error.
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports System.ComponentModel
Public Class Form1
Public Const TOKEN_DUPLICATE As UInt32 = &H2
Public Const TOKEN_IMPERSONATE As UInt32 = &H4
Public Const TOKEN_QUERY As UInt32 = &H8
Public Declare Function GetTokenInformation Lib "advapi32.dll" ( _
ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, _
ByRef ReturnLength As System.UInt32) As Boolean
Declare Function DuplicateToken Lib "advapi32.dll" (ExistingTokenHandle As IntPtr, _
SECURITY_IMPERSONATION_LEVEL As Int16, ByRef DuplicateTokenHandle As IntPtr) _
As Boolean
Enum TOKEN_ELEVATION_TYPE
TokenElevationTypeDefault = 1
TokenElevationTypeFull
TokenElevationTypeLimited
End Enum
Public Enum TOKEN_INFORMATION_CLASS
TokenUser = 1
TokenGroups
TokenPrivileges
TokenOwner
TokenPrimaryGroup
TokenDefaultDacl
TokenSource
TokenType
TokenImpersonationLevel
TokenStatistics
TokenRestrictedSids
TokenSessionId
TokenGroupsAndPrivileges
TokenSessionReference
TokenSandBoxInert
TokenAuditPolicy
TokenOrigin
TokenElevationType
TokenLinkedToken
TokenElevation
TokenHasRestrictions
TokenAccessInformation
TokenVirtualizationAllowed
TokenVirtualizationEnabled
TokenIntegrityLevel
TokenUIAccess
TokenMandatoryPolicy
TokenLogonSid
MaxTokenInfoClass
' MaxTokenInfoClass should always be the last enum
End Enum
Public Enum SECURITY_IMPERSONATION_LEVEL
SecurityAnonymous
SecurityIdentification
SecurityImpersonation
SecurityDelegation
End Enum
Function IsAdmin() As Boolean
Dim identity = WindowsIdentity.GetCurrent()
Return (identity IsNot Nothing AndAlso New WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator))
End Function
''' <summary>
''' The function checks whether the primary access token of the process belongs
''' to user account that is a member of the local Administrators group, even if
''' it currently is not elevated.
''' </summary>
''' <returns>
''' Returns true if the primary access token of the process belongs to user
''' account that is a member of the local Administrators group. Returns false
''' if the token does not.
''' </returns>
Function CanBeAdmin() As Boolean
Dim fInAdminGroup As Boolean = False
Dim hToken As IntPtr = IntPtr.Zero
Dim hTokenToCheck As IntPtr = IntPtr.Zero
Dim pElevationType As IntPtr = IntPtr.Zero
Dim pLinkedToken As IntPtr = IntPtr.Zero
Dim cbSize As Integer = 0
If IsAdmin() Then
Return True
End If
Try
' Check the token for this user
hToken = WindowsIdentity.GetCurrent().Token
' Determine whether system is running Windows Vista or later operating
' systems (major version >= 6) because they support linked tokens, but
' previous versions (major version < 6) do not.
If Environment.OSVersion.Version.Major >= 6 Then
' Running Windows Vista or later (major version >= 6).
' Determine token type: limited, elevated, or default.
' Allocate a buffer for the elevation type information.
cbSize = sizeof(TOKEN_ELEVATION_TYPE)
Dim cbSizeuint As UInteger = Convert.ToUInt32(cbSize)
pElevationType = Marshal.AllocHGlobal(cbSize)
If pElevationType = IntPtr.Zero Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
' Retrieve token elevation type information.
If Not GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSizeuint, cbSizeuint) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
' Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
Dim elevType As TOKEN_ELEVATION_TYPE = CType(Marshal.ReadInt32(pElevationType), TOKEN_ELEVATION_TYPE)
' If limited, get the linked elevated token for further check.
If elevType = TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited Then
' Allocate a buffer for the linked token.
cbSize = IntPtr.Size
Dim cbSizeuint_ee As UInteger = Convert.ToUInt32(cbSize)
pLinkedToken = Marshal.AllocHGlobal(cbSize)
If pLinkedToken = IntPtr.Zero Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
' Get the linked token.
If Not GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSizeuint_ee, cbSizeuint_ee) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
' Marshal the linked token value from native to .NET.
hTokenToCheck = Marshal.ReadIntPtr(pLinkedToken)
End If
End If
' CheckTokenMembership requires an impersonation token. If we just got
' a linked token, it already is an impersonation token. If we did not
' get a linked token, duplicate the original into an impersonation
' token for CheckTokenMembership.
If hTokenToCheck = IntPtr.Zero Then
If Not DuplicateToken(hToken, CInt(SECURITY_IMPERSONATION_LEVEL.SecurityIdentification), hTokenToCheck) Then
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
End If
' Check if the token to be checked contains admin SID.
Dim id As New WindowsIdentity(hTokenToCheck)
Dim principal As New WindowsPrincipal(id)
fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator)
Catch
Return False
Finally
' Centralized cleanup for all allocated resources.
If pElevationType <> IntPtr.Zero Then
Marshal.FreeHGlobal(pElevationType)
pElevationType = IntPtr.Zero
End If
If pLinkedToken <> IntPtr.Zero Then
Marshal.FreeHGlobal(pLinkedToken)
pLinkedToken = IntPtr.Zero
End If
End Try
Return fInAdminGroup
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs)
If CanBeAdmin() Then
MessageBox.Show("admin")
Else
MessageBox.Show("not admin")
End If
End Sub
End Class
You can get the effect of C# cbSize = sizeof(TOKEN_ELEVATION_TYPE) using Marshal.SizeOf to get the size of the underlying type.
Dim undertype As Type = [Enum].GetUnderlyingType(GetType(TOKEN_ELEVATION_TYPE))
cbSize = System.Runtime.InteropServices.Marshal.SizeOf(undertype)
When I ran it, undertype was System.Int32, and cbSize was 4.

Icon.ExtractAssociatedIcon for things that are not files?

Is this possible? It gives me an error, and I had previously thought it could work for folders and drives and stuff like that as well.
Icon.ExtractAssociatedIcon("C:\") did not work when I tried it, and threw an error.
How can I get the associated icon from EVERYTHING? This is vb.net
The SHGetFileInfo() shell function can provide you with the icon you are looking for. This code worked well, it generated appropriate icons for drives, folders and files:
Imports System.Drawing
Imports System.Reflection
Imports System.Runtime.InteropServices
Public Module NativeMethods
Public Function GetShellIcon(ByVal path As String) As Icon
Dim info As SHFILEINFO = New SHFILEINFO()
Dim retval as IntPtr = SHGetFileInfo(path, 0, info, Marshal.SizeOf(info), &H100)
If retval = IntPtr.Zero Then Throw New ApplicationException("Could not retrieve icon")
'' Invoke private Icon constructor so we do not have to copy the icon
Dim cargt() As Type = { GetType(IntPtr) }
Dim ci As ConstructorInfo = GetType(Icon).GetConstructor(BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, cargt, Nothing)
Dim cargs() As Object = { info.IconHandle }
Dim icon As Icon = CType(ci.Invoke(cargs), Icon)
Return icon
End Function
'' P/Invoke declaration
Private Structure SHFILEINFO
Public IconHandle As IntPtr
Public IconIndex As Integer
Public Attributes As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
Public DisplayString As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
Public TypeName As String
End Structure
Private Declare Auto Function SHGetFileInfo lib "Shell32.dll" (path As String, _
attributes As Integer, byref info As SHFILEINFO, infoSize As Integer, flags As Integer) As IntPtr
End Module
It is not possible to use Icon.ExtractAssociatedIcon on anything other than files. This API is a thin wrapper on top of the Win32 call ExtractAssociatedIcon. While the documentation for the managed code is a bit ambiguous, the native documentation is much clearer that the target must be a file. It goes further to say that it must be an executable file.
Unfortunately I'm not sure if there is an equivalent function for Directories or not.