#c# #com #com-interop #openfiledialog
Вопрос:
Цель
Я работаю над заменой диалога открытия системного файла (IFileOpenDialog) на пользовательский диалог. Мое текущее решение отлично работает, когда диалоговое окно открытия файла вызывается многими внешними программами (например, Word, VS, Edge…), но не при вызове из.NET .
Что я сделал
- Создал компонент COM на C# с тем же идентификатором Guid, что и диалоговое окно открытия системного файла, реализующее интерфейс IFileOpenDialog
- Отредактировал реестр с помощью (надеюсь) правильных ключей, чтобы перенаправить диалоговое окно открытия файла в мою библиотеку dll пользовательского диалога
Проблема
Все работает нормально (отображается мой пользовательский диалог), когда диалоговое окно «Открыть файл» вызывается с помощью CoCreateInstance, например, из программы на c :
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(amp;pFileOpen));
Но когда я выполняю следующее из c#, я получаю System.InvalidCastException: Cannot cast from CustomOpenDialog.FilesOpenDialog to type FileOpenDialogRCW
ответ .
var ofd = new System.Windows.Forms.OpenFileDialog();
ofd.ShowDialog();
Детали кода
Мой проект DLL на C# содержит следующее:
- Определение соответствующих COM-интерфейсов (просто показав некоторые из них ниже, большинство из них были взяты из библиотеки Vanara).
[SuppressUnmanagedCodeSecurity]
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]
public interface IFileDialog : IModalWindow
{
...
}
[SuppressUnmanagedCodeSecurity]
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("d57c7288-d4ad-4768-be02-9d969532d960")]
public interface IFileOpenDialog : IFileDialog
{
...
}
- Класс, реализующий пользовательский диалог
[ComVisible(true)]
[Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
[SuppressUnmanagedCodeSecurity]
[ClassInterface(ClassInterfaceType.None)]
public class FilesOpenDialog : IFileOpenDialog, IFileDialogCustomize, IFileDialog, IFileDialog2, IModalWindow, ICustomQueryInterface
{
...
}
- Я отредактировал реестр, применив этот файл reg (созданный с помощью RegAsm):
[HKEY_CURRENT_USERSOFTWAREClassesCustomOpenDialog.FilesOpenDialog]
@="CustomOpenDialog.FilesOpenDialog"
[HKEY_CURRENT_USERSOFTWAREClassesCustomOpenDialog.FilesOpenDialogCLSID]
@="{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}"
[HKEY_CURRENT_USERSOFTWAREClassesCLSID{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}Implemented Categories{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
[HKEY_CURRENT_USERSOFTWAREClassesCLSID{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}ProgId]
@="CustomOpenDialog.FilesOpenDialog"
[HKEY_CURRENT_USERSOFTWAREClassesCLSID{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}]
@="File Open Dialog"
[HKEY_CURRENT_USERSOFTWAREClassesCLSID{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}InProcServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="CustomOpenDialog.FilesOpenDialog"
"Assembly"="CustomOpenDialog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=02fdb5bc5db3ac4c"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///<PATH_TO_DLL_FILE>"
[HKEY_CURRENT_USERSOFTWAREClassesCLSID{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}InprocServer321.0.0.0]
"Class"="CustomOpenDialog.FilesOpenDialog"
"Assembly"="CustomOpenDialog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=02fdb5bc5db3ac4c"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///<PATH_TO_DLL_FILE>"
Есть какие-либо подсказки о том, как решить эту проблему?
Спасибо за помощь!
Комментарии:
1. Поскольку ваш код .NET, вызывающий код .NET, и оба они выполняются в процессе, так что в итоге вы получаете полный . Путь выполнения от сети до .NET, COM находится вне цикла, с 2 классами, которые не могут быть переведены один в другой, как ни странно. Одним из решений было бы написать оболочку записи на C/C (или что-либо еще, кроме .NET), или неработающий COM-сервер вместо inproc, чтобы принудительно проксировать COM (не уверен, поддерживает ли это журнал…). Или попробуйте использовать другую модель потоков реестра, например «Бесплатно».
2. Большое спасибо @SimonMourier У меня было такое чувство, что грядет переписывание на C . (В случае, если вам было интересно, установка модели threading на «Бесплатно» или «Квартира» не устраняет проблему)