Introduction
Recently I encountered an issue with calling a COM method, which has an in parameter of type HWND
, from a managed code.
When I add a reference to the appropriate tlb file, in order to call the COM method, I’ve seen in the object browser that the parameters type is: ref MyComLib._RemotableHandle
.
Searching for the RemotableHandle
type in MSDN, I (eventually) came across this page: http://msdn.microsoft.com/en-us/library/accessibility._remotablehandle.aspx, where it says: “This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.”
This does make me wonder why this is the type we get in the tlb file.
After trying to search for a solution on how to use this structure, I came across many confusing posts.
That is why I decided to write this short tip, to show a quick and easy way to go around this issue.
Basically the solution I have found is to redefine the interface in your managed code, and instead of the RemotableHandle
just pass IntPtr
.
Code Example
The code example was created using Visual Studio 2012.
Start an ATL project and add a simple ATL object called: CwindowCloser
and give it a progid
: MyWindowCloser
.
Add to it a method called CloseWindow
with an input parameter of type HWND
.
[
object,
uuid(7B7E1B3D-4E0D-4DF9-B374-5FC5376CAF66),
dual,
nonextensible,
pointer_default(unique)
]
interface IwindowCloser : IDispatch{
[id(1)] HRESULT CloseWindow([in] HWND wndHandle);
};
Implement the method by calling DestroyWindow
on the HWND
.
STDMETHODIMP CwindowCloser::CloseWindow(HWND wndHandle)
{
DestroyWindow(wndHandle);
return S_OK;
}
Compile the project, which will create the tlb file and register the COM class.
Start a new WindowsForm
project and add a reference to the tlb file.
Write the following code in the Program.cs:
[STAThread]
static void Main()
{
var myForm = new Form1();
myForm.Show();
var serverType = Type.GetTypeFromProgID("MyWindowCloser");
var comServer = (IwindowCloser)Activator.CreateInstance(serverType);
comServer.CloseWindow(
Check out the intellisense of the CloseWindow
method and see that it expects ref _RemotableHandler
type.
Add the following code outside the Program
class (note that the GUID
matches the uuid
of the interface):
[Guid("7B7E1B3D-4E0D-4DF9-B374-5FC5376CAF66")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComImport]
public interface IwindowCloser
{
void CloseWindow([In] IntPtr hwnd);
}
Now the CloseWindow
method will accept an IntPtr
type.
Pass the HWND
of the Form1
to the CloseWindow
:
comServer.CloseWindow(myForm.Handle);
Now you can execute the code, the native method should be invoked and close the form.
And that's it.