리얼시스 CANPro.dll 를 import 하는데 로드를 할 수 없다고 합니다.

안녕하세요. 이번에 새로 가입한 c# 초짜 입니다.

다름이 아니라 리얼시스 사의 CANPro.dll 을 불러와서 통신 예제를 작성하고자 하는데 버튼 이벤트에 api 를 연결하고 실행하면 로드를 할 수 없다고 출력 됩니다.

프로젝트 폴더와 exe 폴더 모두에 dll을 복사해 놓았지만 같은 메시지를 출력합니다. 제가 무엇에서 오류를 범하고 있는지 많은 도움 부탁 드립니다.

p.s 혹시 CAN 통신을 열 때 C# 에서는 어떤 API를 사용해야 하는지 알려주시면 감사하겠습니다.

2개의 좋아요

DLL을 로드할 수 없는 상황이 매우 많은 경우가 있어 좀 더 자세히 써주시면 파악하기 편할 것 같습니다.
일단 dll이 c#으로 작성된 것인지, C++로 작성된 것인지도 알아야하고 코드 내부에서 직접적으로 Import해서 사용하는지도 필요합니다.

CAN 통신은 안해본 분야라서… 저는 답변을 드리기 어려울 것 같아요 :cry:

2개의 좋아요

리얼시스에서 제공하는 것은 C++용인 것으로 보입니다.

2개의 좋아요

사용하고 있으신 플랫폼?(MFC, WPF, 언어 : C …)과 오류 메시지를 올려주시면
문제점을 좀더 정확하게 알 수 있을것 같습니다.

image
출처 : i.got.it

image

출처 : realsys.co.kr

C#용은 아닌 것 같습니다.

2개의 좋아요

조금더 알아보니 D2XX에 대한 예제가 있네요.
말씀하신 CANPro.dll에 관한 내용인지는 모르겠습니다만,
리얼시스 메뉴얼에서 제공하는 예제 사이트를 통해 찾았습니다.

image

image

출처 : http://ftdichip.com

2개의 좋아요

답변 감사합니다.
C++ 로 작성되었으며 MFC 프로젝트에서는 정상적으로 사용할 수 있습니다.
C# 프로젝트 내부에서 직접적으로 IMPORT 하려고 합니다.

1개의 좋아요

답변감사합니다.
C++ 용인것은 맞습니다. 그렇다면 C#에서는 사용하지 못하는건가요? 다른 C++ DLL 을 사용하신 적은 없으신가요?

1개의 좋아요

답변감사합니다.

1개의 좋아요

답변 감사합니다.

1개의 좋아요

질문하신 해당 제조사 자료를 받아보니,
아래와 같더군요.

함수를 노출시킨 것이 아니라, Class를 노출 시켜놓았습니다.
제가 답변드리기에는 내공이 많이 딸립니다.

검색을 해보니 이럴 경우 작업이 많이 필요하더군요.
내공 높으신 분이 답변이 가능한 듯 합니다.

Stupid님 말씀처럼 해당 제품에는 USB를 사용하기 위해서 ftdichip사 제품을 사용한 것으로 보이며,
이 chip과 인터페이스 하기위해서는 Virtual Com Port(VCP) 또는 Direct Interface 방법을 사용할 수 있습니다.
VCP를 사용할 경우에는 일반 시리얼 포트처럼 사용하시면 되지만, 통신 속도가 제한되어 있고
Direct Interface를 사용하기 위해서 보셔야 할 문서가 많습니다.

더 도움을 드리지 못해 죄송합니다. 나이많은 헌 초보자(?)라서요^^

#ifndef _CANPRO_H_

#define _CANPRO_H_

#include<windows.h>

#include<stdio.h>

#include<mmsystem.h>

#include "ftd2xx.h"

   

#define DEVICE_DESCRIPTION      "CANPro Analyzer"

#define FRAME_SIZE              12800

#define START_CHAR              ':'

#define ERROR_CHAR              '?'

#define END_CHAR                0x0d

typedef enum

{

    CAN20A  = 0,

    CAN20B  = 1,

    CAN20AB = 2

}ENUM_CAN_MODE;

typedef enum

{

    CAN_DATA_FRAME      = 0,

    CAN_REMOTE_FRAME    = 1

}ENUM_CAN_DATA_TYPE;

typedef enum

{

    RECEIVE_OK  = 0,

    CAN_ERROR   = 1,

    USB_ERROR   = 2

}ENUM_RECV;

typedef enum

{

    TX_WARNING          = 0,

    RX_WARNING          = 1,

    TX_ERROR_PASSIVE    = 2,

    RX_ERROR_PASSIVE    = 3,

    BUSOFF_ERROR        = 4

}ENUM_ERROR;

typedef enum

{

    READ_RECV_ENV   = 0,

    STOP_RECV_ENV   = 1,

    START_RECV_ENV  = 2

}ENUM_RECV_ENV;

typedef struct

{

    BYTE    MessageMode;        // 0 : CAN2.0A / 1 : CAN2.0B / 2 : CAN2.0A + CAN2.0B

    BOOL    BusOFFtoReset;      // 1 : CAN Bus-Off발생 시 자동으로 CAN Reset 함

    BOOL    BusOFFtoError;      // 1 : CAN Bus-Off발생 시 에러 정보를 알림

    BOOL    PassiveError;       // 1 : CAN 송,수신 Erorr-Passive발생 시 정보를 알림

    BOOL    WarningError;       // 1 : CAN 송,수신 Warning발생 시 정보를 알림

    WORD    BitTime;            // Bit Time

    DWORD   ID;                 // 수신 ID

    DWORD   Mask;               // 수신 Mask

}STRUCT_CAN_ENV;

typedef struct

{

    BOOL    MessageMode;        // 0 : CAN2.0A, 1 : CAN2.0B

    BOOL    MessageType;        // 0 : Data Frame, 1 : Remote Frame

    int     DataSize;           // 데이터 사이즈 : 0 ~ 8

    DWORD   ID;                 // ID

    BYTE    Data[8];            // Data

}STRUCT_CAN_DATA;

// CANPro Library Class

class __declspec(dllexport) CCANPro

{

public:

    CCANPro();

    BOOL    InitPort(char *DeviceSerial);                   // 인자로 받은 시리얼 넘버로 연결

    void    ClosePort();                                    // 연결 종료

    void    SetMessage(HWND *pParent, UINT nMessage);       // 데이터받을때 통지할 유저메시지 설정, pParent가 NULL이면 메시지 보내지 않음

    void    SetBuffer(STRUCT_CAN_DATA *stRecvData);         // 데이터받을때 데이터를 넣어둘 구조체버퍼

    void    PurgePort();                                    // USB 버퍼 초기화

    // 2013. 8. 27

    void    SetTimeout(int nMsec);                          // 응답 대기 시간 설정 ( 1 ~ 1000 msec )

    // 2012. 6. 28

    // Message방식이 아닌 Callback방식으로 CAN데이터수시 할 때 사용

    void    SetCallbackFunction( void (*pFunction)( BYTE nReceiveType, BYTE nErrorType ) );

    BOOL    GetDeviceNum(int *nNum);                        // 현재 연결돼있는 CANPro장비 갯수파악

    BOOL    GetDeviceSerial(char **Buff);                   // 현재 연결돼있는 CANPro장비 시리얼번호 얻기(시리얼번호는 8byte)

                           

    BOOL    SendData(char* szData);                         // CANPro에 가공없이 보냄

    BOOL    ReadData(char* szData, int nTimeout);           // CANPro에 가공없이 읽어옴, Timeout만큼 기다린다.

    BOOL    WriteEnv(STRUCT_CAN_ENV *stData);               // 환경설정을 쓰는 함수

    BOOL    ReadEnv(STRUCT_CAN_ENV *stData);                // 환경설정을 읽는 함수

    BOOL    WriteData(STRUCT_CAN_DATA *stData);             // 데이터를 쓰는 함수

    BOOL    RecvEnv(int nCommand, BOOL *bStatus);           // 수신설정 함수(수신중인가, 수신시작, 수신정지)

    BOOL    Reset();                                        // CANPro Reset

    BOOL    GetVersion(int *nMajor, int *nMinor);           // CANPro Firmware 버전 정보 얻기

protected:

    HMODULE     m_hModule;

    FT_HANDLE   m_hUSB;

    BOOL        m_bLoadDriver;

    char        m_szSerial[10];

    HANDLE      m_hThread;

    char        m_szThreadRxBuff[FRAME_SIZE];

    int         m_nThreadRxBuffLen;

    char        m_szThreadTxBuff[FRAME_SIZE];

    int         m_nThreadTxBuffLen;

    HANDLE      m_hShutdownEvent;

    HANDLE      m_hReadEvent;

    HANDLE      m_hWriteEvent;

    HANDLE      m_hEventArray[3];

    BOOL        m_bRecvResponse;

    STRUCT_CAN_DATA *m_stRecvData;

    HWND*       m_pParent;

    UINT        m_Message;

    int         m_nTimeout;

    // CANPro 데이터수신 또는 에러발생시 호출될 콜백함수형식

    // bError - 0 : 정상데이터, 1 : 에러

    // nErrorType - ENUM_ERROR에 나열되어있는 에러중 한개

    void        (*m_pCallback)( BYTE nReceiveType, BYTE nErrorType );

    void        SendApplication( BYTE nReceiveType, BYTE nErrorType );

    void        UnloadDriver();

    void        LoadDriver();

    BOOL        MakeThread();

    BOOL        DestroyThread();

    static UINT USBThread(LPVOID pParam);

    void        RecvData();

    int         MakeCheckSum(char* szData);

};
3개의 좋아요

참고가 되실지는 모르겠지만.

4개의 좋아요

훌륭한 답변에 부연을 하자면,

C++ 라이브러리를 COM 라이브러리가 아닌이상 바로 .NET에서 쓸 수 있는 방법은 없습니다. .NET에서 클래스의 정의를 알 수 없기 때문인데요,

누군가가 C++/CLI를 이용해 .NET 래핑 라이브러리를 만들던가, 저 라이브러리를 이용해 C 함수로 export 하는 C 래핑 라이브러리를 만들어야 합니다. 사용자 입장에서는 어려울 수 있는 부분이라 아마 가장 빠른 방법은 리얼시스에 해당 라이브러리의 .NET 래퍼 라이브러리가 있는지를 문의 주시는게 빠를 수 있습니다.

이와 별개로 라이브러리의 소스코드가 있어서 컴파일 할 수 있는 환경에서 사용할 수 있는 SWIG라는 도구가 있어서 소개도 해봅니다.

https://www.swig.org/

그리고 SWIG를 이용해서 .NET 6에서 C++ 라이브러리를 래핑하는 방법을 보여주는 글도 소개합니다.

3개의 좋아요

답변 감사합니다. 래핑 라이브러리 만드는 쪽으로 생각해 봐야겠네요

1개의 좋아요

답변 감사합니다.

1개의 좋아요

안녕하세요 쪽지를 보낼 줄 몰라 이렇게 글을 씁니다.
알려주신대로 래핑 클래스 DLL 을 만들어 윈폼에서 출력하도록 시도했습니다.
분명 컴파일에서는 문제가 없는데 디버그 모드 실행시
“파일이나 어셈블리 ‘WrapperDLL.dll’ 또는 여기에 종속되어 있는 파일이나 어셈블리 중 하나를 로드할 수 없습니다. 지정된 모듈을 찾을 수 없습니다.”
메시지가 출력 됩니다.
any cpu 라서 문제인가 싶어서 x86으로 변경해도 같은 메시지가 출력됩니다.
혹시 VC6 에서 컴파일한게 문제가 될 수도 있을까요?(리얼시스 LIB 가 VC6 에서 컴파일했다고 합니다.)
사용하는 VS 는 2022 입니다.
감사합니다.

1개의 좋아요

글쎼요. 구체적인 내용을 알 수 없어 (가령, WrapperDLL.dll 파일을 어떻게 테스트 하셨는지, x86/x64 중 어떤 것인지) 답을 드릴 수가 없습니다. 일단 Any CPU로 선택하시면 안되며 정확히 x86 또는 x64 타겟을 지정하셔야 합니다.

기존 리얼시스에서 제공하는 CANPro.dll이 다른 의존성이 있는지, 있다면 설치 또는 포함해야 합니다.

1개의 좋아요

디모이님 글에 덧붙혀서
혹시 ftd2xx.lib에 종속성이 있어 보이는데요, 이부분은 확인 해 보셨는지요?

1개의 좋아요

네 WrapperDLL.dll 프로젝트에서 #pragma comment(lib,“CANPro.lib”) #pragma comment(lib,“ftd2xx.lib”) 추가했으며 헤더 또한 인클루드 했습니다. 타켓은 x86 이며 테스트는 C# Console 프로그램에서 호출하는 것으로 했습니다…

1개의 좋아요