Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Multiple assemblies with equivalent identity have been imported" error for System.Windows.Forms.dll after importing unity package #122

Open
The-MAZZTer opened this issue May 9, 2022 · 10 comments

Comments

@The-MAZZTer
Copy link

I suspect the error indicates this package is not compatible with Unity 2021.3.

However I have figured out how to work around it by importing a different version of System.Windows.Forms.

I copied C:\Program Files\Unity\Hub\Editor\2021.3.0f1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32\System.Windows.Forms.dll and replaced the DLL the SFB package provided with that one. This resolved the error and the file picker works properly (at least in the editor).

Not sure if I selected the proper DLL as there appear to be several candidates in subfolders of lib\mono. There are some that are ~700kb which I think are native code (eg not .NET binaries so Unity can't use them as such) and there are a few that are ~2-3MB which are probably workable choices. I selected one that sounded plausible and my first choice seems to be working.

@The-MAZZTer
Copy link
Author

It looks like trying to use C:\ as the starting directory for a file open dialog does not work properly with this DLL (I did trace the problem to System.Windows.Forms). The starting directory is the default and C:\ is shown in the file name box. So that is a potential complication with this workaround.

@rafcsoares
Copy link

rafcsoares commented May 10, 2022

It looks like trying to use C:\ as the starting directory for a file open dialog does not work properly with this DLL (I did trace the problem to System.Windows.Forms). The starting directory is the default and C:\ is shown in the file name box. So that is a potential complication with this workaround.

The final solution for this problem is remove System.Windows.Forms.dll from your project and use ShellFileDialog (a wrapper to user32.dll from native c++ windows folder).

----------------- Solution Below will work with all Unity Versions (NetStandard and/or NetFramework) ---------------------------

Drop the DLL below to your unity project and remove old System.Windows.Forms.dll from your project.

DLL Link: ShellFileDialogs.zip
PS: Edit DLL Inspector in Unity to only compile dll in Editor Windows/Standalone Windows x84|x64

Replace the source of StandaloneFileBrowserWindows.cs to the code below.

#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Linq;
using System.Collections.Generic;

namespace SFB {

    // For fullscreen support
    // - "PlayerSettings/Visible In Background" should be enabled, otherwise when file dialog opened app window minimizes automatically.
    public class StandaloneFileBrowserWindows : IStandaloneFileBrowser 
    {

        [DllImport("user32.dll")]
        private static extern IntPtr GetActiveWindow();

        public string[] OpenFilePanel(string title, string directory, ExtensionFilter[] extensions, bool multiselect) {

            var shellFilters = GetShellFilterFromFileExtensionList(extensions);
            if (multiselect)
            {
                var paths = ShellFileDialogs.FileOpenDialog.ShowMultiSelectDialog(GetActiveWindow(), title, directory, string.Empty, shellFilters, null);
                return paths == null || paths.Count == 0 ? new string[0] : paths.ToArray();
            }
            else
            {
                var path = ShellFileDialogs.FileOpenDialog.ShowSingleSelectDialog(GetActiveWindow(), title, directory, string.Empty, shellFilters, null);
                return string.IsNullOrEmpty(path) ? new string[0] : new[] { path };
            }
        }

        public void OpenFilePanelAsync(string title, string directory, ExtensionFilter[] extensions, bool multiselect, Action<string[]> cb) {
            cb.Invoke(OpenFilePanel(title, directory, extensions, multiselect));
        }

        public string[] OpenFolderPanel(string title, string directory, bool multiselect) {

            var path = ShellFileDialogs.FolderBrowserDialog.ShowDialog(GetActiveWindow(), title, directory);
            return string.IsNullOrEmpty(path) ? new string[0] : new[] { path };
        }

        public void OpenFolderPanelAsync(string title, string directory, bool multiselect, Action<string[]> cb) {
            cb.Invoke(OpenFolderPanel(title, directory, multiselect));
        }

        public string SaveFilePanel(string title, string directory, string defaultName, ExtensionFilter[] extensions) {

            var finalFilename = "";
            if (!string.IsNullOrEmpty(directory))
            {
                finalFilename = GetDirectoryPath(directory);
            }

            if (!string.IsNullOrEmpty(defaultName))
            {
                finalFilename += defaultName;
            }

            var shellFilters = GetShellFilterFromFileExtensionList(extensions);
            if(shellFilters.Length > 0 && !string.IsNullOrEmpty(finalFilename))
            {
                var extension = $".{shellFilters[0].Extensions[0]}";
                if (!string.IsNullOrEmpty(extension) && !finalFilename.EndsWith(extension, StringComparison.CurrentCultureIgnoreCase))
                    finalFilename += extension;
            }
            
            var path = ShellFileDialogs.FileSaveDialog.ShowDialog(GetActiveWindow(), title, directory, finalFilename, shellFilters, 0);
            return path;
        }

        public void SaveFilePanelAsync(string title, string directory, string defaultName, ExtensionFilter[] extensions, Action<string> cb) {
            cb.Invoke(SaveFilePanel(title, directory, defaultName, extensions));
        }

        private static ShellFileDialogs.Filter[] GetShellFilterFromFileExtensionList(ExtensionFilter[] extensions)
        {
            var shellFilters = new List<ShellFileDialogs.Filter>();
            if (extensions != null)
            {
                foreach (var extension in extensions)
                {
                    if (extension.Extensions == null || extension.Extensions.Length == 0)
                        continue;

                    var displayName = extension.Name;
                    if (string.IsNullOrEmpty(displayName))
                    {
                        System.Text.StringBuilder extensionFormatted = new System.Text.StringBuilder();
                        foreach (var extensionStr in extension.Extensions)
                        {
                            if (extensionFormatted.Length > 0)
                                extensionFormatted.Append(";");
                            extensionFormatted.Append($"*.{extensionStr}");
                        }
                        displayName = $"({extensionFormatted})";
                    }
                    var filter = new ShellFileDialogs.Filter(displayName, extension.Extensions);
                    shellFilters.Add(filter);
                }
            }
            if (shellFilters.Count == 0)
            {
                shellFilters.AddRange(ShellFileDialogs.Filter.ParseWindowsFormsFilter(@"All files (*.*)|*.*"));
            }

            return shellFilters.ToArray();
        }

        private static string GetDirectoryPath(string directory) {
            var directoryPath = Path.GetFullPath(directory);
            if (!directoryPath.EndsWith("\\")) {
                directoryPath += "\\";
            }
            if (Path.GetPathRoot(directoryPath) == directoryPath) {
                return directory;
            }
            return Path.GetDirectoryName(directoryPath) + Path.DirectorySeparatorChar;
        }
    }
}

#endif

Best Regards
Rafael

@thnewlands
Copy link

Hey @rafcsoares thank you for putting this together! I'm getting a missing directive error when I follow your instructions. Do you have any troubleshooting tips?

Assets\Scripts\Thirdparty\StandaloneFileBrowser\StandaloneFileBrowserWindows.cs(78,24): error CS0246: The type or namespace name 'ShellFileDialogs' could not be found (are you missing a using directive or an assembly reference?

@rafcsoares
Copy link

You need to import dll to project buddy.

@thnewlands i put the link for dll zip in my previous comment.. you just need to drop it inside your project and select to work with UnityEditor Windows x86/x64 and Standalone Windows x86/x64

@thnewlands
Copy link

Turns out I had a competing .asmdef -- works perfectly! Thanks for sharing your solution.

@TheYellowArchitect
Copy link

Thank you for this. I was testing SFB on the editor and it was good, but days later when I built with System.Windows.Forms, I just couldn't build!

I use Unity Version 2018.1.1f1, and so, can confirm it works there. It needed .NET 4.0 though, but luckily that was the last version possible through Project Settings -> Player -> Other Settings

@Profy
Copy link

Profy commented Jun 9, 2022

Hi @rafcsoares. I would like to know which version of ShellFileDialogs you used to make the library you gave in link. Your version does not match with the last version of ShellFileDialogs.

@rafcsoares
Copy link

@Profy i don't know... i just pick the master branch and compiled the DLL by myself to share.

In my project i use the raw code instead

@Profy
Copy link

Profy commented Jun 19, 2022

@rafcsoares thank you for your reply. I have already contacted the developer to make some fixes.

@cmwolke-gamedesign
Copy link

cmwolke-gamedesign commented Jul 14, 2022

It seems ShellFileDialogs doesn't respect the directory parameter, at least for me it always opens in the last location instead of where I want it to (test: BasicSampleScene, "Open file directory" button)
Edit: Can easily be fixed by running

if (!string.IsNullOrEmpty) { directory = GetDirectoryPath(directory); }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants