folderbrowsermoderndialog reverting to non modern on Win 10

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Fri Oct 04, 2019 3:09 pm

Are you only seeing this when you run under PowerShell Studio? It sounds more like you are running this under PowerShell on the users systems. If that is the case then PSS is not involved in any way.

RobBrown
Posts: 13
Joined: Fri Sep 20, 2019 8:40 am

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by RobBrown » Fri Oct 04, 2019 4:14 pm

Apologies, I feel we are on different wavelengths.

To reiterate for clarity, lets put aside all previous replies in this thread and start fresh now that I have narrowed down the problem.

Lets say I create a brand new form project in prowershell studio on my computer.
In this new project, in MainForm.psf I create a single button "button1" and a dialog "folderbrowsermoderndialog1".
In the script tab, I have the following code, nothing more.

Code: Select all

$Login_Load={
}

$button1_Click={
	if ($folderbrowsermoderndialog1.ShowDialog() -eq "OK")
	{
	}
}
I then go into Deploy > Packager > Settings and set Alternate Credentials to a domain\user with run mode of RunAs. All other settings are default.
I then save these settings and build an exe
I copy this exe to a non user profile folder (root C: for example) on one of the reported workstations encountering the problem (We have 3 with this issue that I know of)
When i open the exe and click the button, the folderbrowsermoderndialog shows up as a folderbrowserdialog window 100% of the time

If I then go back on my computer, open the project, modify the packager settings to remove the alternative credentials then build the exe again and move that to the same users workstation, the folderbrowsermoderndialog shows up correctly when pressing the button.

On my own computer, both exe's generated above work correctly, showing the folderbrowsermoderndialog as I would expect to see.

My question is then, what on the OS of the 3 affected computers could cause this problem? How do i troubleshoot it? Shouldn't the alternative credentials feature work the same across the board?

Both my computer and the primary computer with an issue that i'm troubleshooting with are Windows 10 Enterprise 1809. Both have the latest windows updates and both have the same versions of .NET, Yet only one has the problem. Beyond this, i'm not really sure what to look for.

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Fri Oct 04, 2019 4:31 pm

If this only happens on some systems and not others you will need to discover the differences. Some may not have the correct Net Framework installed. Some may have a different OS version and some may have other problems.

Have you tried running this under the account that the EXE is using without the creds to see if that also fails.

Also running some things on a system with no user profile for the account you are impersonating will behave in odd ways. That is usually because the profile contains initialization information that the GUI uses to alter some default behavior such as theme.

I would also suggest that the exe should be tried under a different set of credentials and a set that you know has a profile on the machine and has been tested with no credentials while logged into the target system.

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Fri Oct 04, 2019 4:51 pm

There is another thing that I forgot about. The dialog is a custom control created by Sapien. It was compiled in an earlier version of Visual Studio. VS code is dependent on the C-Run time library. Check the versions of the runtimes on both systems. Add any missing runtimes and test again. There can be many runtime versions installed at the same time.

Code: Select all

Get-WmiObject Win32_Product -Filter "Name LIKE 'Microsoft Visual C++%Redistributable%'" | sort version | select name
Get-WmiObject Win32_Product -Filter "Name LIKE 'Microsoft Visual C++%Runtime%'" | sort version | select name
If they are different then contact Sapien support and ask which runtime is required for that control. I can't tell from my systems because I have almost all runtimes installed.

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Fri Oct 04, 2019 5:05 pm

I looked at the Sapien code and can see nothing that is odd. It does not appear to have any dependencies on any runtime in particular.

This lead me to believe that you are missing some piece of information.

Here is the issue. Both dialogs are really the same dialog. Sapien uses a method of in-memory inheritance that allows them to create a new type and add methods and properties. That is all that is going on. There are really not two types of controls. There is the MS FolderBrowserDialog control; with a wrapper.

How do you know that the dialog is NOT the modern version. There seems to be no way to load the control other than the modern version. Any failures would cause an exception. This points me back to a systems issue or a profile issue.

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Sat Oct 05, 2019 4:31 pm

I finally had time to go through the Sapien code carefully. There are three places where an exception will cause the old dialog to be displayed. The exception is never logged but should show up in the PowerShell log in the event viewer. This might be the cause of your issue and, if logged, will tell you what is causing this to happen. It would be easy to just add logging to the code to capture the event.

Here is the Sapien code:

Code: Select all

<#   C# code injected at startup.
		Add-Type -ReferencedAssemblies ('System.Windows.Forms') -TypeDefinition  @" 
		using System;
		using System.Windows.Forms;
		using System.Reflection;

        namespace SAPIENTypes
        {
		    public class FolderBrowserModernDialog : System.Windows.Forms.CommonDialog
            {
                private System.Windows.Forms.OpenFileDialog fileDialog;
                public FolderBrowserModernDialog()
                {
                    fileDialog = new System.Windows.Forms.OpenFileDialog();
                    fileDialog.Filter = "Folders|\n";
                    fileDialog.AddExtension = false;
                    fileDialog.CheckFileExists = false;
                    fileDialog.DereferenceLinks = true;
                    fileDialog.Multiselect = false;
                    fileDialog.Title = "Select a folder";
                }

                public string Title
                {
                    get { return fileDialog.Title; }
                    set { fileDialog.Title = value; }
                }

                public string InitialDirectory
                {
                    get { return fileDialog.InitialDirectory; }
                    set { fileDialog.InitialDirectory = value; }
                }
                
                public string SelectedPath
                {
                    get { return fileDialog.FileName; }
                    set { fileDialog.FileName = value; }
                }

                object InvokeMethod(Type type, object obj, string method, object[] parameters)
                {
                    MethodInfo methInfo = type.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                    return methInfo.Invoke(obj, parameters);
                }

                bool ShowOriginalBrowserDialog(IntPtr hwndOwner)
                {
                    using(FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
                    {
                        folderBrowserDialog.Description = this.Title;
                        folderBrowserDialog.SelectedPath = !string.IsNullOrEmpty(this.SelectedPath) ? this.SelectedPath : this.InitialDirectory;
                        folderBrowserDialog.ShowNewFolderButton = false;
                        if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                        {
                            fileDialog.FileName = folderBrowserDialog.SelectedPath;
                            return true;
                        }
                        return false;
                    }
                }

                protected override bool RunDialog(IntPtr hwndOwner)
                {
                    if (Environment.OSVersion.Version.Major >= 6)
                    {      
                        try
                        {
                            bool flag = false;
                            System.Reflection.Assembly assembly = Assembly.Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
                            Type typeIFileDialog = assembly.GetType("System.Windows.Forms.FileDialogNative").GetNestedType("IFileDialog", BindingFlags.NonPublic);
                            uint num = 0;
                            object dialog = InvokeMethod(fileDialog.GetType(), fileDialog, "CreateVistaDialog", null);
                            InvokeMethod(fileDialog.GetType(), fileDialog, "OnBeforeVistaDialog", new object[] { dialog });
                            uint options = (uint)InvokeMethod(typeof(System.Windows.Forms.FileDialog), fileDialog, "GetOptions", null) | (uint)0x20;
                            InvokeMethod(typeIFileDialog, dialog, "SetOptions", new object[] { options });
                            Type vistaDialogEventsType = assembly.GetType("System.Windows.Forms.FileDialog").GetNestedType("VistaDialogEvents", BindingFlags.NonPublic);
                            object pfde = Activator.CreateInstance(vistaDialogEventsType, fileDialog);
                            object[] parameters = new object[] { pfde, num };
                            InvokeMethod(typeIFileDialog, dialog, "Advise", parameters);
                            num = (uint)parameters[1];
                            try
                            {
                                int num2 = (int)InvokeMethod(typeIFileDialog, dialog, "Show", new object[] { hwndOwner });
                                flag = 0 == num2;
                            }
                            finally
                            {
                                InvokeMethod(typeIFileDialog, dialog, "Unadvise", new object[] { num });
                                GC.KeepAlive(pfde);
                            }
                            return flag;
                        }
                        catch
                        {
                            return ShowOriginalBrowserDialog(hwndOwner);
                        }
                    }
                    else
                        return ShowOriginalBrowserDialog(hwndOwner);
                }

                public override void Reset()
                {
                    fileDialog.Reset();
                }
            }
       }
"@ -IgnoreWarnings | Out-Null
#>

RobBrown
Posts: 13
Joined: Fri Sep 20, 2019 8:40 am

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by RobBrown » Mon Oct 07, 2019 10:37 am

I checked the powershell event log and can see a "Pipeline Execution Details" log which is essentially the code you provided in your last reply.

Not sure if this says anything useful or not.

Code: Select all

Pipeline execution details for command line: 		Add-Type -ReferencedAssemblies ('System.Windows.Forms') -TypeDefinition  @" 
. 

Context Information: 
	DetailSequence=1
	DetailTotal=1

	SequenceNumber=21

	UserId=domain\username
	HostName=PrimalScriptHostImplementation
	HostVersion=5.0.0.0
	HostId=45ec4c1b-fca3-47ac-92d8-f01fed67f21e
	HostApplication=C:\Program Files\path\name.exe -HOSTRUNAS
	EngineVersion=5.1.17763.592
	RunspaceId=ce65defb-679a-4111-809b-27cfcee53ca6
	PipelineId=2
	ScriptName=
	CommandLine=		Add-Type -ReferencedAssemblies ('System.Windows.Forms') -TypeDefinition  @" 
 

Details: 
CommandInvocation(Add-Type): "Add-Type"
ParameterBinding(Add-Type): name="ReferencedAssemblies"; value="System.Windows.Forms"
ParameterBinding(Add-Type): name="TypeDefinition"; value="		using System;
		using System.Windows.Forms;
		using System.Reflection;

        namespace SAPIENTypes
        {
		    public class FolderBrowserModernDialog : System.Windows.Forms.CommonDialog
            {
                private System.Windows.Forms.OpenFileDialog fileDialog;
                public FolderBrowserModernDialog()
                {
                    fileDialog = new System.Windows.Forms.OpenFileDialog();
                    fileDialog.Filter = "Folders|\n";
                    fileDialog.AddExtension = false;
                    fileDialog.CheckFileExists = false;
                    fileDialog.DereferenceLinks = true;
                    fileDialog.Multiselect = false;
                    fileDialog.Title = "Select a folder";
                }

                public string Title
                {
                    get { return fileDialog.Title; }
                    set { fileDialog.Title = value; }
                }

                public string InitialDirectory
                {
                    get { return fileDialog.InitialDirectory; }
                    set { fileDialog.InitialDirectory = value; }
                }
                
                public string SelectedPath
                {
                    get { return fileDialog.FileName; }
                    set { fileDialog.FileName = value; }
                }

                object InvokeMethod(Type type, object obj, string method, object[] parameters)
                {
                    MethodInfo methInfo = type.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                    return methInfo.Invoke(obj, parameters);
                }

                bool ShowOriginalBrowserDialog(IntPtr hwndOwner)
                {
                    using(FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
                    {
                        folderBrowserDialog.Description = this.Title;
                        folderBrowserDialog.SelectedPath = !string.IsNullOrEmpty(this.SelectedPath) ? this.SelectedPath : this.InitialDirectory;
                        folderBrowserDialog.ShowNewFolderButton = false;
                        if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                        {
                            fileDialog.FileName = folderBrowserDialog.SelectedPath;
                            return true;
                        }
                        return false;
                    }
                }

                protected override bool RunDialog(IntPtr hwndOwner)
                {
                    if (Environment.OSVersion.Version.Major >= 6)
                    {      
                        try
                        {
                            bool flag = false;
                            System.Reflection.Assembly assembly = Assembly.Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
                            Type typeIFileDialog = assembly.GetType("System.Windows.Forms.FileDialogNative").GetNestedType("IFileDialog", BindingFlags.NonPublic);
                            uint num = 0;
                            object dialog = InvokeMethod(fileDialog.GetType(), fileDialog, "CreateVistaDialog", null);
                            InvokeMethod(fileDialog.GetType(), fileDialog, "OnBeforeVistaDialog", new object[] { dialog });
                            uint options = (uint)InvokeMethod(typeof(System.Windows.Forms.FileDialog), fileDialog, "GetOptions", null) | (uint)0x20;
                            InvokeMethod(typeIFileDialog, dialog, "SetOptions", new object[] { options });
                            Type vistaDialogEventsType = assembly.GetType("System.Windows.Forms.FileDialog").GetNestedType("VistaDialogEvents", BindingFlags.NonPublic);
                            object pfde = Activator.CreateInstance(vistaDialogEventsType, fileDialog);
                            object[] parameters = new object[] { pfde, num };
                            InvokeMethod(typeIFileDialog, dialog, "Advise", parameters);
                            num = (uint)parameters[1];
                            try
                            {
                                int num2 = (int)InvokeMethod(typeIFileDialog, dialog, "Show", new object[] { hwndOwner });
                                flag = 0 == num2;
                            }
                            finally
                            {
                                InvokeMethod(typeIFileDialog, dialog, "Unadvise", new object[] { num });
                                GC.KeepAlive(pfde);
                            }
                            return flag;
                        }
                        catch
                        {
                            return ShowOriginalBrowserDialog(hwndOwner);
                        }
                    }
                    else
                        return ShowOriginalBrowserDialog(hwndOwner);
                }

                public override void Reset()
                {
                    fileDialog.Reset();
                }
            }
       }"
ParameterBinding(Add-Type): name="IgnoreWarnings"; value="True"
CommandInvocation(Out-Null): "Out-Null"
I do not see any other errors or reference to it in event viewer.

Based on this new information, it does sound like its failing back to "return ShowOriginalBrowserDialog(hwndOwner);". As its only happening when using the alternative credentials, I dont see how it could be a dependency or it would happen regardless on the problem computer but I believe you ruled that out in your last replies (after asking to review runtimes).

Could you provide details on how I would add logging to capture this event? Its a bit above my skill level.

I will test with different RunAs credentials and also setting up the RunAs user profile on the affected computer to see if we get different results. Being able to log the exception from the above code though would be ideal.

Thanks for all your help.

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Mon Oct 07, 2019 10:47 am

Run the following under a console window started with the alternate credentials. You should see the exception in the console after the dialog is closed.

Code: Select all

#Add-Type -AssemblyName System.Windows.Forms
$code = @'
using System;
using System.Windows.Forms;
using System.Reflection;

namespace SAPIENTypes{
    public class FolderBrowserModernDialog : System.Windows.Forms.CommonDialog{
        private System.Windows.Forms.OpenFileDialog fileDialog;
        public FolderBrowserModernDialog(){
            fileDialog = new System.Windows.Forms.OpenFileDialog();
            fileDialog.Filter = "Folders|\n";
            fileDialog.AddExtension = false;
            fileDialog.CheckFileExists = false;
            fileDialog.DereferenceLinks = true;
            fileDialog.Multiselect = false;
            fileDialog.Title = "Select a folder";
        }

        public string Title{
            get { return fileDialog.Title; }
            set { fileDialog.Title = value; }
        }

        public string InitialDirectory{
            get { return fileDialog.InitialDirectory; }
            set { fileDialog.InitialDirectory = value; }
        }
        
        public string SelectedPath{
            get { return fileDialog.FileName; }
            set { fileDialog.FileName = value; }
        }

        object InvokeMethod(Type type, object obj, string method, object[] parameters){
            MethodInfo methInfo = type.GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            return methInfo.Invoke(obj, parameters);
        }

        bool ShowOriginalBrowserDialog(IntPtr hwndOwner){
            using(FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog()){
                folderBrowserDialog.Description = this.Title;
                folderBrowserDialog.SelectedPath = !string.IsNullOrEmpty(this.SelectedPath) ? this.SelectedPath : this.InitialDirectory;
                folderBrowserDialog.ShowNewFolderButton = false;
                if (folderBrowserDialog.ShowDialog() == DialogResult.OK){
                    fileDialog.FileName = folderBrowserDialog.SelectedPath;
                    return true;
                }
                return false;
            }
        }

        protected override bool RunDialog(IntPtr hwndOwner){

            if (Environment.OSVersion.Version.Major >= 6){      
                try{
                    bool flag = false;
                    System.Reflection.Assembly assembly = Assembly.Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
                    Type typeIFileDialog = assembly.GetType("System.Windows.Forms.FileDialogNative").GetNestedType("IFileDialog", BindingFlags.NonPublic);
                    uint num = 0;
                    object dialog = InvokeMethod(fileDialog.GetType(), fileDialog, "CreateVistaDialog", null);
                    InvokeMethod(fileDialog.GetType(), fileDialog, "OnBeforeVistaDialog", new object[] { dialog });
                    uint options = (uint)InvokeMethod(typeof(System.Windows.Forms.FileDialog), fileDialog, "GetOptions", null) | (uint)0x20;
                    InvokeMethod(typeIFileDialog, dialog, "SetOptions", new object[] { options });
                    Type vistaDialogEventsType = assembly.GetType("System.Windows.Forms.FileDialog").GetNestedType("VistaDialogEvents", BindingFlags.NonPublic);
                    object pfde = Activator.CreateInstance(vistaDialogEventsType, fileDialog);
                    object[] parameters = new object[] { pfde, num };
                    InvokeMethod(typeIFileDialog, dialog, "Advise", parameters);
                    num = (uint)parameters[1];
                    try{
                       int num2 = (int)InvokeMethod(typeIFileDialog, dialog, "Show", new object[] { hwndOwner });
                       flag = 0 == num2;
						Console.WriteLine("Inner Trap: SUCCESS!");
                    }
	                catch (System.Exception e) {
						Console.WriteLine(e.Message);
	                    return flag;
	                }
                    finally{
                        InvokeMethod(typeIFileDialog, dialog, "Unadvise", new object[] { num });
                        GC.KeepAlive(pfde);
                    }
					Console.WriteLine("Outer Trap: SUCCESS!");
                    return flag;
                }
                catch (System.Exception e) {
					Console.WriteLine(e.Message);
                    return ShowOriginalBrowserDialog(hwndOwner);
                }
            }
            else
                return ShowOriginalBrowserDialog(hwndOwner);
        }

        public override void Reset(){
            fileDialog.Reset();
        }
    }
}
'@
try{
	[FolderBrowserModernDialog] | Out-Null
}
catch {
	Add-Type $code -ReferencedAssemblies System.Windows.Forms
}
$f=[SAPIENTypes.FolderBrowserModernDialog]::new()
$f.ShowDialog()
pause

RobBrown
Posts: 13
Joined: Fri Sep 20, 2019 8:40 am

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by RobBrown » Mon Oct 07, 2019 2:43 pm

After running this code on the affected workstation using ISE (RunAs the users used in alternate credentials) it works normally with no errors.

If this works yet its failing when running in a compiled exe, any idea what else the issue could be? Is there some other dependency behind the scenes when using the alternative credentials feature that could be interacting with this code in a negative way?

I'll proceed with a bunch of workstation testing as soon as I can to see if I can push out a different result. Such an odd issue...

User avatar
jvierra
Posts: 13793
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: folderbrowsermoderndialog reverting to non modern on Win 10

Post by jvierra » Mon Oct 07, 2019 3:13 pm

How are you building the EXE and what is the message that is output? The whole point here is to see the error message that is being generated.

Post Reply