【问题标题】:Getting errors with CreateProcess in C using putenv and getpid使用 putenv 和 getpid 在 C 中使用 CreateProcess 出错
【发布时间】:2021-06-12 02:54:03
【问题描述】:

我遇到了这些错误,但我到处寻找答案,但没有找到解决方案:

launcher.c:107:12: warning: implicit declaration of function 'putenv'
launcher.c:116:10: warning: passing argument 2 of 'CreateProcessA' makes pointer from integer without a cast
c:\cs30200\mingw32\bin\../lib/gcc/mingw32/4.5.1/../../../../include/winbase.h:1250:24: 
note: expected 'LPSTR' but argument is of type 'int'

我的错误出现在putenv()CreateProcess()。我知道putenv() 返回int,但我无法获得新的命令提示符来显示新的行标题。但是,我也遇到getpid() 在每个程序开始时给我相同的号码的问题。我之前有它工作过,现在我找不到它出错的地方。

#include <windows.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

void printError(char* functionName);
#define INFO_BUFFER_SIZE 32767
    
int main(void)
{
   int numInput;
   int x=1,y=1;
   static char *promptCmd = "PROMPT=Speak$sUp:$G";
   DWORD dwExitCode = 0;
       
   STARTUPINFO si;
   PROCESS_INFORMATION pi;
       
   pid_t pid;
   pid = getpid();
    
   STARTUPINFO suNW;
   PROCESS_INFORMATION piNW;
   suNW.cb = sizeof(suNW);
   suNW.lpReserved = NULL;
   suNW.dwFlags = 0;
   suNW.cbReserved2 = 0;
   suNW.lpReserved2 = NULL; 
   suNW.lpDesktop = NULL;
   suNW.lpTitle = "What is your command?";
   suNW.dwX = x;
   suNW.dwY = y;
   suNW.dwXSize = CW_USEDEFAULT;
   suNW.dwYSize = CW_USEDEFAULT;
   suNW.dwFillAttribute = FOREGROUND_INTENSITY| FOREGROUND_GREEN|FOREGROUND_RED|BACKGROUND_RED;
   suNW.dwFlags = STARTF_USEPOSITION|STARTF_USEFILLATTRIBUTE;
   suNW.wShowWindow = TRUE;
   suNW.hStdInput = NULL;
   suNW.hStdOutput = NULL;
   suNW.hStdError = NULL;
    
   HANDLE hProc;
   hProc = pi.hProcess;
   GetStartupInfo(&si);
    
   const size_t full_size=256;
   TCHAR  sysLoc[INFO_BUFFER_SIZE],lpCommandLine[5][INFO_BUFFER_SIZE];
   char * progLoc;
    
   GetSystemDirectory(sysLoc, INFO_BUFFER_SIZE);                  //Get location of System32 folder
   progLoc = getenv("ProgramFiles(x86)");                         //Get location of Program Files folder x64
   if (progLoc==NULL) progLoc = getenv("ProgramFiles");           //If running x86 get location of Program Files folder
     
   snprintf(lpCommandLine[1],full_size,"%s\\notepad.exe",sysLoc);
   snprintf(lpCommandLine[2],full_size,"%s\\cmd.exe",sysLoc);
   snprintf(lpCommandLine[3],full_size,"%s\\nslookup.exe",sysLoc);
   snprintf(lpCommandLine[4],full_size,"%s\\charmap.exe",sysLoc);
   snprintf(lpCommandLine[5],full_size,"%s\\Windows NT\\Accessories\\wordpad.exe",progLoc);
    
runProgram:
   printf("Which program would you like to run:\n");
   printf("0: Quit\n");
   printf("1: Run Notepad\n");
   printf("*2: Run cmd shell\n");
   printf("#3: Run NS LooKUp\n");
   printf("4: Run Character Map\n");
   printf("5: Run WordPad\n");
   printf("Enter your choice now: ");
   scanf("%d", &numInput);
       
   switch(numInput)
   {
       case 0:
          
           exit(0);
             
       case 1:
            
           if(TRUE==CreateProcessA(NULL,lpCommandLine[1], NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
           {
               printf("Started program 1 with pid = %i",getpid());//pid);
           }  
           else printError(lpCommandLine[1]);
             
           printf("\n\n");
           goto runProgram;
           break;
             
       case 2:
             
           if (CreateProcess(
               lpCommandLine[2],         // LPCTSTR lpApplicationName
               promptCmd,//putenv(promptCmd),               // LPTSTR lpCommandLine
               NULL,                // LPSECURITY_ATTRIBUTES lpProcessAttributes
               NULL,                // LPSECURITY_ATTRIBUTES lpThreadAttributes
               FALSE,//TRUE,               // BOOL bInheritHandles
               CREATE_NEW_CONSOLE,    // DWORD dwCreationFlags
               NULL,                // LPVOID lpEnvironment
               NULL,                // LPCTSTR lpCurrentDirectory
               &suNW,       // LPSTARTUPINFO lpStartupInfo
               &piNW        // LPPROCESS_INFORMATION lpProcessInformation
           ))
           {
               printf("Started program 2 with pid = %i \n",getpid());//pid);
               printf("  waiting for program 2 to terminate...\n");

               WaitForSingleObject(piNW.hProcess,INFINITE);
               CloseHandle(piNW.hThread);

               GetExitCodeProcess(piNW.hProcess,&dwExitCode);                  

               CloseHandle(piNW.hProcess);   
           }  
           else printError(lpCommandLine[2]);
             
           printf("  program 2 exited with a return value %i\n", dwExitCode);
           printf("\n\n");
           goto runProgram;
           break;     
          
       case 3:
           if(CreateProcessA(NULL, lpCommandLine[3], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ 
               printf("Started program 3 with pid = %i \n",getpid());//pid);
               WaitForSingleObject(pi.hProcess,INFINITE);
               CloseHandle(pi.hThread);
               CloseHandle(pi.hProcess);    
               goto runProgram;
           }  
           else printError(lpCommandLine[3]);
             
           printf("\n");
           goto runProgram;
           break;     
          
       case 4:
           if(CreateProcessA(NULL,lpCommandLine[4], NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
           { 
               printf("Started program 4 with pid = %i \n",getpid());//pid);
               CloseHandle(pi.hThread);
               CloseHandle(pi.hProcess); 
           }
           else printError(lpCommandLine[4]);
                
           printf("\n\n"); 
           goto runProgram;
           break;     
          
       case 5:
           if(CreateProcessA(NULL,lpCommandLine[5], NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
           { 
               printf("Started program 5 with pid = %i \n",getpid());//pid);
               CloseHandle(pi.hThread);
               CloseHandle(pi.hProcess); 
           }
           else printError(lpCommandLine[5]);
                
           printf("\n\n");
           goto runProgram;
           break;
   }
       
   return 0;
}
    
/****************************************************************
 The following function can be used to print out "meaningful"
 error messages. If you call a Win32 function and it returns
 with an error condition, then call this function right away and
 pass it a string containing the name of the Win32 function that
 failed. This function will print out a reasonable text message
 explaining the error and then (if chosen) terminate the program.
*/
void printError(char* functionName)
{
   LPVOID lpMsgBuf;
   int error_no;
   error_no = GetLastError();
   FormatMessage(
       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
       NULL,
       error_no,
       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
       (LPTSTR) &lpMsgBuf,
       0,
       NULL
   );
   // Display the string.
   fprintf(stderr, "\n%s failed on error %d: ", functionName, error_no);
   fprintf(stderr, (char*)lpMsgBuf);
   // Free the buffer.
   LocalFree( lpMsgBuf );
   //ExitProcess(1);  // terminate the program
}//printError

【问题讨论】:

  • 你为什么使用goto
  • 附带说明:数组是 0 索引的,因此在填充具有 5 个元素的 lpCommandLine[] 数组时会超出范围,因此它的有效索引是 0..4,而不是1..5。写入lpCommandLine[5] 会损坏内存。
  • 是的,我改为转到 while 循环,我试图找出什么不起作用。我什至没有意识到我开始时索引是 1 而不是 0。谢谢

标签: c windows winapi createprocess


【解决方案1】:

getpid 返回调用进程的进程ID。新创建进程的进程 ID 通过lpProcessInformation 参数返回,在dwProcessId 字段中。因此,不要调用getpid,而是按如下方式更改您的代码:

printf("Started program 1 with pid = %i", pi.dwProcessId);

至于putenv,它也修改了调用进程的环境。在 Windows 上,它也只更改 CRT 的环境副本,而不是真正的进程环境。要更改过程环境,您应使用SetEnvironmentVariable。只要将CreateProcesslpEnvironment设置为NULL,子进程就会继承父进程环境。

综上所述,实现您想要的最简单的方法是在程序开始时在您的进程中设置PROMPT=... 环境:

SetEnvironmentVariableA("PROMPT", "Speak$sUp:$G");

然后让孩子们通过在CreateProcess中不做任何特别的事情来继承它。

【讨论】:

  • 附带说明,dwProcessId 是一个DWORD (unsigned long),因此对printf() 的调用应该使用%lu 而不是%i。另外,在不改变父环境的情况下设置子环境的另一种方法是将CreateProcessA()lpEnvironment 参数设置为非NULL 字符串指针,例如:CreateProcessA(NULL, lpCommandLine[...], ..., promptCmd, ...)
  • @RemyLebeau:是的,我提出了“最简单的方法”,因为构建 lpEnvironment 对于 OP 的技能水平可能过于复杂。
  • @Jon:你真的不应该那样做。你很幸运,因为 (1) lpEnvironment 需要以两个零字节结束,而不是 C 字符串中的一个字节,并且 (2) 这会清除进程可能需要的所有其他环境变量(如 TMPDIRWINDIRPATH 等...)。考虑到您使用它来启动cmd.exe,如果没有设置PATH,它将是一个相当无用的终端。
  • Yakov: 设置 SetEnvironmentVariableA("PROMPT", "Speak$sUp:$G");在代码的开头工作。我前段时间尝试过,但在我使用 CreateProcess 之前和之后都试过了。
  • @Jon: 在CreateProcess 之前应该也可以工作。也许你把它放在错误的前面;)
猜你喜欢
  • 2019-06-14
  • 1970-01-01
  • 2022-01-09
  • 2011-04-10
  • 2016-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
相关资源
最近更新 更多