Я случайным образом получаю 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 бита, и уходит после перезапуска.
Клиенты, конечно, не запускают приложение в отладчике, таким образом, это, конечно, восстанавливаемо из отладчика.
Вот пара мыслей:
Насколько я с помощью 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 самостоятельно и не использовать класс диалога.
Вы можете рассмотреть возможность использования Windows® API Code Pack for Microsoft®, если вам не нужна поддержка XP или Windows 2003. Возможно, его диалог обозревателя папок не только красивее, но и стабильнее...
У меня была почти такая же проблема (также InvalidCastException) в моем проекте, которая возникала только иногда.
Это произошло из потока, который не работал как STAThread. Хотя мой метод Main был помечен атрибутом [STAThread].
Вы сказали, что не используете отдельный поток. Но, возможно, вы не знаете о из-за асинхронного делегата, который не использует явно класс Thread, а обрабатывается как один.
Если вы создаете новые потоки (не имеет значения, создаете ли вы его с помощью ThreadPool или асинхронного делегата), они всегда являются потоками MTA . Таким образом, вы должны создать свой поток самостоятельно и запустить его явно как STAThread.
Вы можете сделать это примерно так:
var thread=new Thread( () => method() );
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Я думаю, вам нужно покопаться в этом направлении, чтобы найти ошибку.
Этот симптом, кажется, случился с другими , так что, по крайней мере, вы не одиноки; -)
Пара возможностей: