Handle IE Protected Mode in managed code (c#)

Protected mode helps protect users from attack by running the Internet Explorer process with greatly restricted privileges. File operation are restricted and virtualized and developers must modify theirs application to handle this  behaviour. Your application should detect the protected mode and use special methods from IE’s API ported in managed code.

Here are snipplets in C# how to achieve it.

You must specify C# signatures for the protected mode methods, in our case for saving files.

[DllImport("ieframe.dll")]
public static extern int IECancelSaveFile(IntPtr hState);
 
[DllImport("ieframe.dll")]
public static extern int IEIsProtectedModeProcess(ref bool pbResult);
 
[DllImport("ieframe.dll")]
public static extern int IELaunchURL(IntPtr pszUrl, ref PROCESS_INFORMATION pProcInfo, ref IELAUNCHURLINFO lpInfo);
 
[DllImport("ieframe.dll")]
public static extern int IESaveFile(IntPtr hState, IntPtr lpwstrSourceFile);
 
[DllImport("ieframe.dll")]
public static extern int IEShowSaveFileDialog(
IntPtr hwnd,
IntPtr lpwstrInitialFileName,
IntPtr lpwstrInitialDir,
IntPtr lpwstrFilter,
IntPtr lpwstrDefExt,
uint dwFilterIndex,
uint dwFlags,
ref IntPtr lppwstrDestinationFilePath,
ref IntPtr phState);
 
[DllImport("shell32.dll")]
static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr pszPath);

Protected mode detection and setting LowAppFolder/Temp path:

switch (IEIsProtectedModeProcess(ref isInProtecteMode))
{
case HResults.S_OK:
isInProtecteMode = true;
IntPtr protectedFolderPath;
Guid LowAppFolderGuid = new Guid("{A520A1A4-1780-4FF6-BD18-167343C5AF16}");
if (SHGetKnownFolderPath(LowAppFolderGuid, 0, IntPtr.Zero, out protectedFolderPath) == HResults.S_OK)
{
tempPath = Marshal.PtrToStringUni(protectedFolderPath);
}
Marshal.FreeCoTaskMem(protectedFolderPath);
break;
 
case HResults.E_NOTIMPL:
isInProtecteMode = false;
tempPath = Path.GetTempPath();
break;
}

Save file dialog:

private void SaveFile(string sourcefile, String fileDialogMask, string defaultExtension)
{
IntPtr hState = IntPtr.Zero;
if (isInProtecteMode)
{
Guid LowAppFolderGuid = new Guid("{A520A1A4-1780-4FF6-BD18-167343C5AF16}");
Guid DocumentsLibraryGuid = new Guid("{7B0DB17D-9CD2-4A93-9733-46CC89022E7C}");
IntPtr protectedFolderPath;
IntPtr documentsLibraryPathIntPtr;
IntPtr defaultExtensionIntPtr = Marshal.StringToHGlobalUni(defaultExtension);
IntPtr targetDirIntPtr = IntPtr.Zero;
IntPtr sourceFilenameIntPtr = Marshal.StringToHGlobalUni(Path.GetFileName(sourcefile));
IntPtr fileDialogMaskIntPtr = Marshal.StringToHGlobalUni(fileDialogMask + "|");
IntPtr protectedfilenamePathIntPtr = IntPtr.Zero;
if (SHGetKnownFolderPath(LowAppFolderGuid, 0, IntPtr.Zero, out protectedFolderPath) == HResults.S_OK)
{
protectedfilenamePathIntPtr = Marshal.StringToHGlobalUni(sourcefile);
if (SHGetKnownFolderPath(DocumentsLibraryGuid, 0, IntPtr.Zero, out documentsLibraryPathIntPtr) == HResults.S_OK)
{
int dialogResult = IEShowSaveFileDialog(
this.Handle,
sourceFilenameIntPtr,
documentsLibraryPathIntPtr,
fileDialogMaskIntPtr,
defaultExtensionIntPtr,
1,
0,
ref targetDirIntPtr,
ref hState);
if (dialogResult == HResults.S_OK)
{
int saveResult = IESaveFile(hState, protectedfilenamePathIntPtr);
if (saveResult == HResults.S_OK)
{
// successfully saved
}
}
else
{
int saveResult = IECancelSaveFile(hState);
}
}
Marshal.FreeCoTaskMem(protectedFolderPath);
Marshal.FreeCoTaskMem(documentsLibraryPathIntPtr);
Marshal.FreeCoTaskMem(defaultExtensionIntPtr);
Marshal.FreeCoTaskMem(sourceFilenameIntPtr);
Marshal.FreeCoTaskMem(fileDialogMaskIntPtr);
Marshal.FreeCoTaskMem(targetDirIntPtr);
Marshal.FreeCoTaskMem(protectedfilenamePathIntPtr);
}
}
else {
SaveFileDialog saveasdialog = new SaveFileDialog();
saveasdialog.Filter = fileDialogMask;
saveasdialog.FilterIndex = 1;
saveasdialog.DefaultExt = defaultExtension;
saveasdialog.InitialDirectory = Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
DialogResult result = saveasdialog.ShowDialog();
 
if (result == DialogResult.OK)
{
File.Copy(sourcefile,saveasdialog.FileName,true);
}
}
File.Delete(sourcefile);
}

HResult c# class:

internal sealed class HResults {
internal const int S_OK                   = 0;
internal const int E_NOTIMPL              = unchecked((int)0x80004001);
internal const int E_POINTER              = unchecked((int)0x80004003);
internal const int E_FAIL                 = unchecked((int)0x80004005);
internal const int E_FILENOTFOUND         = unchecked((int)0x80070002);
internal const int E_PATHNOTFOUND         = unchecked((int)0x80070003);
internal const int E_ACCESSDENIED         = unchecked((int)0x80070005);
internal const int E_INVALID_DATA         = unchecked((int)0x8007000D);
internal const int E_OUTOFMEMORY          = unchecked((int)0x8007000E);
internal const int E_INVALIDARG           = unchecked((int)0x80070057);
internal const int E_INSUFFICIENT_BUFFER  = unchecked((int)0x8007007A);
internal const int WSAECONNABORTED        = unchecked((int)0x80072745);
internal const int WSAECONNRESET          = unchecked((int)0x80072746);
internal const int ERROR_TOO_MANY_CMDS    = unchecked((int)0x80070038);
internal const int ERROR_NOT_SUPPORTED    = unchecked((int)0x80070032);
private HResults() {}
}
Trefný Luděk

Author Trefný Luděk

More posts by Trefný Luděk

Leave a Reply