Calling MFC DLL from C#

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • alexgm23
    New Member
    • Mar 2009
    • 6

    Calling MFC DLL from C#

    Hi,

    I'm trying to call a MFC DLL function from C# code, but I just don't know how to do it.

    I've got the DLL's function names using "Dependency Walker" but they look like this:

    ?AddApl@CDocsHe adings@@QAEHPAV CDocsApl@@@Z
    ?AddItem@CDocsH eadings@@QAEHPA VCDocsItems@@H@ Z
    ?AddNew@CDocsHe adings@@UAEXXZ
    ?AddRef@CDocsHe adings@@QAEXDVC String@@@Z
    .....

    Click image for larger version

Name:	sgsql.dll.jpg
Views:	1
Size:	29.9 KB
ID:	5415542

    I've got the C++ header files used to make the DLL, so I know how many parameters and what parameter types the DLL's functions expect.

    Any idea on how can I accomplish this?


    Alejandro Gutierrez
    Last edited by pbmods; Mar 12 '09, 12:02 AM. Reason: Removed email.
  • craig1231
    New Member
    • Mar 2009
    • 6

    #2
    Those look like debug strings. Build -> Clean Solution. Ensure the Configuration is set to Release. Then Build -> Build Solution

    Craig

    Comment

    • alexgm23
      New Member
      • Mar 2009
      • 6

      #3
      Thanks Craig.

      I already found out what those strings mean and how to deal with them, but I still need (too much) help on import a function from the DLL that has a return value of type 'CString &'.

      Can you help me on this?

      Thanks in advance.

      Comment

      • craig1231
        New Member
        • Mar 2009
        • 6

        #4
        Well this can be attacked in many different ways, but heres how I would do it;

        Have the function return 'const char*' instead of 'CString'

        CString theString( "This is a test" );
        char* mychar = new char[theString.GetLe ngth()+1];
        _tcscpy(mychar, theString);
        return mychar;

        then in C# use DLLImport to import the function which it will now return a normal C# string that is recognised and terminated by a null value.

        If you still have any problems, let me know

        Craig

        Comment

        • alexgm23
          New Member
          • Mar 2009
          • 6

          #5
          Thanks again!

          After doing a research I got the same answer, and I think that's the best. But I haven't been explicit enough. The fact is that I can't add such wrapper function returning something more suitable like char* because I don't have the DLL code.

          There's a way to instantiate a C++ class from a DLL. You can call a function that returns a pointer such as a class constructor (returns this). Then in C# you have to declare a struct that properly holds the this pointer:

          Code:
          [StructLayout(LayoutKind.Sequential, Pack = 4)]
          public unsafe struct __CString
          {
          	public IntPtr* _vtable;
          	public int m_Value;
          }
          Then you can make a C# wrapper class for the C++ class CString:

          Code:
          public unsafe class CString : IDisposable
          {
          	private __CString* _cpp;
          
          	[DllImport("mfc42.dll", EntryPoint = "#535", CallingConvention = CallingConvention.ThisCall)]
          	private static extern int _CString_Constructor(__CString* ths, CString str);
          
          	[DllImport("mfc42.dll", EntryPoint = "#537", CallingConvention = CallingConvention.ThisCall)]
          	private static extern int _CString_Constructor(__CString* ths, [MarshalAs(UnmanagedType.LPStr)] String str);
          
          	[DllImport("mfc42.dll", EntryPoint = "#540", CallingConvention = CallingConvention.ThisCall)]
          	private static extern int _CString_Constructor(__CString* ths);
          
          	[DllImport("mfc42.dll", EntryPoint = "#800", CallingConvention = CallingConvention.ThisCall)]
          	private static extern void _CString_Destructor(__CString* ths);
          
          	[DllImport("mfc42.dll", EntryPoint = "#2915", CallingConvention = CallingConvention.ThisCall)]
          	[return: MarshalAs(UnmanagedType.LPStr)]
          	private static extern String _CString_GetBuffer(__CString* ths, int Length);
          
          	public CString(CString str)
          	{
          		_cpp = (__CString*)Memory.Alloc(sizeof(__CString));
          		_CString_Constructor(_cpp, str);
          	}
          		
          	public CString(String str)
          	{
          		_cpp = (__CString*)Memory.Alloc(sizeof(__CString));
          		_CString_Constructor(_cpp, str);
          	}
          		
          	public CString()
          	{
          		_cpp = (__CString*)Memory.Alloc(sizeof(__CString));
          		_CString_Constructor(_cpp);
          	}
          
          	public void Dispose()
          	{
          		_CString_Destructor(_cpp);
          		Memory.Free(_cpp);
          	}
          
          	public String GetBuffer()
          	{
          		return _CString_GetBuffer(_cpp, 255);
          	}
          }
          Actually, I can instatiate a CString in this way without any problems:

          Code:
          class Program
          {
          	static void Main(string[] args)
          	{
          		CString s = new CString("Hello, World!");
          		Console.WriteLine(s.GetBuffer());
          	}
          }
          But when I try to do this:

          Code:
          class Program
          {
          	static void Main(string[] args)
          	{
          		Sample s = new Sample(1000);
          		Console.WriteLine(s.AsString().GetBuffer());
          	}
          }
          
          /*
            CString code...
          */
          
          /*
            Sample Class Wrapper
          */
          
          [StructLayout(LayoutKind.Sequential, Pack = 4)]
          public unsafe struct __Sample
          {
          	public IntPtr* _vtable;
          	public int m_Value;
          }
          
          public unsafe class Sample : IDisposable
          {
          	private __Sample* _cpp;
          
          	[DllImport("OldMFC.dll", EntryPoint = "??0Sample@@QAE@H@Z", CallingConvention = CallingConvention.ThisCall)]
          	private static extern int _Sample_Constructor(__Sample* ths, int Value);
          
          	[DllImport("OldMFC.dll", EntryPoint = "??1Sample@@UAE@XZ", CallingConvention = CallingConvention.ThisCall)]
          	private static extern void _Sample_Destructor(__Sample* ths);
          
          	[DllImport("OldMFC.dll", EntryPoint = "?AsString@Sample@@QAEAAVCString@@XZ", CallingConvention = CallingConvention.ThisCall)]
          	private static extern CString _Sample_AsString(__Sample* ths);
          
          	[DllImport("OldMFC.dll", EntryPoint = "?GetValue@Sample@@QAEHXZ", CallingConvention = CallingConvention.ThisCall)]
          	private static extern int _Sample_GetValue(__Sample* ths);
          
          	public Sample(int Value)
          	{
          		_cpp = (__Sample*)Memory.Alloc(sizeof(__Sample));
          		_Sample_Constructor(_cpp, Value);
          	}
          
          	public void Dispose()
          	{
          		_Sample_Destructor(_cpp);
          		Memory.Free(_cpp);
          	}
          
          	public CString AsString()
          	{
          		return _Sample_AsString(_cpp);
          	}
          }
          
          /*
            Memory Class code...
          */
          I get this error:

          Unspecied error
          Exception from HRESULT: 0x80004005 (E_FAIL)
          The DLL function declaration is:

          CString & Sample::AsStrin g();
          Any idea about it?

          Alex G.

          Comment

          Working...