You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

集成NI-IMAQ与WINAPI时Visual Studio子系统冲突问题咨询

NI-IMAQ与WinAPI子系统设置冲突问题及解决

问题描述

我尝试在NI-IMAQ相关功能中嵌入WINAPI逻辑,但遇到子系统设置冲突:NI-IMAQ要求Visual Studio的子系统设置为Console,WINAPI要求子系统设置为Windows,二者无法同时满足,请问有什么方法可以解决该问题?
子系统设置界面
现有int main()和int WINAPI WinMain()两个入口函数,分别独立运行均正常。但int main()的代码仅能在子系统设置为Console时运行,WinMain的代码仅能在子系统设置为Windows时运行,请问是否有方法可以将二者整合,还是二者本身存在冲突?

现有代码

int main()
{
  INTERFACE_ID interfaceID;
  SESSION_ID sessionID;
  unsigned int bitsPerPixel, plotFlag;
  if (imgInterfaceOpen("img0", &interfaceID) == IMG_ERR_GOOD) // "img0"是接口名,打开名为img0的接口
  {
    std::cout << "Interface is open" << std::endl;
    if (imgSessionOpen(interfaceID, &sessionID) == IMG_ERR_GOOD)
    {
        std::cout << "Session is open" << std::endl;
        // 2021年9月30日:尝试采集
        // 1. imgInterfaceOpen(已完成)
        // 2. imgSessionOpen(已完成)
        // 3. imgGrabSetup(已完成)
        // 4. imgSessionStartAcquisition(已完成)
        // 5. imgGrab(已完成)
        // 6. 用户自定义功能
        // 7. imgSessionStop Acquisition(已完成)
        // 8. imgClose(已完成)
        //3. imgGrabSetup
        imgGrabSetup(sessionID, TRUE); //手动调用imgSessionStartAcquisition启动采集
        //4. imgSessionStartAcquisition
        imgSessionStartAcquisition(sessionID);
        //5. imgGrab (sessionID, 缓冲区地址, uint32 waitForNext)
        imgGrab(sessionID, NULL, TRUE);
        // imgSessionSaveBufferEx将会话缓冲区保存为PNG格式
        imgSessionSaveBufferEx(sessionID, NULL, reinterpret_cast<Int8*>(const_cast<char*>("test.png")));
        std::cout << "Image saved" << std::endl;
        // 获取相机像素深度属性
        imgGetAttribute(sessionID, IMG_ATTR_BITSPERPIXEL, &bitsPerPixel); //获取像素深度并存入bitsPerPixel
        std::cout << "Get Attribute" << std::endl;
        // 根据像素深度bitsPerPixel定义plotFlag
        switch (bitsPerPixel)
        {
        case 10:
            plotFlag = IMGPLOT_MONO_10;
            break;
        case 12:
            plotFlag = IMGPLOT_MONO_12;
            break;
        case 14:
            plotFlag = IMGPLOT_MONO_14;
            break;
        case 16:
            plotFlag = IMGPLOT_MONO_16;
            break;
        case 24:
        case 32:
            // 假设24位相机为彩色相机
            // 该模式下即使相机是24位,采集板也会返回32位值
            plotFlag = IMGPLOT_COLOR_RGB32;
            break;
        default:
            plotFlag = IMGPLOT_MONO_8;
            break;
        }
        std::cout << "plotFlag obtained" << std::endl;
        //6. 调用imgPlot显示图像(1. GUIHNDL 窗口, 2. void* 缓冲区, 3. uInt32 缓冲区左偏移, 4. uInt32 缓冲区上偏移, 5. uInt32 x尺寸, 6. uInt32 y尺寸, 
        // 7. uInt32 x坐标, 8. uInt32 y坐标, 9. uInt32 标识位)
        //            1          2   3  4      5              6           7           8          9
        imgPlot2(ImaqSmplHwnd, NULL, 0, 0, AcqWinWidth, AcqWinHeight, CanvasLeft, CanvasTop, plotFlag);
        std::cout << "imgPlot2 done" << std::endl;
        //7. 停止采集会话
        imgSessionStopAcquisition(sessionID);
        std::cout << "Stop acquisition" << std::endl;
        imgClose(sessionID, FALSE); //调用imgClose关闭会话
        std::cout << "Session is closed" << std::endl;
    }
    imgClose(interfaceID, FALSE);   //调用imgClose关闭接口
    std::cout << "Interface is closed" << std::endl;
   }
}
////////////////////////////////////////////////////////
// 2. 窗口事件回调函数,第一个参数为窗口句柄
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam);
// 主函数
int WINAPI WinMain(HINSTANCE currentInstance, HINSTANCE previousInstance, LPSTR cmdLine, INT cmdCount) 
{
   // 1. 注册窗口类
   const char* CLASS_NAME = "myWin32WindowClass";
   WNDCLASS wc{};
   wc.hInstance = currentInstance;
   wc.lpszClassName = CLASS_NAME;
   wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
   wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
   wc.lpfnWndProc = WindowProcessMessages; //每个窗口需要自定义回调函数,系统在触发窗口事件(如关闭、点击)时调用该函数
   RegisterClass(&wc);
   // 3. 创建窗口
   CreateWindow(CLASS_NAME, "Win32 Tutorial",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,           // 窗口样式
    CW_USEDEFAULT, CW_USEDEFAULT,               // 窗口初始位置
    800, 600,                       // 窗口尺寸
    nullptr, nullptr, nullptr, nullptr);
   // 4. 窗口消息循环:所有图形应用都需要运行该循环直到应用关闭
   MSG msg{}; //空窗口消息,只要GetMessage返回TRUE就持续运行循环
   while (GetMessage(&msg, nullptr, 0, 0)) 
   {
       TranslateMessage(&msg);
       //return MessageBox(NULL, "hello, world", "caption", 0);
       DispatchMessage(&msg);
   }
return 0;
}
// 2. 窗口事件回调实现
LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM param, LPARAM lparam) 
{
   switch (msg) {
   case WM_DESTROY: //用户点击右上角关闭按钮
       PostQuitMessage(0);
       return 0;
   default:
       return DefWindowProc(hwnd, msg, param, lparam);
   }
}

解决方法

二者本身不存在本质冲突,有两种常用方案可以实现整合:

  • 方案一:保留Console子系统
    Console子系统完全支持调用所有WinAPI接口,不会限制窗口创建。你只需要删除WinMain入口,把窗口初始化、消息循环的逻辑全部移到main函数中即可,还能保留控制台输出,方便调试NI-IMAQ的采集流程。
    如果需要实现实时采集+窗口响应,把NI-IMAQ的采集逻辑放到单独的工作线程运行,主线程只负责处理窗口消息即可。
  • 方案二:保留Windows子系统
    如果不想要控制台黑框,就把子系统设置为Windows,入口用WinMain,如果需要输出调试日志,可以主动调用WinAPI创建控制台:
// WinMain开头加入以下代码即可创建控制台,支持std::cout输出
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);

再把原来main函数中的NI-IMAQ逻辑移到WinMain中即可。
注意:不管选哪种方案,都只能保留一个入口函数,两个入口同时存在会导致编译错误。NI-IMAQ本身没有子系统依赖,你之前以为它只能在Console子系统运行,只是因为你用了std::cout输出,Windows子系统默认没有控制台看不到输出而已,加上面的手动开控制台代码即可解决。

内容的提问来源于stack exchange,提问作者Ong Shi Quan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 10:45:00