WinForms: Почему я получаю InvalidCastException при показе диалогового окна браузера папки?

Я случайным образом получаю InvalidCastException при показе FolderBrowserDialog, и также многие клиенты сообщили об этом.

Я не смог найти что-либо релевантным в Интернете. Кто-либо знает то, что заставляет это/как фиксировать это?

Мой код:

        using (FolderBrowserDialog fbd = new FolderBrowserDialog())
        {
            fbd.ShowNewFolderButton = false;
            if (fbd.ShowDialog() == DialogResult.OK)

Отслеживание стека:

Error: System.InvalidCastException: 
'Unable to cast object of type 'System.__ComObject' to type 'IMalloc'.'.

    Stack trace:    
at System.Windows.Forms.UnsafeNativeMethods.Shell32.SHGetMalloc(IMalloc[] ppMalloc)
at System.Windows.Forms.FolderBrowserDialog.GetSHMalloc()
at System.Windows.Forms.FolderBrowserDialog.RunDialog(IntPtr hWndOwner)
at System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window owner)
at System.Windows.Forms.CommonDialog.ShowDialog()

Править: Дополнительная информация: Я смог воспроизвести это только при выполнении в отладчике VS2008.

При исчерпывании отладчика это происходит только очень редко (произошел несколько раз за 6 месяцев) в моем Windows 7 на 64 бита, и уходит после перезапуска.

Клиенты, конечно, не запускают приложение в отладчике, таким образом, это, конечно, восстанавливаемо из отладчика.

6
задан David 19 July 2015 в 03:17
поделиться

4 ответа

Вот пара мыслей:

Насколько я с помощью Reflector.Net можно сказать, что это происходит в блоке finally сразу после возврата из реального диалогового окна. В основном здесь возникает проблема:

IntPtr pszPath = IntPtr.Zero;
try
{
    UnsafeNativeMethods.BROWSEINFO lpbi = new UnsafeNativeMethods.BROWSEINFO();
    hglobal = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
    pszPath = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize));
    ... /*init structure*/
    pidl = UnsafeNativeMethods.Shell32.SHBrowseForFolder(lpbi);
    if (pidl != IntPtr.Zero)
    {
        UnsafeNativeMethods.Shell32.SHGetPathFromIDList(pidl, pszPath);
        ...
    }
}
finally
{
    UnsafeNativeMethods.IMalloc sHMalloc = GetSHMalloc(); /* Boom! */
    sHMalloc.Free(zero);
    ...

Если вы вообще не видите диалоговое окно, указанное выше исключение, вероятно, маскирует реальную ошибку. Попробуйте запустить с «Прерыванием при исключении» и отключите Инструменты-> Отладка-> Только мой код. Код в блоке try выглядит довольно просто, самое рискованное, что они делают, - это PInvoke на SHBrowseForFolder shell32.dll. Я был бы удивлен, если бы он генерировал «случайную» ошибку.

Если вы видите диалоговое окно и только после закрытия вы получаете эту ошибку, вы можете просто проигнорировать ее за счет утечки памяти, когда это произойдет:

    using (FolderBrowserDialog fbd = new FolderBrowserDialog())
    {
        fbd.ShowNewFolderButton = false;
        DialogResult r;
        try { r = fbd.ShowDialog(); }
        catch (InvalidCastException) 
        { r = DialogResult.OK; /* you might check the path first */ }
        if (fbd.ShowDialog() == DialogResult.OK)
            ...

Конечно, вы всегда можете PInvoke SHBrowseForFolder самостоятельно и не использовать класс диалога.

1
ответ дан 17 December 2019 в 22:11
поделиться

Вы можете рассмотреть возможность использования Windows® API Code Pack for Microsoft®, если вам не нужна поддержка XP или Windows 2003. Возможно, его диалог обозревателя папок не только красивее, но и стабильнее...

0
ответ дан 17 December 2019 в 22:11
поделиться

У меня была почти такая же проблема (также InvalidCastException) в моем проекте, которая возникала только иногда.

Это произошло из потока, который не работал как STAThread. Хотя мой метод Main был помечен атрибутом [STAThread].

Вы сказали, что не используете отдельный поток. Но, возможно, вы не знаете о из-за асинхронного делегата, который не использует явно класс Thread, а обрабатывается как один.

Если вы создаете новые потоки (не имеет значения, создаете ли вы его с помощью ThreadPool или асинхронного делегата), они всегда являются потоками MTA . Таким образом, вы должны создать свой поток самостоятельно и запустить его явно как STAThread.

Вы можете сделать это примерно так:

var thread=new Thread( () => method() );
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Я думаю, вам нужно покопаться в этом направлении, чтобы найти ошибку.

0
ответ дан 17 December 2019 в 22:11
поделиться

Этот симптом, кажется, случился с другими , так что, по крайней мере, вы не одиноки; -)

Пара возможностей:

  1. Вы запускаете это в однопотоковой квартире (т.е. с [STAThreadAttribute] в методе точки входа)?
  2. Максимальная длина пути в Windows составляет 260 символов. Может ли начальный путь, используемый FolderBrowserDialog, быть длиннее этого? Если вы можете (иногда) воспроизвести это в режиме отладки VS, попробуйте переместить свое решение выше в дереве папок, сократив таким образом путь к папке по умолчанию, используемый диалоговым окном.
0
ответ дан 17 December 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: