P/Invoke MFC member

T

Tony Maresca

Hello.

My C# based assembly is loaded into a commercial MFC
based application as a 'plug-in' of sorts. The host app
exposes limited API functionality, and one of the APIs
it provides is a static exported unmanaged C++ function
that returns a pointer to its CWinApp object.

From my assembly, I need to P/Invoke the following
member on the instance of the CWinApp:

CWinApp::pumpMessage()

I believe that I can do this, using [DllImport()...] with
CallingConvention.ThisCall, but I don't know how to
identify the export (it seems to be that MFC70P.dll shows
only ordinals).

Any ideas on if/how to do this from C# ?

TIA, Tony
 
N

Nicholas Paldino [.NET/C# MVP]

Tony,

Why not create a function which will make the call to the static member
and return the pointer? You can then export this easily, and not have to
worry about the calling convention and things of that nature.

Hope this helps.
 
W

Willy Denoyette [MVP]

Tony Maresca said:
Hello.

My C# based assembly is loaded into a commercial MFC
based application as a 'plug-in' of sorts. The host app
exposes limited API functionality, and one of the APIs
it provides is a static exported unmanaged C++ function
that returns a pointer to its CWinApp object.

From my assembly, I need to P/Invoke the following
member on the instance of the CWinApp:

CWinApp::pumpMessage()

I believe that I can do this, using [DllImport()...] with
CallingConvention.ThisCall, but I don't know how to
identify the export (it seems to be that MFC70P.dll shows only ordinals).

Any ideas on if/how to do this from C# ?

TIA, Tony
You can't use the ThisCall convention explicitely from C#, this feature is
for compiler writes only.
Before yo can call a method on an unmanaged class you need an instance of
the class (or at least a pointer to the class instance), you can't do this
from C# either. So your only option is to thunk the call, or use managed C++
to interop with MFC.

Willy.
 
T

Tony Maresca


Thanks for the response.

As I mentioned in my orignal post, I already have
a pointer to the CWinApp instance (this is returned
by this exported C++ function):

// C++ header declaration:

CWinApp* GetWinApp(); // This is exported by name

// C# declaration:

[DllImport("host.exe"), CallingConvention=CallingConvention.Cdecl]
IntPtr GetWinApp();

Hence, I can call the above export to get a pointer
to the CWinApp instance.

Given that, is there any way to call PumpMessage() ?

--
 
W

Willy Denoyette [MVP]

Tony Maresca said:

Thanks for the response.

As I mentioned in my orignal post, I already have
a pointer to the CWinApp instance (this is returned
by this exported C++ function):

// C++ header declaration:

CWinApp* GetWinApp(); // This is exported by name

// C# declaration:

[DllImport("host.exe"), CallingConvention=CallingConvention.Cdecl]
IntPtr GetWinApp();

Hence, I can call the above export to get a pointer
to the CWinApp instance.

Given that, is there any way to call PumpMessage() ?

No you can't. DllImport can only call non member functions with "C linkage",
it cannot be used to call native C++ class member functions. Your only
option is to write a thunk or wrapper using managed C++, it's the only
language that allows mixed code.

I'm also not clear on why you need to call PumpMessage() from an add-in,
pumping messages is the task of the host not the task of the add-in.
Willy.
 
T

Tony Maresca

Willy Denoyette said:
I'm also not clear on why you need to call PumpMessage() from an add-in,
pumping messages is the task of the host not the task of the add-in.
Willy.

Yes, in a perfect world it would probably not be needed.

The host application is a computer-aided design program
called AutoCAD. It's fairly complicated, and there are several
programming interfaces. Add to that, the fact that it is not
multi-threaded. Unfortunately, users can write scripts that
can include long processing loops that execute in an MDI
document's thread/fibre, which is also the target of all input
messages. Hence, when these scripts execute, the host app
fails to process its message queue until the script has ended
and hence, the host app appears non-responsive to the user.

As a workaround, a script can call the plug-in function from a
loop, which in-turn calls PumpMessage() to force the host to
process pending messages.

Regards, Tony.
 
W

Willy Denoyette [MVP]

Tony Maresca said:
Yes, in a perfect world it would probably not be needed.

The host application is a computer-aided design program
called AutoCAD. It's fairly complicated, and there are several
programming interfaces. Add to that, the fact that it is not
multi-threaded. Unfortunately, users can write scripts that
can include long processing loops that execute in an MDI
document's thread/fibre, which is also the target of all input messages.
Hence, when these scripts execute, the host app
fails to process its message queue until the script has ended
and hence, the host app appears non-responsive to the user.

As a workaround, a script can call the plug-in function from a
loop, which in-turn calls PumpMessage() to force the host to process
pending messages.

Regards, Tony.

Those AutoCAD scripts are written in what, a specific AutoCAD language or
what?
Just currious, how do they manage to call a member function when the only
thing they have is a pointer to a class?

Willy.
 
T

Tony Maresca

Willy Denoyette said:
Those AutoCAD scripts are written in what, a specific AutoCAD language or
what?

There's several APIs (C++, LISP, VBA, CLR, and high-level command scripting).
Just currious, how do they manage to call a member function when the only
thing they have is a pointer to a class?

Via a native C++ wrapper.

I'm simply trying to replace that with a managed wrapper.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top