我正在尝试在我的 C# 应用程序中使用可自定义的文件打开对话框,我发现通用项对话框提供了简单的自定义 API。然而,它需要一些 COM 互操作魔法,而且由于我在 COM 方面完全是菜鸟,我认为这将是一个很好的学习练习。现在我遇到了以下问题:
我创建了以下*.bat文件来生成互操作程序集:
set OUT_DIR=.\com_interop
if not exist %OUT_DIR% mkdir "%OUT_DIR%
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
set SDK_DIR="C:\Program Files\Microsoft SDKs\Windows\v7.1"
%SDK_DIR%\Bin\midl.exe /server none /client stub /out "%OUT_DIR%" /tlb ShObjIdl.tlb /x64 %SDK_DIR%\Include\ShObjIdl.idl
%SDK_DIR%\Bin\TlbImp.exe "%OUT_DIR%\ShObjIdl.tlb" /out:ComInterop.ShObj.dll /namespace:ComInterop.ShObj /machine:X64
move /Y ComInterop.ShObj.dll "%OUT_DIR%\ComInterop.ShObj.dll"
所有与 x64 相关的开关都来自我(失败的)解决问题的尝试,我不确定它们是否有必要。
现在,问题是:midl.exe在句柄转换为_RemotableHandle
类型的位置生成符号。Show(IntPtr)
它生成的不是方法,而是RemoteShow(_RemotableHandle)
:
[Guid("D57C7288-D4AD-4768-BE02-9D969532D960")]
[InterfaceType(1)]
public interface IFileOpenDialog : IFileDialog
{
void AddPlace(IShellItem psi, FDAP FDAP);
void Advise(IFileDialogEvents pfde, out uint pdwCookie);
void ClearClientData();
void Close(int hr);
void GetCurrentSelection(out IShellItem ppsi);
void GetFileName(out string pszName);
void GetFileTypeIndex(out uint piFileType);
void GetFolder(out IShellItem ppsi);
void GetOptions(out uint pfos);
void GetResult(out IShellItem ppsi);
void GetResults(out IShellItemArray ppenum);
void GetSelectedItems(out IShellItemArray ppsai);
void RemoteShow([ComAliasName("ComInterop.ShObj.wireHWND")] ref _RemotableHandle hwndOwner); // <===== argument, why u no HWND?
void SetClientGuid(ref Guid guid);
void SetDefaultExtension(string pszDefaultExtension);
void SetDefaultFolder(IShellItem psi);
void SetFileName(string pszName);
void SetFileNameLabel(string pszLabel);
void SetFileTypeIndex(uint iFileType);
void SetFileTypes(uint cFileTypes, ref _COMDLG_FILTERSPEC rgFilterSpec);
void SetFilter(IShellItemFilter pFilter);
void SetFolder(IShellItem psi);
void SetOkButtonLabel(string pszText);
void SetOptions(uint fos);
void SetTitle(string pszTitle);
void Unadvise(uint dwCookie);
}
是否可以生成使用常规句柄的方法?如果没有,我应该如何RemoteShow
从我的应用程序中调用?额外的问题:为什么会这样(COM-wise)?
在其他一些线程中,我发现了使用以下代码转换IntPtr
为的建议:_RemotableHandle
_RemotableHandle HWNDtoRemotableHandle(IntPtr handle)
{
return (_RemotableHandle)Marshal.PtrToStructure(handle, typeof(_RemotableHandle));
}
但它因AccessViolation
错误而失败,我相信这种转换不是很干净的事情。