集成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
相关产品推荐
相关产品推荐

