Well when starting through the code I'm looking at every ref or out parameter to the P/Invoke calls.
I notice that you use SHGetDesktopFolder, I don't see you making it null/releasing it until you make the ShowContextMenu call again, the documentation for that function says you are responsible for releasing it with an IUnknown::Release call
SHGetDesktopFolder
P/Invoke describes interop
It looks like...
// TrackPopupMenu
[DllImport("user32.dll", EntryPoint = "TrackPopupMenu", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int TrackPopupMenu(IntPtr hMenu, int wFlags, int x, int y, int nReserved, IntPtr hwnd, out IntPtr lprc);
becomes
// TrackPopupMenu
[DllImport("user32.dll", EntryPoint = "TrackPopupMenu", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int TrackPopupMenu(IntPtr hMenu, uint wFlags, int x, int y, int nReserved, IntPtr hwnd, IntPtr lprc);
and your call
cmdID = TrackPopupMenu(hMenu, (TPM_RETURNCMD | TPM_LEFTALIGN), intX, intY, 0, hwnd, out Test);
should be
cmdID = TrackPopupMenu(hMenu, (TPM_RETURNCMD | TPM_LEFTALIGN), intX, intY, 0, hwnd, IntPrt.Zero);
or
cmdID = TrackPopupMenu(hMenu, (TPM_RETURNCMD | TPM_LEFTALIGN), intX, intY, 0, hwnd, null);
So your problem is either with the TrackPopupMenu still having out test, or actually with the SHGetDesktopFolder using the DesktopFolder object after it has been moved.
Unfortunately with interop access violation aren't always where they appear to be.