c++builder6使用ShellExecuteEx遇到诡异问题

CB6的程序是很多年前的一个东西,现在要给它增加新功能,用QT写一个摄像头控制让他来调用。试过system()函数,功能完全可以实现但那个黑窗口太丑了。于是改用ShellExecuteEx。于是为了这一点点的美化,一天时间就扔进去了。

一开始代码是这样的,网上类似代码有很多,也没有什么特殊操作。series是个变量,作为参数送给被执行的takePic。
    .
    .
    .
    AnsiString cmd = "takePic_32\\takePic.exe ";
    AnsiString series = var;
    .
    .
    .

    SHELLEXECUTEINFO sei;
    ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO));
    sei.cbSize = sizeof(SHELLEXECUTEINFO);
    sei.lpFile = cmd.c_str();
    sei.lpParameters = series.c_str();
    sei.nShow = SW_SHOW;
    sei.fMask = SEE_MASK_NOCLOSEPROCESS;//使用 SEE_MASK_NOCLOSEPROCESS 参数
    sei.lpVerb = NULL;//("open");
    if (ShellExecuteEx(&sei))//执行成功
    {
        if (sei.hProcess)//指定 SEE_MASK_NOCLOSEPROCESS 并其成功执行,则 hProcess 将会返回执行成功的进程句柄
            WaitForSingleObject(sei.hProcess, INFINITE);//等待执行完毕
    }else{
        ShowMessage("无法启动摄像头!");
        return;
    }


takePic单独运行时一切正常,被调用之后虽然程序可以运行,可以拍照,但拍出来的照片无法存储。
一开始以为是权限问题,试了各种方法都无法解决。做了很多试验总结出的规律是,被调用的程序可以复制已经存在的文件,但不能建立新的文件。
又以为是takePic有问题,在QT里找了很久也没有线索。
各种查资料,各种试验,没头绪。
就在已经准备放弃这个方案时,无意发现不传 lpParameters 运行时一切正常,或者把 lpParameters 用裸字串写死也一切正常。
太奇怪了,按文档资料来看,

SHELLEXECUTEINFO定义:
typedef struct _SHELLEXECUTEINFO {
  DWORD     cbSize;//结构大小,sizeof(SHELLEXECUTEINFO)
  ULONG     fMask;//指定结构成员的有效性
  HWND      hwnd;//父窗口句柄或出错时显示错误父窗口的句柄,可以为 NULL
  LPCTSTR   lpVerb;//指定该函数的执行动作
  LPCTSTR   lpFile;//操作对象路径
  LPCTSTR   lpParameters;//执行参数,可以为 ULL
  LPCTSTR   lpDirectory;//工作目录,可以为 NULL
  int       nShow;//显示方式
  HINSTANCE hInstApp;//如果设置了 SEE_MASK_NOCLOSEPROCESS ,并且调用成功则该值大于32,调用失败者被设置错误值
  LPVOID    lpIDList;//ITEMIDLIST结构的地址,存储成员的特别标识符,当fMask不包括SEE_MASK_IDLIST或SEE_MASK_INVOKEIDLIST时该项被忽略
  LPCTSTR   lpClass;//指明文件类别的名字或GUID,当fMask不包括SEE_MASK_CLASSNAME时该项被忽略
  HKEY      hkeyClass;//获得已在系统注册的文件类型的Handle,当fMask不包括SEE_MASK_HOTKEY时该项被忽略
  DWORD     dwHotKey;//程序的热键关联,低位存储虚拟关键码(Key Code),高位存储修改标志位(HOTKEYF_),当fmask不包括SEE_MASK_HOTKEY时该项被忽略
  union {
    HANDLE hIcon;//取得对应文件类型的图标的Handle,当fMask不包括SEE_MASK_ICON时该项被忽略
    HANDLE hMonitor;//将文档显示在显示器上的Handle,当fMask不包括SEE_MASK_HMONITOR时该项被忽略
  } DUMMYUNIONNAME;
  HANDLE    hProcess;//指向新启动的程序的句柄。若fMask不设为SEE_MASK_NOCLOSEPROCESS则该项值为NULL。
                     //但若程序没有启动,即使fMask设为SEE_MASK_NOCLOSEPROCESS,该值也仍为NULL。
                     //如果没有新创建进程,也会为空
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;


可执行文件和参数都是LPCTSTR类型的,我在调用时虽然没特意进行LPCTSTR的转换,但传送char * 进去,编译运行都没有任何出错提示。

于是把参数相关的地方改了个写法:

    char p[256];
    strcpy(p,bzh->Text.Trim().c_str());
    LPCSTR pa = (LPCSTR) p;
    sei.lpParameters = pa;

这么罗嗦一圈之后,程序运行一切正常了。
总结一下,不同开发环境下,类似类型的变量之间还是有很多差异的,使用时应当加以注意,不能随便相信编译环境的默认转换。
但我遇到的问题也很解释不通,同一个函数调用,同样要求LPCSTR变量,为什么有的参数行,有的参数就不行?而且引发这么诡异的连带后果,被调程序运行正常,可以读写已经存在的文件,却失去了创建新文件的权限。

posted @ 2020-05-10 17:23  桑底坡  阅读(307)  评论(0编辑  收藏  举报