龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > VC开发 >

VC用键盘操作静态链接打开应用程序中的URLs[组图](4)

时间:2009-12-30 15:42来源:未知 作者:admin 点击:
分享到:
所以,如果你已经使用托管扩展,为什么不用.NET框架的Process类和 Process::Start 来代替 ShellExecute 呢?有一个静态重载正好是你想要的: Process::Start("http://

  所以,如果你已经使用托管扩展,为什么不用.NET框架的Process类和 Process::Start 来代替 ShellExecute 呢?有一个静态重载正好是你想要的:

Process::Start("http://www.microsoft.com");
  哦,回来一试,还是不行。此调用丢出 Win32Exception 异常,它甚至在 NativeErrorCode 属性中产生更莫名其妙的错误代码:ERROR_SXS_KEY_NOT_FOUND。此错误的描述是:“请求的查找键在所有的活动上下文中未找到。”怎么回事呢?

  如果你认真看一看 Process 的文档,你会发现 Process 使用一个叫 StartInfo 的东西来告诉它如何启动该进程。StartInfo 的属性之一便是 UseShellExecute。默认情况下,UseShellExecute 为 True,由此告诉框架用外壳启动进程,也就是说用 ShellExecuteEx。好了,试一下将它置成 False。结果正像文档所说的,你只能启动 EXEs,而非文件名或URLs。两种方法都行不通,你在兜圈子。

  再仔细看看 Process::Start 的文档,它告诉你如果你想用 UseShellExecute,你必须保证指  定 [STAThread](单线程公寓模型)作为应用程序 main 函数的特征:

// in C#
public class MyForm : Form {
[STAThread]
     public static void Main(string[] args) {
     ...
     }
}
  那么,对 C# 或者是“纯”(非 MFC)C++ 程序能行得通,它们有自己的 main 函数,但 MFC 程序怎么办?如果是那样的话,main,_tmain,_tWinMain 或任何平台入口点都深藏在 MFC 内部,无法编辑源代码添加 [STAThread]。你可以使用 /ENTRY:MyMain 并编写自己的调用 CRT 启动例程的 [STAThread] MyMain,碰到这种情况太糟了。肯定有比这个简单的方法。

  实际上,在 MFC 应用程序中有一种强制线程为单线程(STA)模型的方法,而不使用 [STAThread]。你只要在框架试图调用 CoInitializeEx(COINIT_MULTITHREADED) 之前调用 CoInitialize(NULL) 即可。用一个小类来做这件事情。代码如下:

//////////////////////////////////////////////////////////////////////////
// 用此类在混合模式应用程序中强制 STA (单线程公寓模型) 线程。使用方法如下:
// 在你的 main 应用模块中建一个静态实例,例如,MyApp.cpp 或在进入 CLR 之前要
// 运行构造函数的任何地方。
//////////////////////////////////////////////////////////////////////////
class CSTAThread {
public:
   CSTAThread() {
     CoInitialize(NULL);
   }
   ~CSTAThread() {
     CoUninitialize();
   }
};   
  构造函数调用 CoInitialize(NULL)(STA 线程)和析构函数调用 CoUninitialize。所以只要象下面这样在 MFC 程序的 main 中插入一个实例即可:

// 这样做效果与 [STAThread] 一样
CSTAThread forceSTAThread;
  真是聪明。(感谢微软的 Martyn Lovell 给我提出这个建议)。在 Visual C++ 2005 中,你可以告诉链接器你的入口点使用 STAThread,但目前你得用 CSTAThread。

  还有一个方法可以在应用程序中启动 URLs,它甚至可以用于多线程模式,这个方法就是 rundll32.exe,这个程序很方便,用它可以调用任何 DLL 中的函数。你只要给它提供 DLL、函数名以及要传递的参数即可。Rundll32.exe 绝对多才多艺,你可以用它来关闭和重启 Windows,创建快捷方式以及启动控制面板程序。我见过一个专门研究 rundll32.exe 使用技巧的网站;只要知道要调用的DLLs,一切都搞掂。你可以象下面这样用 rundll32.exe 从命令行打开一个 URL:

  rundll32.exe url.dll,FileProtocolHandler www.vckbase.com

  url.dll 中的函数 FileProtocolHandler 负责这个工作。如果使用 ShellExecute,可以象下面这样写:

LPCTSTR url = _T("www.vckbase.com");
CString args;
args.Format(_T("url.dll,FileProtocolHandler %s"), url);
ShellExecute(NULL, _T("open"), _T("rundll32.exe"), args);
  即便是在多线程应用中这都是可以行得通的,因为你赋予 ShellExecute 的是一个真正的 EXE,而不是一个外壳扩展和 IShellExecuteHook 运行必须的文件名。唯一的缺点是一旦打不开 URL,你得不到任何错误返回码。因此,我推荐使用 CSTAThread,并直接用 ShellExecute 来调用 URL,尤其是在 MFC 程序中,不管怎样,它与公寓模型线程配合得很好。

  作为实践的例子,我更新了第一个问题中的 CStaticLink 类,使用 CSTAThread 和 ShellExecute,并编写了一个托管测试程序,LinkTest,为了证明它能在托管模式下正常运行。我在 StatLink.h 中包含了 CSTAThread 类。所以现在 CStaticLink 又多了一个特性:不管是本机应用还是用 /clr 编译以及托管扩展,它都能正常运行。具体细节请下载源代码。

精彩图集

赞助商链接