Why does windows spawn process sometimes trigger error STATUS_SXS_ASSEMBLY_NOT_FOUND?

假如想象 提交于 2019-12-01 12:42:18

问题


So, I have a tiny fragment of C code running on a windows box, that reads:

/* invoke command */
impl->procHandle = _spawnve(_P_NOWAIT, command, vargs, env);
if (impl->procHandle == -1) {
  printf("Failed to invoke command: %s\n", strerror(errno));
  impl->busy = false;
}
printf("VICTORY\n");

I wrote some unit tests around this where my "command" was C:\windows\system32\ipconfig.exe and it works, no problem.

Tried to use it for an application launcher... doo doo. Failed with the helpful error:

The application failed to initialize properly (0xc0150004). 
Click on OK to terminate the application.

Ok... searching around I discovered that the error code is STATUS_SXS_ASSEMBLY_NOT_FOUND, and it happens when I try to launch notepad.exe as well. Missing assemblies?

Why is this happening?

How can I work around it?

I'm just guessing here, but I suspect it has something to do with needing the PATH variable to be set in the _spawnve(), but I dont know what it should be. I tried passing in the path, but that doesn't seem to help. Running this code:

int offset = 0;
while (vargs[offset] != NULL) {
  printf("vargs %d: %s\n", offset, vargs[offset]);
  ++offset;
}
offset = 0;
while (env[offset] != NULL) {
  printf("env %d: %s\n", offset, env[offset]);
  ++offset;
}

Yeilds:

vargs 0: C:\windows\system32\notepad.exe
env 0: PATH=c:\WINDOWS\system32

ie. I am passing in argv[0], and a path value; not other env variables or arguments.

Any ideas?

--

Edit:

So, it seems this error is occurring because the PATH is not correctly set when I invoke the command using _spawnve().

This is made obvious by invoking either _spawnv() or _spawnvpe(), both of which seem to work correctly.

However, that doesn't really help me, because I need to specify an additional PATH component for the application when it runs. Passing PATH=... into _spawnvpe() causes the same error, and obviously _spawnv is no used because it doesn't allow you to specify the PATH.

So really, the answer to this question is: Because the PATH variable is wrong.

...but I still have no idea what it should be. There seem to be no working examples of this that I can find anywhere. I'll accept any answer that links to an example of coding using _spawnve() or _spawnvpe() and passing the PATH variable into it (and working).

Edit #2:

Really. No, actually, this doesn't work. Here's an example of it not working. Forget linking to an example that works; just modify my example and post a diff that 1) passes in PATH and 2) runs without an error.

Nb. Want to see it work? change to _spawnv() or make the env value NULL and it runs just fine.

#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <errno.h>

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

  char *path_value;
  char buffer[4000];
  const char *env[2];
  const char *args[1];
  char *command;
  int result;
  intptr_t procHandle;

  path_value = getenv("PATH");
  sprintf(buffer, "PATH=%s", path_value);
  env[0] = buffer;
  env[1] = NULL;

  args[0] = NULL;

  int offset = 0;
  while (env[offset] != NULL) {
    printf("env %d: %s\n", offset, env[offset]);
    ++offset;
  }

  offset = 0;
  while (args[offset] != NULL) {
    printf("arg %d: %s\n", offset, args[offset]);
    ++offset;
  }

  command = "C:\\windows\\system32\\notepad.exe";

  procHandle = _spawnvpe(_P_NOWAIT, command, args, NULL);
  if (procHandle == -1) {
    printf("Failed to invoke command: %s\n", strerror(errno));
    exit(1);
  }

  _cwait(&result, procHandle, 0);
  if (result != 0)
    printf("Command exited with error code %d\n", result);
}

Output:

env 0: PATH=.;c:\Program Files\Common Files\Microsoft Shared\Windows Live;c:\WINDOWS\system32;c:\WINDOWS;c:\WINDOWS\System32\Wbem;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;c:\Program Files\CMake 2.8\bin;c:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;c:\Program Files\Common Files\Microsoft Shared\Windows Live
Command exited with error code -1072365564

回答1:


This is wrong:

const char *args[1];
args[0] = NULL;

you need

const char *args[2];
args[0] = "notepad";
args[1] = NULL;

Other than that, your example code works, at least when compiled with Visual Studio 2010. I've tested it on both Windows 7 and Windows XP, and it works. Notepad runs.

What compiler are you using?




回答2:


You are right, the second parameter to _spawnev() takes the name of the app to be executed inlcuding its full path.

To get around to know the path you could call the command processer cmd.exe and pass it along the name of the app to execute as a parameter to it using cmd.exe's option /C.

This works in all the cases where you could have started the application out of one of cmd.exe's command line windows.

cmd.exe knows the value of the environment variable PATH and used it to search through it for the app's path to start.

The path to cmd.exe itself could be read from the environment variable COMSPEC.

Update: For more on this issue (including examples) please read here.




回答3:


As specified here _spawn, _wspawn Functions, only the functions with a 'p' letter in the name implicitely use the PATH environment variable. The others don't.

So you need to do this:

char *args[] =  {"notepad.exe", NULL };
_spawnvpe(_P_NOWAIT, args[0], args, NULL);


来源:https://stackoverflow.com/questions/10969488/why-does-windows-spawn-process-sometimes-trigger-error-status-sxs-assembly-not-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!