0

I have library say tenslib.h, I have changed it to tensLibs.dll using visual Studio 10 C (I have used this).

I want to open it using C# window form application. I build it and succeeded. But when I run the application, there is an error:

An unhandled exception of type 'System.DllNotFoundException' occurred in WindowsFormsCSharpApplication3.exe

Additional information: Unable to load DLL 'tensLibs.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Here the snapshot of my program

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices; //for export dll


namespace WindowsFormsCSharpApplication3
{
public partial class Form1 : Form
{
    [DllImport("tensLibs.dll", EntryPoint = "tens_init")]
    public static extern int tens_init([MarshalAsAttribute(UnmanagedType.LPStr)]string port);

 private void button2_Click(object sender, EventArgs e)
    {
        if (tens_init("COM8") == 1)
            label2.Text="Com 8 is initiated";
        else
            label2.Text="Com 8 does not exists";
    }
}
}

I have add the tensLibs.dll in the folders but the error still appear. I have tried to add reference the dll file to the project but cannot added.

I used the depedency walker program to find the root of my .dll it need Kernel32.dll and MSVCR100d.dll and I have add to my folders, the error still occur.

I run in x86.

This is my Tens.h source

#ifndef TENSLIB_H_
#define TENSLIB_H_

#ifdef __cplusplus
 extern "C" {
#endif

int  tens_init( char* port );
void tens_shutdown( void );


int tens_tutor( unsigned char finger );
void tens_shutdown( void );

int tens_settarget( unsigned char id );

int tens_enable( unsigned char supply_on, unsigned char bridge_on );
int tens_power( unsigned char power );
int tens_freq( unsigned char freq );
int tens_control( unsigned char power, unsigned char freq );

int tens_chargerate( unsigned char rate );
int tens_tunepower( unsigned char up );
int tens_writeconfig( void );
int tens_changeid( unsigned char id );

int tens_envs( unsigned char distance );
int tens_envsconf( unsigned char pmin, unsigned char pmax, unsigned char fmin, unsigned char fmax );

int tens_tutor( unsigned char finger );

int tens_garbage( void );


#ifdef __cplusplus
}
#endif

#endif

And for tens.c is to long I just put the tens_init()

#ifdef __cplusplus
extern "C" {
#endif

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include "tenslib.h"

#ifdef TENSLIB_CHATTER
#define PRINTF( ... ) printf( __VA_ARGS__ )
#else
    #define PRINTF( ... )
#endif

#define TRUE  1
 #define FALSE 0

#define PACKET_ENABLE      0
#define PACKET_POWER       1
#define PACKET_FREQ        2
#define PACKET_CONTROL     3
#define PACKET_CHARGERATE  4
#define PACKET_TUNEPOWER   5
 #define PACKET_WRITECONFIG 6
#define PACKET_CHANGEID    7
#define PACKET_ENVS        8
#define PACKET_ENVSCONF    9
#define PACKET_TUTOR       10

static HANDLE hnd_serial = INVALID_HANDLE_VALUE;
static unsigned char patch_id = 0;

 int tens_init( char* port )
 {
    DCB conf = { 0 };
conf.DCBlength = sizeof( conf );

if ( hnd_serial != INVALID_HANDLE_VALUE )
    CloseHandle( hnd_serial );

PRINTF( "Opening serial connection.\n" );

hnd_serial = CreateFileA( port, GENERIC_READ | GENERIC_WRITE, 0, 0,
                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );

if ( hnd_serial == INVALID_HANDLE_VALUE ) {
    PRINTF( "Failed to open serial port.\n" );
    return FALSE;
}

if ( !GetCommState( hnd_serial, &conf ) ) {
    PRINTF( "Failed to configure serial port.\n" );
    CloseHandle( hnd_serial );
    hnd_serial = INVALID_HANDLE_VALUE;
    return FALSE;
}

conf.BaudRate = CBR_9600;
conf.ByteSize = 8;
conf.Parity = NOPARITY;
conf.StopBits = ONESTOPBIT;

if ( !SetCommState( hnd_serial, &conf ) ) {
    PRINTF( "Failed to configure serial port.\n" );
    CloseHandle( hnd_serial );
    hnd_serial = INVALID_HANDLE_VALUE;
    return FALSE;   
}

PRINTF( "Connected to %s at 9600/8/N/1.\n", port );
return TRUE;
 }

     void tens_shutdown( void )
 {
if ( hnd_serial != INVALID_HANDLE_VALUE ) {
    PRINTF( "Closing serial connection.\n" );
    CloseHandle( hnd_serial );
    hnd_serial = INVALID_HANDLE_VALUE;
}
 }

can any one tell me what is this problem, and how can i fix it?

Thank you.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Limavolt
  • 811
  • 1
  • 14
  • 26
  • [PInvoke](https://msdn.microsoft.com/en-us/library/55d3thsc.aspx) – Taekahn Mar 02 '15 at 03:15
  • possible duplicate of [Unable to load DLL (Module could not be found HRESULT: 0x8007007E)](http://stackoverflow.com/questions/9003072/unable-to-load-dll-module-could-not-be-found-hresult-0x8007007e) – Claies Mar 02 '15 at 04:19
  • I have shown that page, but I still not working, I have tried using console C# and working, what the different between window form application and console c#? – Limavolt Mar 02 '15 at 05:19
  • When you say you changed tenslib.h to tenslib.dll, you mean you compiled it to a dll right? – evolvedmicrobe Mar 02 '15 at 05:34
  • And when you say you added tensLibs.dll in the folders, do you mean you have placed it in bin/Release and bin/Debug? – evolvedmicrobe Mar 02 '15 at 05:34
  • Yes, I have dll file, and I use it in my programs. In console program it working, but in window form it not working. I dont have bin/Release in my program, but when I add it in bin/Debug it say error Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in .. \bin\Debug\WindowsFormsCSharpApplication3.vshost.exe'. Additional Information: A call to PInvoke function 'WindowsFormsCSharpApplication3!WindowsFormsCSharpApplication3.Form1::tens_init' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature – Limavolt Mar 02 '15 at 05:41
  • I don't see why it would work in one case and not the other, what does your function do in the DLL? It's possible the bug is Inside your unmanaged code. Also the one big diference between console vs winform is the com threading model, are you doing anything funky with threads in the dll? Can you add a simple function that takes an int and returns that int +1 to your dll and see if you get the same issue with it (to saparate an issue INSIDE the dll from an issue "calling" the dll)? – Ronan Thibaudau Mar 02 '15 at 05:54
  • Ideally it would be nice if you could also give us the source of the tenslib header and cpp – Ronan Thibaudau Mar 02 '15 at 06:02
  • I will edit my question to add source of tenslib – Limavolt Mar 02 '15 at 06:03
  • The most likely culprit i can think of in your situation is the calling convention not matching, do you know what calling convention was used by the C compiler? Can you try running your C# program by adding Callingnvention = CallingConvention.StdCall to your C# program and testing, if it doesn't work doing the same but changing to CallingConvention.Cdecl and testing that too? – Ronan Thibaudau Mar 02 '15 at 06:32
  • I have added: [DllImport(@"tensLibs.dll", EntryPoint = "tens_init", CallingConvention = CallingConvention.Cdecl)] public static extern int tens_init([MarshalAsAttribute(UnmanagedType.LPStr)]string port); the error is not appear but the function is not working – Limavolt Mar 02 '15 at 06:35
  • Now you've fixed the interop which is the subject of this question. We can't really help with the rest of your program with no details. – David Heffernan Mar 02 '15 at 07:05
  • Hi @DavidHeffernan, I am sorry, what is the meaning of interop? my english and my programming are not good enough. Should I make a new question? – Limavolt Mar 02 '15 at 07:11
  • Interop is the connecting of two modules that don't connect directly. Here it is the managed and unmanaged modules. The interop is fine. You had missing dependency, and calling convention problem. – David Heffernan Mar 02 '15 at 07:26
  • Basically you have multiple problems, the one you asked about here was working from C# with a C++ dll, this solved your question but you now have another question (which you should ask a separate question) which is "why doesn't my C++ function work" and has nothing to do with C# – Ronan Thibaudau Mar 02 '15 at 08:11
  • @RonanThibaudau thank you, I am sorry, your answers is right, I have to use Cdecl, yesterday I used my laptop which have different com port with my pc in the office – Limavolt Mar 03 '15 at 00:19

1 Answers1

2

There are two problems with the interop.

1. Missing Dependency

The System.DllNotFoundException exception tells you that your DLL, or one of its dependencies cannot be found. Place the DLL in the same directory as the executable. Install any runtime dependencies of the DLL, for instance the MSVC runtime. You may need to compile the release build of the DLL if you don't have the version of VS used for the DLL on your target machine.

2. Calling convention mismatch

The DLL exports cdecl functions. You import as stdcall. The DllImport attribute needs to specify the correct calling convention:

[DllImport("tensLibs.dll", CallingConvention = CallingConvention.Cdecl)]

An aside. Boolean testing in C is as follows. Zero is false, everything else is true. Don't test == 1 in your C# code. Test != 0. However, it is simpler to use bool for the return type of tens_init and let the marshaler do the work for you.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490