0

I am currently trying to communicate with a device using CAN. To do so I am using PCAN Basic using C++.

Unfortunately, I know nothing about accessing a function inside a dll file (which is what is provided). I found this link:

Calling a dll function from C++

and am trying to use LoadLibrary via code I found here:

http://www.goffconcepts.com/techarticles/development/cpp/calldll.html

My Code:

// dll_get_func.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <stdio.h> 
#include <conio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h> /* For sqrt() */
#include <windows.h> 

#define DELCLDIR __declspec("Pcan_usb.dll")
#define PCAN_USBBUS1 0x51
#define CAN_BAUD_1M     0x0014  //   1 MBit/s
#define MSGTYPE_STANDARD 0x00 

typedef struct {
    DWORD ID;        // 11/29 bit identifier
    BYTE  MSGTYPE;   // Bits from MSGTYPE_*
    BYTE  LEN;       // Data Length Code of the Msg (0..8)
    BYTE  DATA[8];   // Data 0 .. 7
} TPCANMsg;


int hardCodeInit(void)
{
    /* get handle to dll */
   HINSTANCE hGetProcIDDLL = LoadLibrary(_T("Pcan_usb.dll"));

   /* get pointer to the function in the dll*/
   FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hGetProcIDDLL),"CAN_Init");

   /*
      Define the Function in the DLL for reuse. This is just prototyping the dll's function.
      A mock of it. Use "stdcall" for maximum compatibility.
   */
   typedef int (__stdcall * pICFUNC)(WORD wBTR0BTR1, int CANMsgType);

   pICFUNC CAN_Init;
   CAN_Init = pICFUNC(lpfnGetProcessID);
   //DWORD __stdcall CAN_Init(WORD wBTR0BTR1, int CANMsgType);  

   /* The actual call to the function contained in the dll */
   int intMyReturnVal = CAN_Init(PCAN_USBBUS1,CAN_BAUD_1M);

   /* Release the Dll */
   FreeLibrary(hGetProcIDDLL);

   /* The return val from the dll */
    return intMyReturnVal;
}
int hardCodeWrite(void)
{
   HINSTANCE hGetProcIDDLL = LoadLibrary(_T("Pcan_usb.dll"));
   FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hGetProcIDDLL),"CAN_Write");
   typedef int (__stdcall * pICFUNC)(WORD wBTR0BTR1, TPCANMsg CANMsgType);
   pICFUNC CAN_Write;
   CAN_Write = pICFUNC(lpfnGetProcessID);

   TPCANMsg msgOut; 
   msgOut.MSGTYPE = MSGTYPE_STANDARD;
   msgOut.LEN = 1;
   msgOut.DATA[0] = 0x03; // 0x03 = Get ID

   int toReturn;
   toReturn = CAN_Write(PCAN_USBBUS1,msgOut);
   FreeLibrary(hGetProcIDDLL);
   return toReturn;
}
int _tmain(int argc, _TCHAR* argv[])
{
    int derp=hardCodeInit();
    int herp=hardCodeWrite();
    std::cout<<derp;
    std::cout<<herp;
    _getch();
    return 0;
}

However, Visual Studio says that there is a:

Unhandled exception at 0x10001D95 (Pcan_usb.dll) in dll_get_func.exe: 0xC0000005: 
Access violation reading location 0x00000051.

I have Pcan_usb.dll and Pcan_usb.lib in the same folder and I am using visual studio 2012.

Community
  • 1
  • 1
code11
  • 1,986
  • 5
  • 29
  • 37
  • 1
    Check your return values for `LoadLibrary` and `GetProcAddress`. If they fail what does `GetLastError` say? – Dave Rager Jul 02 '13 at 18:13
  • Does the DLL come with a link library file and header files? Then include the header files and link with the library, and you don't have to load the DLL yourself or worry about function pointers. – Some programmer dude Jul 02 '13 at 18:13
  • @JoachimPileborg- Good point, I looked more carefully and there is a .h file. I included the .h file. It now gives me `Error 1 error LNK2019: unresolved external symbol _CAN_Init@8 referenced in function _wmain C:\Users\britter\Documents\Visual Studio 2012\Projects\dll_get_func\dll_get_func\dll_get_func.obj dll_get_func` which is guess is a library not being resolved. You mention "linking the library" is that a line of code that I need to add, or options that I need to configure in my visual studio project? (and if this is getting off topic, should I submit a new question/edit?) – code11 Jul 02 '13 at 19:40

2 Answers2

1
Access violation reading location 0x00000051.

This tells me the function is treating PCAN_USBBUS1 as a pointer. Perhaps:

#define PCAN_USBBUS1 0x51

should be changed to

WORD pcan_usbbus1 = 0x51;

And the call to CAN_Init should be changed to:

int intMyReturnVal = CAN_Init(&pcan_usbbus1, CAN_BAUD_1M);

The function signature should probably be something like:

typedef int (__stdcall * pICFUNC)(WORD* wBTR0BTR1, int CANMsgType);
                                      ^ pointer here

I imagine CAN_BAUD_1M might also need to be changed in the same way but maybe not.

Dave Rager
  • 8,002
  • 3
  • 33
  • 52
  • That fixed that particular error, but caused another: `Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.` I have never encountered such an error, and its causes seem very varied. What is "calling convention" referring to? – code11 Jul 02 '13 at 18:56
  • 1
    The function is likely not `__stdcall` but `__cdecl` which means the caller cleans up the stack. Basically when the function returns, specifying `__stdcall` assumes the callee is cleaning up the stack, but when that doesn't happen your stack is now hosed and you get this error. `__cdecl` says your program is responsible for cleaning up the stack. – Dave Rager Jul 02 '13 at 19:43
1

There are several points here. Signature of the LoadLibrary:

HMODULE WINAPI LoadLibrary(_In_  LPCTSTR lpFileName);

Remove unneeded casts. This will simplify reading and understanding your code.

FARPROC lpfnGetProcessID - the name of the variable is confusing. This might be a source of confusion or misunderstanding.

Regarding the AV - the signature of the CAN_Init function as you are trying to use it is wrong. From your post it is hard to tell for sure what is should be. Look into manual (if possible), header file, etc.

Main point - you should not release the library. There are rare cases when this is needed. Most likely your case does not need this. It is very difficult to believe that you need to reload the library (and this what happens when you call FreeLibrary/LoadLibrary!) between initing it and writing.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
  • I agree that the name is confusing. I will change that. However, you say I should not release the library, are you referring to this line:`FreeLibrary(hGetProcIDDLL);` or something different? – code11 Jul 02 '13 at 19:02
  • Yes, remove this line. The library will be released automatically when the process will terminate. – Kirill Kobelev Jul 02 '13 at 19:11