用户可定义函数不适用于 Visual Studio,但适用于 GCC

问题描述 投票:0回答:1

尝试获取用户可定义的函数而不是 API 库中的函数。这在 Linux GCC 中没有问题,但无法弄清楚在 Visual Studio 中该怎么做。该库是一个 .dll,并且 Linux 中 .so 上的所有内容都相同。

标题:

        typedef struct _usb_can_packet_ {
        uint8_t             size;
        uint8_t             cmd;
        uint8_t             port;
        uint8_t             misc;
        uint32_t            extendedStatus;
        union {
            MCAN_OPEN           openInfo;
            MCAN_RX_PACKET      rxPacket;
            MCAN_TX_PACKET      txPacket;
            MCAN_TX_DONE        txEvent;
        } u;
    } VL_USB_CAN_XFER;

        void user_CANRxCallBackFunction(VL_USB_CAN_XFER* pRxPacket, int txStatus);

DLL:

        // User Defined function called when a packet is recieved.
void user_CANRxCallBackFunction(VL_USB_CAN_XFER* pRxPacket, int status)
{
    /* ***** Declarations. ***** */
    /* ************************* */

    /* ***** Initializations. ***** */
    /* **************************** */

    /* ***** Construct the packet. ***** */
    if (gCallBackInfo.rxFlag)
    {
        if (gAPIDebugLevel >= VL_DEBUG_1)
        {
            printf("Entering user_CANRxCallBackFunction() with an event\n");
        }

        gCallBackInfo.rxFlag = 1;  // Reset the flag for next packet.

        if (gAPIDebugLevel >= VL_DEBUG_1)
            printf("Leaving user_CANRxCallBackFunction()\n");
    }

    /* ********************************* */
}


void rxCallBack(struct libusb_transfer* pXfer)
{
    /* ***** Declarations. ***** */
    VL_USB_CAN_XFER* pRxPacket;
    /* ************************* */

    // We are here.
    if (gAPIDebugLevel >= VL_DEBUG_2)
        printf("Entering rxCallBack()\n");

    gRxPacketCount++;
    if (LIBUSB_TRANSFER_COMPLETED == pXfer->status)
    {
        if (gAPIDebugLevel >= VL_DEBUG_2)
        {
            printf("Status complete;\n");

            printf("  usb->flags=0x%x\n", pXfer->flags);
            printf("  usb->actual_length=0x%x\n", pXfer->actual_length);
        }

        gCallBackInfo.rxFlag = 1;
        gCallBackInfo.rxSts = (int)pXfer->flags;
        gCallBackInfo.rxLength = (int)pXfer->actual_length;
        memcpy(gCallBackInfo.pRxBuf, pXfer->buffer, pXfer->actual_length);
        gRxTimeOutCount = 0;

        // For ease of reference, create a CAN packet.
        pRxPacket = (VL_USB_CAN_XFER*)gCallBackInfo.pRxBuf;

        // Filter out certain packets.
        switch (pRxPacket->cmd)
        {
        case USB_CAN_CMD_OPEN:
        case USB_CAN_CMD_CLOSE:
        case USB_CAN_CMD_ID:
        case USB_CAN_CMD_MAX:
        case USB_CAN_CMD_UNDEFINED:
            break;  // Do nothing for these.
        case USB_CAN_CMD_TX:
            if (gAPIDebugLevel >= VL_DEBUG_2)
            {
                VSL_CANPrintPktHeader("rxCallBack():", pRxPacket);
            }
            break;
        case USB_CAN_CMD_STS:
            gCANPortStatus = pRxPacket->misc;
            break;
        case USB_CAN_CMD_MCU_FW_VER:
            gMCUFwReceived = pRxPacket->extendedStatus;
            break;
        case USB_CAN_CMD_MCU_REG_VAL:
            gMCURegValReceived = pRxPacket->extendedStatus;
            gMCURegId = pRxPacket->misc;
            if (gAPIDebugLevel >= VL_DEBUG_2)
            {
                printf("\trxCallBack(): reg 0x%d val = 0x%08x\n",
                    gMCURegId, gMCURegValReceived);
            }
            break;
        case USB_CAN_CMD_RX:
            if (gAPIDebugLevel >= VL_DEBUG_2)
            {
                VSL_CANPrintPktHeader("rxCallBack(): RX", pRxPacket);
                mydumpData((uint8_t*)&(pRxPacket->u.rxPacket.mcanRxData), 8);
            }
            break;
        default:
            break;
        }
    }
    else if (LIBUSB_TRANSFER_TIMED_OUT == pXfer->status) {
        if (gAPIDebugLevel >= VL_DEBUG_1)
        {
            if (gAPIDebugLevel >= VL_DEBUG_2)
                printf("Status timed_out;\n");
        }
        gRxTimeOutExit = true;
        gRxTimeOutCount++;
    }
    else if (LIBUSB_TRANSFER_CANCELLED == pXfer->status) {
        if (gAPIDebugLevel >= VL_DEBUG_2)
            printf("Status cancelled;\n");
        gRxCancelled = true;
        gRxTimeOutCount = 0;
    }
    else
    {
        if (gAPIDebugLevel >= VL_DEBUG_2)
            printf("UNKNOWN STATUS (%d);\n", pXfer->status);
    }

    // Call a user defined function.
    (void)user_CANRxCallBackFunction(pRxPacket, pXfer->status);

    libusb_submit_transfer(pXfer);

    if (gAPIDebugLevel >= VL_DEBUG_2)
        printf("Leaving rxCallBack(rxPacketCount=%d; rxTimeOutCount=%d);\n",
            gRxPacketCount, gRxTimeOutCount);

    return;
}

应用程序(主程序之外):

// User Defined function called when a packet is recieved.
        void user_CANRxCallBackFunction(VL_USB_CAN_XFER* pRxPacket, int txStatus)
        {
    /* ***** Declarations. ***** */
    /* ************************* */

    /* ***** Initializations. ***** */
    /* **************************** */

    /* ***** PROCESS. ***** */
    if (gAPIDebugLevel >= VL_DEBUG_2)
    {
        printf("Entering app userDefinedRxFunction(), txStatus=%d\n", txStatus);
    }

    if (txStatus == LIBUSB_TRANSFER_COMPLETED)
    {
        if (pRxPacket->cmd == USB_CAN_CMD_RX)
        {
            gCurRxPktCount++;
            gCurTxRxPktCount++;

            (void)VSL_CANPrintPktHeader("Packet Received:", pRxPacket);
            CANPrintPacket(pRxPacket);
        }
    }
    else
    {
        gFailedPktCount++;
    }
    /* ******************** */

    if (gAPIDebugLevel >= VL_DEBUG_2)
        printf("Leaving app userDefinedRxFunction()\n");

    return;
}

如何让 Visual Studio 优先考虑应用程序定义?

c++ c
1个回答
0
投票

Linux 动态链接器允许应用程序定义同名函数来覆盖共享对象中的函数,而 Windows 动态链接器不允许这样做。

需要修改 DLL 以允许此功能,C 方式是公开全局导出函数指针,并将其绑定到默认值,然后在主应用程序中覆盖它。

// in DLL
using func_type = void (*)(VL_USB_CAN_XFER* , int);
__declspec(dllexport) func_type user_CANRxCallBackFunction;
user_CANRxCallBackFunction = some_inital_function;

// in executable
__declspec(dllimport) func_type user_CANRxCallBackFunction;

// somewhere in main
user_CANRxCallBackFunction = some_new_function;

C++ 添加了很多东西使这段代码更加灵活,最大的变化是你可以使用 std::function 来代替保存任何可调用的,而不仅仅是函数指针,以及提供 OOP 接口而不是使用全局变量。

© www.soinside.com 2019 - 2024. All rights reserved.