在运行的 Windows 控制台应用程序中处理拖放文件

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

首先,澄清一下,我不是问如何将文件拖放到exe的图标上。我想知道如何处理拖放到“已经运行”的 win32 控制台应用程序上。我也不是询问如何通过 Windows 消息泵处理基于 WinMain 的应用程序内部的拖放操作。我想在一个程序内部执行此操作,其入口点 int main() 还没有 WndProc 或任何东西。 也就是说,我想知道我的目标是否可以实现(并希望如此)。

我有一个在控制台窗口中运行的服务器应用程序。由于庞大的代码库和许多奇怪的耦合,它是一个用于所有密集用途的“仅输出”控制台。不过,在其中,我仍然可以处理按键之类的事情,因为我有一个更新循环滴答作响。我希望能够将充满命令(使用自定义语法)的文件拖放到正在运行的应用程序上并让它处理它们。

这可以做到吗?我在想,我可能可以获得一个指向控制台 HWND 的指针(希望这是一个东西?),然后也许对该窗口进行子类化,以使用自定义 WndProc 来侦听 WM_DROPFILES 消息。

我从未真正尝试过在

int main()

程序而不是 WinMain 程序中设置 Windows 消息的处理,但我希望它在某种程度上是可能的。 任何帮助将不胜感激!

奇怪的解决方案也很好。

c++ winapi drag-and-drop console-application
3个回答
6
投票

要在控制台窗口本身上使用拖放功能,请尝试使用

GetConsoleWindow()

 获取控制台 HWND,然后:

    使用
  1. SetWindowLong/Ptr()

    SetWindowSubClass()
     对 HWND 进行子类化,然后使用 
    DragAcceptFiles()
     注册 HWND 以开始接收 
    WM_DROPFILES
    消息。请务必再次调用
    DragAcceptFiles()
    以停止接收消息,然后在退出应用程序之前取消挂钩您的子类。
    
    

  2. 实现
  3. IDropTarget

    接口,然后使用
    RegisterDragDrop()
    注册HWND以开始接收通知。退出应用程序之前,请务必致电 
    RevokeDragDrop()

WM_DROPFILES

更容易编码,但

IDropTarget
更灵活,因为它可以处理虚拟项目和物理文件。
    


2
投票


0
投票

/* This is the final work which shows whether it is possible or not to track messages sent to the command window. All tests have shown that this is not possible. 15-04-2024 */ #include <windows.h> LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam); char textString[] = "Click this area to create a Console Window"; HWND hConsoleWindow = (HWND)1; // needs to be global HANDLE ohandle, ihandle; // needs to be global LPDWORD lpThreadId; // needs to be global (!) int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow) { HWND hWnd; MSG lpMsg; WNDCLASS wndclss; TCHAR szBuffer[2056]; if(!hPrevInst) { wndclss.lpszClassName = "Console Message Test"; wndclss.hInstance = hInst; wndclss.lpfnWndProc = WndProc; wndclss.hCursor = LoadCursor(NULL, IDC_ARROW); wndclss.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclss.lpszMenuName = NULL; wndclss.hbrBackground = GetStockObject(WHITE_BRUSH); wndclss.style = 0; wndclss.cbClsExtra = 0; wndclss.cbWndExtra = 0; if(!RegisterClass(&wndclss)) return FALSE; } hWnd = CreateWindow("Console Message Test", "Console Message Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, hInst, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while(GetMessage(&lpMsg, NULL, 0, 0)) // This is the message loop { TranslateMessage(&lpMsg); //hConsoleWindow = FindWindow("ConsoleWindowClass", NULL); // activate this line facultatively, as a test. Might have an effect if no other conole window is open. /* the above line will terminate the program if no console is present. All this means is that a NULL was returned. */ if(lpMsg.hwnd == hConsoleWindow) return( lpMsg.wParam); /* (the above line) if any message reaches the console window through this loop, the program closes! */ //if(lpMsg.message == WM_DROPFILES) return( lpMsg.wParam); // activate this line facultatively (as a test) /* the above line will make the program close if a file is dropped into the white area */ DispatchMessage(&lpMsg); } return(lpMsg.wParam); } DWORD WINAPI ConsoleThread(LPVOID Param) { DWORD dwCount, dwMsgLen; TCHAR szBuffer[2056]; for(;;){ ReadConsole(ihandle, szBuffer, sizeof(szBuffer) - 2, &dwCount, NULL); WriteConsole(ohandle, "You typed: ", 11, &dwMsgLen, NULL); WriteConsole(ohandle, szBuffer, dwCount, &dwMsgLen, NULL); } } // Main Window Procedure LRESULT CALLBACK WndProc(HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT pstruct; static HANDLE hThread = NULL; switch(messg) { case WM_PAINT: hdc = BeginPaint(hWnd, &pstruct); TextOut(hdc, 0, 0, textString, (sizeof(textString) - 1)); EndPaint(hWnd, &pstruct); break; case WM_LBUTTONDOWN: AllocConsole(); hConsoleWindow = FindWindow("ConsoleWindowClass", NULL); if(hConsoleWindow) Beep(1000, 250); // high note when console detected //DragAcceptFiles(hConsoleWindow, TRUE); // this line seems to have no effect DragAcceptFiles(hWnd,TRUE); /* this line makes the white area accept dragged objects once it is clicked */ if(hThread == NULL) { ohandle = GetStdHandle(STD_OUTPUT_HANDLE); ihandle = GetStdHandle(STD_INPUT_HANDLE); hThread = CreateThread(NULL, 0, ConsoleThread, NULL, 0, lpThreadId); } break; case WM_DESTROY: PostQuitMessage(0); break; case WM_DROPFILES: Beep(500, 250); // low note when file drop detected break; default: return(DefWindowProc(hWnd, messg, wParam, lParam)); } return(0); }

PS 我把OP指的是XP/Windows Server 2003时代的Windows操作系统的命令行。后来的 Windows 操作系统有所不同(即在控制台程序中默认接受删除的多个项目。)

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