尝试获取用户可定义的函数而不是 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 优先考虑应用程序定义?
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 接口而不是使用全局变量。