Imports System.Runtime.InteropServices
Imports System.Text

Friend Class ShellContextMenu

    ' Define the internal POINT structure
    <StructLayout(LayoutKind.Sequential)>
    Private Structure POINT
        Public x As Integer
        Public y As Integer
    End Structure

    ' Define other internal structures and interfaces
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
    Private Structure CMINVOKECOMMANDINFOEX
        Public cbSize As Integer
        Public fMask As Integer
        Public hwnd As IntPtr
        Public lpVerb As IntPtr
        Public lpParameters As String
        Public lpDirectory As String
        Public nShow As Integer
        Public dwHotKey As Integer
        Public hIcon As IntPtr
        Public lpTitle As String
        Public lpVerbW As IntPtr
        Public lpParametersW As String
        Public lpDirectoryW As String
        Public lpTitleW As String
        Public ptInvoke As POINT
    End Structure

    <ComImport(), Guid("000214E4-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IContextMenu

        <PreserveSig()>
        Function QueryContextMenu(hMenu As IntPtr, indexMenu As UInt32, idCmdFirst As UInt32, idCmdLast As UInt32, uFlags As UInt32) As Integer

        <PreserveSig()>
        Function InvokeCommand(ByRef pici As CMINVOKECOMMANDINFOEX) As Integer

        <PreserveSig()>
        Function GetCommandString(idCmd As UIntPtr, uType As UInt32, pReserved As IntPtr, pszName As StringBuilder, cchMax As UInt32) As Integer

    End Interface

    <ComImport(), Guid("000214E6-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    Private Interface IShellFolder

        ' Define other necessary methods
        <PreserveSig()>
        Function BindToObject(pidl As IntPtr,
                              pbc As IntPtr,
                              ByRef riid As Guid,
                              <MarshalAs(UnmanagedType.Interface)> ByRef ppvOut As IShellFolder) As Integer

        <PreserveSig()>
        Function GetUIObjectOf(hwndOwner As IntPtr,
                               cidl As UInt32,
                               <[In](), MarshalAs(UnmanagedType.LPArray)> apidl As IntPtr(),
                               ByRef riid As Guid,
                               rgfReserved As UInt32,
                               ByRef ppvOut As IntPtr) As Integer

    End Interface

    ' Import necessary functions
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function CreatePopupMenu() As IntPtr
    End Function

    <DllImport("shell32.dll", CharSet:=CharSet.Unicode)>
    Private Shared Function SHParseDisplayName(pszName As String,
                                               pbc As IntPtr,
                                               ByRef ppidl As IntPtr,
                                               sfgaoIn As UInt32,
                                               ByRef psfgaoOut As UInt32) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function TrackPopupMenuEx(hMenu As IntPtr,
                                             uFlags As UInt32,
                                             x As Int32,
                                             y As Int32,
                                             hwnd As IntPtr,
                                             lptpm As IntPtr) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function DestroyMenu(hMenu As IntPtr) As Boolean
    End Function

    <DllImport("shell32.dll")>
    Private Shared Function SHGetDesktopFolder(<Out()> ByRef ppshf As IShellFolder) As Integer
    End Function

    ' IL functions for PIDL manipulation
    <DllImport("shell32.dll", EntryPoint:="#17")>
    Private Shared Function ILClone(pidl As IntPtr) As IntPtr
    End Function

    <DllImport("shell32.dll", EntryPoint:="#18")>
    Private Shared Sub ILFree(pidl As IntPtr)
    End Sub

    <DllImport("shell32.dll", EntryPoint:="#16")>
    Private Shared Function ILFindLastID(pidl As IntPtr) As IntPtr
    End Function

    <DllImport("shell32.dll", EntryPoint:="#26")>
    Private Shared Function ILRemoveLastID(pidl As IntPtr) As Boolean
    End Function

    ' Constants
    Private Const CMF_NORMAL As UInt32 = &H0

    Private Const TPM_LEFTALIGN As UInt32 = &H0
    Private Const TPM_RETURNCMD As UInt32 = &H100
    Private Const SW_SHOWNORMAL As Integer = 1

    ' Public method to show the context menu for a folder
    Public Sub ShowContextMenuForFolder(folderPath As String, control As Control, location As System.Drawing.Point)
        ' Parse the display name to get the PIDL
        Dim pidlMain As IntPtr = IntPtr.Zero
        Dim sfgao As UInt32 = 0

        If SHParseDisplayName(folderPath, IntPtr.Zero, pidlMain, 0, sfgao) = 0 Then
            ' Get the desktop IShellFolder
            Dim desktopFolder As IShellFolder = Nothing
            If SHGetDesktopFolder(desktopFolder) = 0 Then
                ' Get the parent folder
                Dim parentFolder As IShellFolder = Nothing
                Dim pidlChild As IntPtr = IntPtr.Zero

                If GetParentIShellFolder(desktopFolder, pidlMain, parentFolder, pidlChild) Then
                    ' Get the context menu
                    Dim contextMenuPtr As IntPtr = IntPtr.Zero
                    Dim iidIContextMenu As Guid = New Guid("000214E4-0000-0000-C000-000000000046")
                    Dim apidl() As IntPtr = {pidlChild}

                    If parentFolder.GetUIObjectOf(IntPtr.Zero, 1, apidl, iidIContextMenu, 0, contextMenuPtr) = 0 Then
                        Dim contextMenu As IContextMenu = CType(Marshal.GetObjectForIUnknown(contextMenuPtr), IContextMenu)

                        Dim hMenu As IntPtr = CreatePopupMenu()
                        contextMenu.QueryContextMenu(hMenu, 0, 1, &H7FFF, CMF_NORMAL)

                        Dim screenPoint As POINT = control.PointToScreen(location)
                        Dim selected As Integer = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN Or TPM_RETURNCMD, screenPoint.x, screenPoint.y, control.Handle, IntPtr.Zero)

                        DestroyMenu(hMenu)
                        If selected <> 0 Then
                            Dim invoke As New CMINVOKECOMMANDINFOEX()
                            invoke.cbSize = Marshal.SizeOf(GetType(CMINVOKECOMMANDINFOEX))
                            invoke.fMask = 0
                            invoke.hwnd = control.Handle
                            invoke.lpVerb = New IntPtr(selected - 1)
                            invoke.lpVerbW = New IntPtr(selected - 1)
                            invoke.nShow = SW_SHOWNORMAL
                            ' Convert System.Drawing.Point to internal POINT
                            invoke.ptInvoke = New POINT() With {.x = screenPoint.x, .y = screenPoint.y}

                            contextMenu.InvokeCommand(invoke)
                        End If

                        Marshal.ReleaseComObject(contextMenu)
                    End If

                    Marshal.ReleaseComObject(parentFolder)
                End If

                Marshal.ReleaseComObject(desktopFolder)
            End If

            ILFree(pidlMain)
        End If
    End Sub

    ' Private helper method to get the parent IShellFolder
    Private Function GetParentIShellFolder(desktopFolder As IShellFolder, pidl As IntPtr, ByRef parentFolder As IShellFolder, ByRef pidlChild As IntPtr) As Boolean
        pidlChild = ILFindLastID(pidl)
        Dim pidlParent As IntPtr = ILClone(pidl)
        If pidlParent <> IntPtr.Zero Then
            ILRemoveLastID(pidlParent)
            Dim iidIShellFolder As Guid = New Guid("000214E6-0000-0000-C000-000000000046")
            If desktopFolder.BindToObject(pidlParent, IntPtr.Zero, iidIShellFolder, parentFolder) = 0 Then
                ILFree(pidlParent)
                Return True
            End If
            ILFree(pidlParent)
        End If
        Return False
    End Function

End Class

Value of type 'Point' cannot be converted to 'ShellContextMenu.POINT'.
Value of type 'Point' cannot be converted to 'ShellContextMenu.POINT'.