I am trying to use customizable File Open Dialog in my C# application, and I found out that Common Item Dialog provides easy API for customization. However it requires some COM Interop magic, and since I am complete noob when it comes to COM I think it will be good learning excercise. Now I am stuck with following problem:
I created following *.bat file to generate interop assembly:
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"
All x64-related switches come from my (failed) attempts to resolve my problem, and I am not sure if they are necessary.
Now, the problem is: midl.exe generates symbols where handles are converted to _RemotableHandle
type. Instead of Show(IntPtr)
method, it generates 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);
}
Is it possible to generate methods which use regular handles? If not, how am I supposed to call RemoteShow
from my application? Bonus question: Why does it happen this way (COM-wise)?
In some other thread I found a suggestion to convert IntPtr
to _RemotableHandle
with following code:
_RemotableHandle HWNDtoRemotableHandle(IntPtr handle)
{
return (_RemotableHandle)Marshal.PtrToStructure(handle, typeof(_RemotableHandle));
}
But it fails with AccessViolation
error, and I believe that such conversion is not very clean thing to do.