现在的位置: 首页 > 综合 > 正文

COM文摘

2013年10月08日 ⁄ 综合 ⁄ 共 6398字 ⁄ 字号 评论关闭

http://hi.baidu.com/loserwang/blog/item/fedb0354a87b79193a293594.html

CLSCTX Enumeration

CLSCTX_INPROC_SERVER

The code that creates and manages objects of this class is a DLL that runs in the same process as the caller of the function specifying the class context.

CLSCTX_INPROC_HANDLER

The code that manages objects of this class is an in-process handler. This is a DLL that runs in the client process and implements client-side structures of this class when instances of the class are accessed remotely.

CLSCTX_LOCAL_SERVER

The EXE code that creates and manages objects of this class runs on same machine but is loaded in a separate process space.

CLSCTX_INPROC_SERVER16

Obsolete.

CLSCTX_REMOTE_SERVER

A remote context. The LocalServer32 or LocalService code that creates and manages objects of this class is run on a different computer.

Values from the CLSCTX enumeration are used in activation calls (CoCreateInstance, CoCreateInstanceEx, CoGetClassObject, and so on) to indicate the preferred execution contexts—in-process, local, or remote—in which an object is to be run. They are also used in calls to CoRegisterClassObject to indicate the set of execution contexts in which a class object is to be made available for requests to construct instances (IClassFactory::CreateInstance).

To indicate that more than one context is acceptable, you can combine multiple values with Boolean ORs. The contexts are tried in the order in which they are listed.

Given a set of CLSCTX flags, the execution context to be used depends on the availability of registered class codes and other parameters according to the following algorithm.

  1. If the call specifies one of the following, CLSCTX_REMOTE_SERVER is implied and is added to the list of flags:
    1. An explicit COSERVERINFO structure indicating a machine different from the current computer.
    2. No explicit COSERVERINFO structure specified but the specified class is registered with either the RemoteServerName or ActivateAtStorage registry value.

    The second case allows applications written prior to the release of distributed COM to be the configuration of classes for remote activation to be used by client applications available prior to DCOM and the CLSCTX_REMOTE_SERVER flag. The cases in which there would be no explicit COSERVERINFO structure are when the value is specified as NULL or when it is not one of the function parameters (as in calls to CoCreateInstance and CoGetClassObject).

  2. If the explicit COSERVERINFO parameter indicates the current computer, CLSCTX_REMOTE_SERVER is removed if present.

The rest of the processing proceeds by looking at the value(s) in the following sequence:

  1. If the flags include CLSCTX_REMOTE_SERVER and no COSERVERINFO parameter is specified and if the activation request indicates a persistent state from which to initialize the object (with CoGetInstanceFromFile, CoGetInstanceFromIStorage, or, for a file moniker, in a call to IMoniker::BindToObject) and the class has an ActivateAtStorage subkey or no class registry information whatsoever, the request to activate and initialize is forwarded to the computer where the persistent state resides. (Refer to the remote activation functions listed in the See Also section for details.)
  2. If the flags include CLSCTX_INPROC_SERVER, the class code in the DLL found under the class's InprocServer32 key is used if this key exists. The class code will run within the same process as the caller.
  3. If the flags include CLSCTX_INPROC_HANDLER, the class code in the DLL found under the class's InprocHandler32 key is used if this key exists. The class code will run within the same process as the caller.
  4. If the flags include CLSCTX_LOCAL_SERVER, the class code in the service found under the class's LocalService key is used if this key exists. If no service is specified but an EXE is specified under that same key, the class code associated with that EXE is used. The class code (in either case) will be run in a separate service process on the same computer as the caller.
  5. If the flag is set to CLSCTX_REMOTE_SERVER and an additional COSERVERINFO parameter to the function specifies a particular remote computer, a request to activate is forwarded to this remote computer with flags modified to set to CLSCTX_LOCAL_SERVER. The class code will run in its own process on this specific computer, which must be different from that of the caller.
  6. Finally, if the flags include CLSCTX_REMOTE_SERVER and no COSERVERINFO parameter is specified and if a computer name is given under the class's RemoteServerName named-value, the request to activate is forwarded to this remote computer with the flags modified to be set to CLSCTX_LOCAL_SERVER. The class code will run in its own process on this specific computer, which must be different from that of the caller.

 

vista创建一个被“提升”了的COM对象

若你对COM有所造诣的话,应该知道COM支持我们在一个代理进程中创建COM服务器。现在这项技术又有了一些发展,我们可以在一个“提升”了的代理进程中创建COM服务器了。这项技术非常有用,借助于它的帮助,我们就可以在应用程序运行期间简单地创建一个COM对象,而不必去创建一个全新的进程。

使用这个技术中最难的一部分就是如何正确地注册该COM服务器,保证将其加载到一个“提升”了的代理进程中,因为COM对象需要我们显式地声明其协作方式。

我们要做的第一件事就是更新COM的注册,用来保证我们的库(DLL)服务器能够运行于一个代理进程中。只要将“DllSurrogate”添加至服务器的AppID注册表键中即可。在ATL中,只要简单地更新项目的主RGS文件,如下所示:

HKCR
{
    NoRemove AppID
    {
        '%APPID%' = s 'SampleServer'
        {
            val DllSurrogate = s ''
        }
        'SampleServer.DLL'
        {
            val AppID = s '%APPID%'
        }
    }
}

DllSurrogate 的空值表示系统提供的代理进程即刻可以使用。现在COM客户端就能够指定CLSCTX_LOCAL_SERVER 运行上下文,在该代理进程中创建COM服务器了:

CComPtr<ISampleServer>server;
COM_VERIFY(server.CoCreateInstance(__uuidof(SampleServer),
                                   0,
                                   CLSCTX_LOCAL_SERVER));

下一步就是启用该COM类的“提升”运行。这需要我们在该COM类的注册脚本中添加一些东西——一个用来表示支持“提升”的提升键,以及一个名为“LocalizedString”的值,加上用来显示在UAC确认对话框中的名称。ATL中COM类的注册脚本将类似如下所示:

HKCR
{
    SampleServer.SampleServer.1 = s 'SampleServer Class'
    {
        CLSID = s '{91C5423A-CF90-4E62-93AD-E5B922AE8681}'
    }
    SampleServer.SampleServer = s 'SampleServer Class'
    {
        CLSID = s '{91C5423A-CF90-4E62-93AD-E5B922AE8681}'
        CurVer = s 'SampleServer.SampleServer.1'
    }
    NoRemove CLSID
    {
        ForceRemove {91C5423A-CF90-4E62-93AD-E5B922AE8681} = s 'SampleServer Class'
        {
            ProgID = s 'SampleServer.SampleServer.1'
            VersionIndependentProgID = s 'SampleServer.SampleServer'
            InprocServer32 = s '%MODULE%'
            {
                val ThreadingModel = s 'Neutral'
            }
            val AppID = s '%APPID%'
            'TypeLib' = s '{A43B074B-0452-4FF4-8308-6B0BF641C3AE}'
            Elevation
            {
                val Enabled = d 1
            }
            val LocalizedString = s '@%MODULE%,-101'
        }
    }
}

不要忘记在你的字符串表中为本地化名称添加一个条目。现在该COM客户即可启动该“提升”了的COM服务器了。CoCreateInstance 不像CreateProcess那样直接创建一个“提升”了的COM对象,我们需要使用“COM提升名称(COM elevation moniker)”来完成。最简单的方法就是使用CoGetObject 函数创建这个名称(moniker )并返回最终创建好的对象的代理:

template <typename T>
HRESULT CreateElevatedInstance(HWND window,
                               REFCLSID classId,
                               T** object)
{
    BIND_OPTS3 bindOptions;
    ::ZeroMemory(&bindOptions, sizeof (BIND_OPTS3));
    bindOptions.cbStruct = sizeof (BIND_OPTS3);
    bindOptions.hwnd = window;
    bindOptions.dwClassContext = CLSCTX_LOCAL_SERVER;
    CString string;
    const int guidLength = 39;
    COM_VERIFY(::StringFromGUID2(classId,
                                 string.GetBufferSetLength(guidLength),
                                 guidLength));
    string.ReleaseBuffer();
    string.Insert(0, L"Elevation:Administrator!new:");
    return ::CoGetObject(string,
                         &bindOptions,
                         __uuidof(T),
                         reinterpret_cast<void**>(object));
}
Using the function template is just as simple as calling CoCreateInstance:
CComPtr<ISampleServer>server;
COM_VERIFY(CreateElevatedInstance(0, // window
                                  __uuidof(SampleServer),
                                  &server);

如同ShellExecute一样,UAC使用该窗体的句柄判断该提示是否会得到输入焦点,还是只在后台默默等待。

抱歉!评论已关闭.