7

I got a C++ dll which has to be integrated in a C# project.

I think I found the correct way to do it, but calling the dll gives me this error: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

This is the function in the dll:

extern long FAR PASCAL convert (LPSTR filename);

And this is the code I'm using in C#

namespace Test{
public partial class Form1 : Form
{
    [DllImport("convert.dll", SetLastError = true)]
    static extern Int32 convert([MarshalAs(UnmanagedType.LPStr)] string filename);

    private void button1_Click(object sender, EventArgs e)
    {
        // generate textfile
        string filename = "testfile.txt";

        StreamWriter sw = new StreamWriter(filename);
        sw.WriteLine("line1");
        sw.WriteLine("line2");
        sw.Close();

        // add checksum
        Int32 ret = 0;
        try
        {
            ret = convert(filename);

            Console.WriteLine("Result of DLL:  {0}", ret.ToString());
        }
        catch (Exception ex)
        {
            lbl.Text = ex.ToString();
        }
    }
}}

Any ideas on how to proceed with this?

Thanks a lot, Frank

Frank
  • 5,741
  • 4
  • 28
  • 49

4 Answers4

4

Try to switch your C# code from AnyCPU to x86 (in Properties dialog).

Josip Medved
  • 3,631
  • 1
  • 28
  • 36
  • same result ... System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) – Frank Jun 08 '10 at 07:53
  • 1
    @Frank: Exception points to x86/x64 mismatch in DLL and C# code. If C++ code is compiled as x64, try setting C# code also to x64 (and vice-versa if code is x86). When dealing with DllImport, that is only cause for that exception (as per Microsoft documentation - http://msdn.microsoft.com/en-us/library/system.badimageformatexception.aspx). – Josip Medved Jun 08 '10 at 08:28
4

Your exported function uses the PASCAL calling convention, which in Windows is the same as stdcall. The .Net runtime needs to know about that, so modify your C# method signature as follows:

[DllImport("convert.dll", SetLastError = true, CallingConvention=CallingConvention.StdCall)]
static extern Int32 convert([MarshalAs(UnmanagedType.LPStr)] string filename);
Frank Bollack
  • 24,478
  • 5
  • 49
  • 58
  • there was an ) too much at the first line, so removed this: [DllImport("convert.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] static extern Int32 convert([MarshalAs(UnmanagedType.LPStr)] string filename); but still the same error System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) – Frank Jun 08 '10 at 07:56
  • 1
    Can you please give some more details about your platform, project settings and the DLL used. (Architecture x86/x64 etc) – Frank Bollack Jun 08 '10 at 08:07
4

try to use __stdcall (or WINAPI or APIENTRY) in the function exported from the DLL.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I have to use the dll "as is" ... no changes allowed – Frank Jun 08 '10 at 07:57
  • There are different declaration of PASCAL in different headers (also in WinDef.h), but dierct usage of `__stdcall` will be allways interpreted in the same way – Oleg Jun 08 '10 at 08:00
  • @Frank: Ohhh! The DLL is not from your code, than probably the DLL has really another format like 64-bit etc? – Oleg Jun 08 '10 at 08:03
  • You can use dumpbin.exe with /headers parameter from Visual Studio or dependency walker www.dependencywalker.com to see more information about dll – Oleg Jun 08 '10 at 08:07
  • pffff... dependency walker shows: Error: at least one file was not a 32-bit or 64-bit Windows module No PE signature found. This file appears to be a 16-bit Windows module. I could be wrong, but this doesn't seem to look good... – Frank Jun 08 '10 at 08:12
  • a 16-bit Windows module or a DOS Program can be all dumped with `dumpbin.exe /headers convert.dll`. You can also open the DLL with a text editor and verify is the first 2 bytes are 'MZ'. – Oleg Jun 08 '10 at 08:17
  • indeed starts with MZ.! so what you mean is that it can be converted with dumpbin.exe ? – Frank Jun 08 '10 at 08:20
  • Not converted but examined. What kind of DLL you have. For which processor it is compiled. If it DOS/Windows/OS2 etc dll etc. After you will know more about the DLL you can decide what to do. One more question: what is that DLL? Is it a part of well known product? Can it be free downloaded? – Oleg Jun 08 '10 at 08:26
  • no it's not free, but part of a larger project (embedded software) I have to generate datafiles for. tried dumpbin, result: warning LNK4094: is an MS-DOS executable; use EXEHDR to dump it – Frank Jun 08 '10 at 08:30
  • The reason can be different. I have problem to give a recommendation without more information. It can be, for example, that you downloaded the DLL from FTP with ASCII instead on IMAGE type and you have CR LF instead of all CR in you binary. It can be that you receive the corrupted DLL with other way. If can be a lot of reason, why you have so strange DLL. At least it is clear, that you have not a problem with C# import declaration, but you have NOT correct Windows DLL at all. – Oleg Jun 08 '10 at 09:57
  • Thanks a lot Oleg. I will contact the supplier of it to deliver me a new version compiled for usage on x86 – Frank Jun 08 '10 at 09:59
0

Two main steps involved are

1- Creating a C++ dll

In visual studio

**New->Project->Class Library** in c++ template Name of project here is first_dll in visual studio 2010. Now **declare your function as public** in first_dll.h file and write the code in first_dll.cpp file as shown below.

Header File

Cpp File

Check **Project-> Properties -> Configuration/General -> Configuration Type** 
this option should be **Dynamic Library(.dll)** and build the solution/project now.

first_dll.dll file is created in Debug folder

2- Linking it in C# project

Open C# project

Rightclick on project name in solution explorer -> Add -> References -> Browse to path
where first_dll.dll is created and add the file 

Add this line at top in C# project

Using first_dll; 

Now file can be accessed using below statement in some function

double var = Class1.sum(4,5);

I linked the C++ project .dll created in VS2010 to C# project created in VS2013. It works well.

Croko
  • 99
  • 1
  • 4