移植GCC应用程序时,Windows光标停留在IDC_应用程序上

移植GCC应用程序时,Windows光标停留在IDC_应用程序上,windows,gcc,cursor,Windows,Gcc,Cursor,我正在移植一个应用程序,它使用mingwgcc将启动程序存根移植到Windows 这里有一个最小的例子,我将作为参考来演示这个问题 #include <process.h> int main(int argc, char *argv[]) { chdir("C:\appdir"); spawnl(P_WAIT, "C:\appdir\app.exe", "C:\appdir\app.exe", NULL); return 0; } 运行launcher.e

我正在移植一个应用程序,它使用mingwgcc将启动程序存根移植到Windows

这里有一个最小的例子,我将作为参考来演示这个问题

#include <process.h>

int main(int argc, char *argv[])
{
    chdir("C:\appdir");
    spawnl(P_WAIT, "C:\appdir\app.exe", "C:\appdir\app.exe", NULL);
    return 0;
}
运行launcher.exe时,它会正确执行app.exe,然后等待其终止,然后再终止自身

这会产生意想不到的副作用,即在生成launch.exe后,Windows光标会进入arrow+沙漏模式约5秒钟

如果直接通过命令提示符或双击app.exe运行,则不会发生这种情况

我已经尝试将以下内容添加到上面的应用程序中,但没有成功,游标的行为仍与以前完全相同:

#include <windows.h>
SetCursor(LoadCursor(NULL, IDC_ARROW));
有趣的是,在命令提示符下运行launcher.exe而不是在资源管理器中双击,会使光标正常工作。也就是说,它只会闪烁到沙漏,并几乎立即恢复正常

如何抑制忙碌的光标?或者至少可靠地重新更改,而无需阻塞?

设置光标技巧将不起作用,因为当系统响应WM\u设置光标消息时,它将立即更改为IDC\u应用程序启动

Windows中的APPSTARTING光标或多或少记录在结构页面中,请参见STARTF_FORCEONFEEDBACK上的说明

在那里,它说您可以调用GetMessage来摆脱反馈光标,但您似乎已经知道了这一点。为什么你不想用它

关于从控制台窗口调用时的不同行为,这是有意义的。想象一下当程序输入空闲时:

如果程序是Windows程序:当第一个窗口创建并准备就绪时,调用GetMessage。 如果程序是控制台程序: 如果从双击运行:一旦创建控制台窗口。 如果从其他控制台运行:立即。 更新:尝试在main的开头添加以下内容:

PostMessage(0, 0, 0, 0);
MSG msg;
GetMessage(&msg, 0, 0, 0);
SetCursor技巧不起作用,因为它将立即更改为IDC_APPSTARTING,因为系统正在响应WM_SetCursor消息

Windows中的APPSTARTING光标或多或少记录在结构页面中,请参见STARTF_FORCEONFEEDBACK上的说明

在那里,它说您可以调用GetMessage来摆脱反馈光标,但您似乎已经知道了这一点。为什么你不想用它

关于从控制台窗口调用时的不同行为,这是有意义的。想象一下当程序输入空闲时:

如果程序是Windows程序:当第一个窗口创建并准备就绪时,调用GetMessage。 如果程序是控制台程序: 如果从双击运行:一旦创建控制台窗口。 如果从其他控制台运行:立即。 更新:尝试在main的开头添加以下内容:

PostMessage(0, 0, 0, 0);
MSG msg;
GetMessage(&msg, 0, 0, 0);

这很简单,罗德里戈为你指出了正确的方向

Windows显示此光标以指示应用程序正在启动,并在应用程序开始其消息循环时将其关闭。您的启动器应用程序从不启动消息循环,因此Windows从不关闭光标

因此,以下是您需要的:

#include <process.h>
#include <Windows.h>

void turn_off_the_starting_cursor()
{
  PostQuitMessage( 0 );

  MSG msg;
  BOOL bRet;
  while( (bRet = GetMessage( &msg, 0, 0, 0 )) != 0)
  { 
      if (bRet != -1)
      {
          TranslateMessage(&msg); 
          DispatchMessage(&msg); 
      }
  }
}

int main(int argc, char *argv[])
{
    turn_off_the_starting_cursor();

    chdir("C:\appdir");
    spawnl(P_WAIT, "C:\appdir\app.exe", "C:\appdir\app.exe", NULL);
    return 0;
}
这将向消息队列发布一条退出消息,然后运行循环,该循环将立即退出。Windows认为该应用程序已准备就绪

杰弗里
这很简单,罗德里戈为你指出了正确的方向

Windows显示此光标以指示应用程序正在启动,并在应用程序开始其消息循环时将其关闭。您的启动器应用程序从不启动消息循环,因此Windows从不关闭光标

因此,以下是您需要的:

#include <process.h>
#include <Windows.h>

void turn_off_the_starting_cursor()
{
  PostQuitMessage( 0 );

  MSG msg;
  BOOL bRet;
  while( (bRet = GetMessage( &msg, 0, 0, 0 )) != 0)
  { 
      if (bRet != -1)
      {
          TranslateMessage(&msg); 
          DispatchMessage(&msg); 
      }
  }
}

int main(int argc, char *argv[])
{
    turn_off_the_starting_cursor();

    chdir("C:\appdir");
    spawnl(P_WAIT, "C:\appdir\app.exe", "C:\appdir\app.exe", NULL);
    return 0;
}
这将向消息队列发布一条退出消息,然后运行循环,该循环将立即退出。Windows认为该应用程序已准备就绪

杰弗里
整个发射装置都在上面。没有创建窗口,也不应该生成控制台。GetMessage将引入不需要的阻塞行为。启动器本身充当主可执行文件的包装器。您可以通过在之前发布任何消息来避免在GetMessage中阻塞。请尝试我更新答案中的代码。整个启动器都张贴在上面。没有创建窗口,也不应该生成控制台。GetMessage将引入不需要的阻塞行为。启动器本身充当主可执行文件的包装器。您可以通过在之前发布任何消息来避免在GetMessage中阻塞。请尝试我更新答案中的代码。您的解决方案与rodrigo的效果相同,但要大得多。为什么会这样?那是因为他复制了一个完全标准的消息循环,但之前有一条发布的消息。PostQuitMessage将第一次调用GetMessage return FALSE,然后它将完成。@rodrigo:PostMessage0、0、0和PostQuitMessage0有什么优点或缺点吗?PostQuitMessageX与PostMessage0、WM_QUIT、x、0相同,后者又与PostThreadMessageGetCurrentThreadId、WM_QUIT、x、0相同。因为收到了消息
立即丢弃,不管你在里面放了什么:WM_QUIT,0,42,任何数字都可以。你的解决方案和rodrigo的效果一样,但要大得多。为什么会这样?那是因为他复制了一个完全标准的消息循环,但之前有一条发布的消息。PostQuitMessage将第一次调用GetMessage return FALSE,然后它将完成。@rodrigo:PostMessage0、0、0和PostQuitMessage0有什么优点或缺点吗?PostQuitMessageX与PostMessage0、WM_QUIT、x、0相同,后者又与PostThreadMessageGetCurrentThreadId、WM_QUIT、x、0相同。由于消息会被立即接收并丢弃,因此您在其中输入的内容并不重要:WM_QUIT,0,42,任何数字都可以。