VC中用ShellExecute等函数执行exe出现错误,但是鼠标双击就可以,这是为啥?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC中用ShellExecute等函数执行exe出现错误,但是鼠标双击就可以,这是为啥?相关的知识,希望对你有一定的参考价值。

代码:
hRet = ShellExecute(NULL,"open",C:\\APPLIC\\LCTLEX3\\LctLex3.exe",NULL,NULL,SW_SHOWDEFAULT);
执行后先弹出上面的图二错误信息,点确定后会出现LctLex3进程,如下图

但是窗口是非正常显示,没有正确执行,什么都没显示,如下图。

也试过其他函数,ShellExecuteEx,CreateProcess和WinExec都没有成功。非常困惑,用鼠标双击LctLex3.exe,是可以正常执行的,用CMD命令也可以正常执行的,实在找不出啥原因,请帮忙解答,非常感谢!

初步判断是调用ShellExecute这个函数时没有指定缺省目录。请参考该Api参数意义,并将缺省目录指定为exe文件所在目录。追问

之前的代码:

ShellExecute(NULL,"open","C:\\APPLIC\\LCTLEX3\\LctLex3.exe",NULL,NULL,SW_SHOWDEFAULT);
改完之后的代码:

ShellExecute(NULL,"open","C:\\APPLIC\\LCTLEX3\\LctLex3.exe",NULL,"C:\\APPLIC\\LCTLEX3",SW_SHOWDEFAULT);
改完之后确实可以执行了。
不过还不明白缺省目录的作用是干什么用的
已经非常感谢了!

追答

是这样,你要执行的程序肯定使用了loadpicture这类函数运行时载入了这个bmp文件,由于载入bmp使用了相对路径,它将搜索他的缺省路径下有没有这个bmp文件。双击打开的话系统将指定缺省路径为exe文件所在路径,而使用shellexecute打开,如果你不指定缺省路径,函数将于内部指定缺省路径为你编写这个程序的缺省路径,而这个路径下是没有这个bmp的,所以打不开。

参考技术A ShellExecute打开非程序文件,一些参数必须是指定设置,否则打不开。
如:
Parameters: PChar; //给要打开的程序指定参数; 如果打开的是文件这里必须是 null
更多设定参考帮助文档。

MFC 打开外部EXE文件的三种方法

目前知道三种方式:WinExec,ShellExecute ,CreateProcess,别人已经总结的很好了《vc中调用其他应用程序的方法(函数) winexec,shellexecute ,createprocess》,我全文转载一下,另外后面加点自己的总结(黑体部分,除了标题)。 
  三个SDK函数: WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。 
  WinExec 两个参数,前一个指定路径,后一个指定显示方式。 
  ShellExecute 可以指定工作目录,并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序,ShellExecute还可以打开网页,启动相应的邮件关联发送邮件等等。 
  CreateProcess  一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性,若要达到这些目的,我们就需要使用CreateProcess函数了。  
  三个SDK函数( WinExec、ShellExec、CrateProcess )的语法:  
  (一)WinExec  
  这个函数最简单,只有两个参数,原型如下:  
  UINT WinExec(  
  LPCSTR lpCmdLine,   // 命令路径  
  UINT uCmdShow      // 显示方式  
  );  
  使用方法如下:  
  WinExec("Notepad.exe", SW_SHOW);  // 打开记事本  
  WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED); // 以最大化的方式打开Test.exe  
  需要注意的是若用 SW_SHOWMAXMIZED 方式去加载一个无最大化按钮的程序,譬如Neterm,Calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。 
  这个函数只能打开exe文件。  
  需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。 
  msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms687 393[/url](VS.85).aspx  
  (二)ShellExecute  
  原型如下:  
  HINSTANCE ShellExecute(  
  HWND hwnd,           //父窗口句柄  
  LPCTSTR lpOperation,   //操作, 打开方式 "edit","explore","open","find","print","NULL"  
  LPCTSTR lpFile,         //文件名,前面可加路径  
  LPCTSTR lpParameters,   //参数  
  LPCTSTR lpDirectory,    //默认文件夹  
  INT nShowCmd          //显示方式  
  );  
  使用方法如下:  
  ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL, SW_SHOWNORMAL); // 打开C:\Test.txt 文件  
  ShellExecute(NULL, "open", "http://www.google.com/",  NULL, NULL, SW_SHOWNORMAL); // 打开网页www.google.com  
  ShellExecute(NULL,"explore", "D:\\C++",NULL,NULL,SW_SHOWNORMAL); // 打开目录D:\C++  
  ShellExecute(NULL,"print","C:\\Test.txt",NULL,NULL , SW_HIDE); // 打印文件C:\Test.txt  
  ShellExecute不支持定向输出。 
  这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。 
  需要的头文件:windows.h,shellapi.h(前者是我试验出来的,后者是msdn说需要的)。另外这两者的先后顺序不能变。 
  msdn上说明:[url]http://msdn.microsoft.com/en-us/library/bb762 153[/url](VS.85).aspx  
  (三)CreateProcess  
  原型如下:  
  BOOL CreateProcess(  
  LPCTSTR lpApplicationName, //执行程序名  
  LPTSTR lpCommandLine,  // 参数行  
  //下面两个参数描述了所创建的进程和线程的安全属性,如果为NULL则使用默认的安全属性  
  LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes  
  LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes  
  BOOL bInheritHandles,  // 继承标志  
  DWORD dwCreationFlags, // 创建标志  
  LPVOID lpEnvironment,  // 环境变量  
  LPCTSTR lpCurrentDirectory,   // 运行该进程的初始目录  
  LPSTARTUPINFO lpStartupInfo,  // 用于在创建子进程时设置各种属性  
  LPPROCESS_INFORMATION lpProcessInformation //用于在进程创建后接受相关信息  
  );  
  使用方法如下:  
  PROCESS_INFORMATION pi;  
  STARTUPINFO si;  
  memset(&si,0,sizeof(si));  
  si.cb=sizeof(si);  
  si.wShowWindow=SW_SHOW;  
  si.dwFlags=STARTF_USESHOWWINDOW;  
  bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi); 
  这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。 
  需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。 
  msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms682 425[/url](VS.85).aspx 
  可以看出,通过上面的几个不同的方法,都可以实现在应用程序中打开其他应用程序的目的,其中有些方法可能会麻烦一点,所以就需要我们根据不同的目的去选择最适合自己的方法去实现自己的目的!  
  关于三个SDK函数: WinExec, ShellExecute,CreateProcess 的其他注意事项:  
  1、定义头文件  
  原作者的内容删去。 
  这个是引用新函数都必须注意的内容。但是MS的头文件引用顺序有点怪,比如上面的三种清理。另外,如果用了预编译,那么记得在任何源程序中的#include "stdafx.h"之前的引用都会失效,从其后才生效。(不可否认,预编译有他的好处,尤其当程序很大的时候,但是任何好处都是要付出代价的) 
  2、定义路径  
  C++中所表示的路径要用 " \\ "而不是平常所用的" \ ",所以以上三个函数表示路径都为:  
  Disk:\\Directory\\...\\File name  
  WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED);  
  ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL, SW_SHOWNORMAL);  
  bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi) 
  3、注意文件的路径 
  在程序a调用程序b的时候,b原来的默认的当前路径都会变成a的当前路径。所以,一定要注意。 
  可以养成使用绝对路径的习惯,另外,记得打开文件之类的操作,一定要验证是否有错。 
  VC++6.0  
  Win95  
  如何在VC++中调用外部的DOS程序?它的函数是什么?如果用API,它的函数是什么?  
  回答:  
  你可以使用Windows API函数WinExec、ShellExecute。这两个函数可以调用Windows和DOS程序。WinExec主要运行EXE文件。如:  
  WinExec("Notepad.exe Readme.txt", SW_SHOW);  
  ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。如:  
  ShellExecute(0, "open", "http://askpro.yeah.net", NULL, NULL, 0);  
  另外,参考QA000583 "外调一个DOS程序,但是又不想显示其产生的窗口"。  
  Vc 5.0  
  Windows 95  
  我正在编写一个程序,想外调一个现成的Com,但是又不想显示其产生的窗口,我试过可以关闭该窗口,一样能运行,可是在我的程序中如何获取该窗口句柄,如何自动关闭它?(飞飞)   
  其实使用ShellExecute调用DOS程序时可以不显示窗口,如:  
  ShellExecute(0, "open", "c:\\tools\\arj.exe", "a c:\\p.arj c:\\*.bat c:\\*.sys", NULL, SW_HIDE);  
  对于你的问题,你可以使用FindWindow获得句柄,但关掉窗口就不能再继续执行了。而你说的关闭窗口还能执行,大概是因为在你关闭窗口时已经运行结束了。   
  #include "stdafx.h" 
  #include  
  #include //ShellExecute 要引用的库 
  int main(int argc, _TCHAR* argv[]) 
  {     
  ShellExecute(NULL,NULL,_T("E:\\Projekt1.exe"),NULL ,NULL,SW_SHOW); 
  getchar(); 
  return 0; 
  } 
  #include "stdafx.h" 
  #include   
  #include   
  #include  
  DWORD WINAPI ThreadWork(LPVOID num) 
  { 
  printf("%d\n",num); 
  return 0; 
  } 
  int _tmain(int argc, _TCHAR* argv[]) 
  { 
  DWORD dwThreadID[5];  
  HANDLE threadhandle=CreateThread(NULL, 
  0, 
  ThreadWork, 
  (LPVOID)2,//传递的参数 
  0, 
  &dwThreadID[0]); 
  getchar();  
  return 0; 
  } 

http://blog.csdn.net/samdy1990/article/details/16919969

目前知道三种方式:WinExec,ShellExecute ,CreateProcess,别人已经总结的很好了《vc中调用其他应用程序的方法(函数) winexec,shellexecute ,createprocess》,我全文转载一下,另外后面加点自己的总结(黑体部分,除了标题)。 
  三个SDK函数: WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。 
  WinExec 两个参数,前一个指定路径,后一个指定显示方式。 
  ShellExecute 可以指定工作目录,并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序,ShellExecute还可以打开网页,启动相应的邮件关联发送邮件等等。 
  CreateProcess  一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性,若要达到这些目的,我们就需要使用CreateProcess函数了。  
  三个SDK函数( WinExec、ShellExec、CrateProcess )的语法:  
  (一)WinExec  
  这个函数最简单,只有两个参数,原型如下:  
  UINT WinExec(  
  LPCSTR lpCmdLine,   // 命令路径  
  UINT uCmdShow      // 显示方式  
  );  
  使用方法如下:  
  WinExec("Notepad.exe", SW_SHOW);  // 打开记事本  
  WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED); // 以最大化的方式打开Test.exe  
  需要注意的是若用 SW_SHOWMAXMIZED 方式去加载一个无最大化按钮的程序,譬如Neterm,Calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。 
  这个函数只能打开exe文件。  
  需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。 
  msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms687 393[/url](VS.85).aspx  
  (二)ShellExecute  
  原型如下:  
  HINSTANCE ShellExecute(  
  HWND hwnd,           //父窗口句柄  
  LPCTSTR lpOperation,   //操作, 打开方式 "edit","explore","open","find","print","NULL"  
  LPCTSTR lpFile,         //文件名,前面可加路径  
  LPCTSTR lpParameters,   //参数  
  LPCTSTR lpDirectory,    //默认文件夹  
  INT nShowCmd          //显示方式  
  );  
  使用方法如下:  
  ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL, SW_SHOWNORMAL); // 打开C:\Test.txt 文件  
  ShellExecute(NULL, "open", "http://www.google.com/",  NULL, NULL, SW_SHOWNORMAL); // 打开网页www.google.com  
  ShellExecute(NULL,"explore", "D:\\C++",NULL,NULL,SW_SHOWNORMAL); // 打开目录D:\C++  
  ShellExecute(NULL,"print","C:\\Test.txt",NULL,NULL , SW_HIDE); // 打印文件C:\Test.txt  
  ShellExecute不支持定向输出。 
  这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。 
  需要的头文件:windows.h,shellapi.h(前者是我试验出来的,后者是msdn说需要的)。另外这两者的先后顺序不能变。 
  msdn上说明:[url]http://msdn.microsoft.com/en-us/library/bb762 153[/url](VS.85).aspx  
  (三)CreateProcess  
  原型如下:  
  BOOL CreateProcess(  
  LPCTSTR lpApplicationName, //执行程序名  
  LPTSTR lpCommandLine,  // 参数行  
  //下面两个参数描述了所创建的进程和线程的安全属性,如果为NULL则使用默认的安全属性  
  LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes  
  LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes  
  BOOL bInheritHandles,  // 继承标志  
  DWORD dwCreationFlags, // 创建标志  
  LPVOID lpEnvironment,  // 环境变量  
  LPCTSTR lpCurrentDirectory,   // 运行该进程的初始目录  
  LPSTARTUPINFO lpStartupInfo,  // 用于在创建子进程时设置各种属性  
  LPPROCESS_INFORMATION lpProcessInformation //用于在进程创建后接受相关信息  
  );  
  使用方法如下:  
  PROCESS_INFORMATION pi;  
  STARTUPINFO si;  
  memset(&si,0,sizeof(si));  
  si.cb=sizeof(si);  
  si.wShowWindow=SW_SHOW;  
  si.dwFlags=STARTF_USESHOWWINDOW;  
  bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi); 
  这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。 
  需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。 
  msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms682 425[/url](VS.85).aspx 
  可以看出,通过上面的几个不同的方法,都可以实现在应用程序中打开其他应用程序的目的,其中有些方法可能会麻烦一点,所以就需要我们根据不同的目的去选择最适合自己的方法去实现自己的目的!  
  关于三个SDK函数: WinExec, ShellExecute,CreateProcess 的其他注意事项:  
  1、定义头文件  
  原作者的内容删去。 
  这个是引用新函数都必须注意的内容。但是MS的头文件引用顺序有点怪,比如上面的三种清理。另外,如果用了预编译,那么记得在任何源程序中的#include "stdafx.h"之前的引用都会失效,从其后才生效。(不可否认,预编译有他的好处,尤其当程序很大的时候,但是任何好处都是要付出代价的) 
  2、定义路径  
  C++中所表示的路径要用 " \\ "而不是平常所用的" \ ",所以以上三个函数表示路径都为:  
  Disk:\\Directory\\...\\File name  
  WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED);  
  ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL, SW_SHOWNORMAL);  
  bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE ,NULL,NULL,NULL,NULL,&si,&pi) 
  3、注意文件的路径 
  在程序a调用程序b的时候,b原来的默认的当前路径都会变成a的当前路径。所以,一定要注意。 
  可以养成使用绝对路径的习惯,另外,记得打开文件之类的操作,一定要验证是否有错。 
  VC++6.0  
  Win95  
  如何在VC++中调用外部的DOS程序?它的函数是什么?如果用API,它的函数是什么?  
  回答:  
  你可以使用Windows API函数WinExec、ShellExecute。这两个函数可以调用Windows和DOS程序。WinExec主要运行EXE文件。如:  
  WinExec("Notepad.exe Readme.txt", SW_SHOW);  
  ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。如:  
  ShellExecute(0, "open", "http://askpro.yeah.net", NULL, NULL, 0);  
  另外,参考QA000583 "外调一个DOS程序,但是又不想显示其产生的窗口"。  
  Vc 5.0  
  Windows 95  
  我正在编写一个程序,想外调一个现成的Com,但是又不想显示其产生的窗口,我试过可以关闭该窗口,一样能运行,可是在我的程序中如何获取该窗口句柄,如何自动关闭它?(飞飞)   
  其实使用ShellExecute调用DOS程序时可以不显示窗口,如:  
  ShellExecute(0, "open", "c:\\tools\\arj.exe", "a c:\\p.arj c:\\*.bat c:\\*.sys", NULL, SW_HIDE);  
  对于你的问题,你可以使用FindWindow获得句柄,但关掉窗口就不能再继续执行了。而你说的关闭窗口还能执行,大概是因为在你关闭窗口时已经运行结束了。   
  #include "stdafx.h" 
  #include  
  #include //ShellExecute 要引用的库 
  int main(int argc, _TCHAR* argv[]) 
  {     
  ShellExecute(NULL,NULL,_T("E:\\Projekt1.exe"),NULL ,NULL,SW_SHOW); 
  getchar(); 
  return 0; 
  } 
  #include "stdafx.h" 
  #include   
  #include   
  #include  
  DWORD WINAPI ThreadWork(LPVOID num) 
  { 
  printf("%d\n",num); 
  return 0; 
  } 
  int _tmain(int argc, _TCHAR* argv[]) 
  { 
  DWORD dwThreadID[5];  
  HANDLE threadhandle=CreateThread(NULL, 
  0, 
  ThreadWork, 
  (LPVOID)2,//传递的参数 
  0, 
  &dwThreadID[0]); 
  getchar();  
  return 0; 
  } 

以上是关于VC中用ShellExecute等函数执行exe出现错误,但是鼠标双击就可以,这是为啥?的主要内容,如果未能解决你的问题,请参考以下文章

用ShellExecuteEx函数执行一个vc写的exe,vc程序的返回函数是return(n)

VC中,ShellExecute函数如何用默认打印机打印?

ShellExecute函数使用求助

MFC 打开外部EXE文件的三种方法

MFC中如何关闭ShellExecute调用的外部执行程序?

ShellExecute API函数用法简析