Multithreading 定义一个COM类,该类只能从注册它的同一个EXE创建 如果在主线程中有一个带有STA的EXE 在EXE中,创建了另一个STA的第二个线程 带有STA的第二个线程应该使用CoRegisterClassObject公开一个类工厂,该类工厂只能从此进程中使用

Multithreading 定义一个COM类,该类只能从注册它的同一个EXE创建 如果在主线程中有一个带有STA的EXE 在EXE中,创建了另一个STA的第二个线程 带有STA的第二个线程应该使用CoRegisterClassObject公开一个类工厂,该类工厂只能从此进程中使用,multithreading,com,Multithreading,Com,当我将CoreRegisterClassObject与CLSCTX_INPROC_服务器和REGCLS_多线程一起使用时,主线程使用CLSCTX_创建对象,我得到错误“类未注册” 当我将CoreRegisterClassObject与CLSCTX_LOCAL_SERVER和REGCLS_MULTIPLEUSE一起使用时,主线程可以创建该对象。但程序的下一个实例将在第一个进程内创建thze对象 在CoCreateInstance内使用CLSCTX_INPROC标志将始终表示该类未注册 顺便说一句:

当我将CoreRegisterClassObject与CLSCTX_INPROC_服务器和REGCLS_多线程一起使用时,主线程使用CLSCTX_创建对象,我得到错误“类未注册”

当我将CoreRegisterClassObject与CLSCTX_LOCAL_SERVER和REGCLS_MULTIPLEUSE一起使用时,主线程可以创建该对象。但程序的下一个实例将在第一个进程内创建thze对象

在CoCreateInstance内使用CLSCTX_INPROC标志将始终表示该类未注册

顺便说一句:因为我总是在程序启动时自己注册这个类,所以除了typelib中必需的注册表项外,没有其他注册表项

更详细的解释我为什么需要这个: 创建的类使用在EXE上下文中内部创建的指针和函数。试想一下,我正在编程一个“应用程序”对象,它应该只支持这个进程中的函数以及这个会话管理的文件和对象。我需要这个COM对象,因为它在VBScript主机中使用,并且再次暴露给其他COM对象


有没有办法注册只支持从我的EXE内部创建的类工厂?

这里的问题是
CLSCTX\u INPROC\u SERVER
使注册仅对调用单元可见,而下一个选项
CLSCTX\u LOCAL\u SERVER
使其跨单元跨进程。也就是说,正如您所发现的,没有特定的选项,跨单元但在进程内,因此2+进程可以公开其进程范围内的类对象

另外,
CoRegisterClassObject
以及注册本身指示COM使用调用的单元进行进一步实例化,这看起来也很相关,这可以防止在可能被阻止的线程上注册,甚至阻止这些单元参与指针的封送


解决方法是通过使用进程特定的名称运行对象表来公开类对象。标准的
RegisterActiveObject
将使用“!{CLSID}”名称,您对“!{CLSID}-processid”这样的名称感兴趣(这种灵活性可以通过
IRunningObjectTable::Register
ROT注册而不是
RegisterActiveObject
)来实现,这样单独的进程就可以查找自己的对象。从侧面STA线程调用ROT注册将导致直接绕过“阻塞”的主STA将调用封送回那里。

。R已经回答了这个问题,我接受了。但我想详细解释一下我选择的解决方案。使用ROT有点简单

  • 当Exe启动时,第二个带有STA2的线程将在启动阶段创建
  • 我只是像往常一样在第二个线程(STA2)中创建类工厂
  • 我没有使用CoRegisterClassObject公开这个类工厂。我将IClassFactory指针存储在IROT中。我使用现有的ATL实现
  • 现在,我的应用程序中任何需要此STA对象的线程都可以从IROT检索IClassFactory指针,并可以代表它创建所需的对象。封送处理在我的应用程序内部不同STA之间安全地完成。每个EXE都可以在IROT中存储自己的类工厂私有副本

  • 因此,我有我的私人“每进程”COM类注册。

    要实现您想要的,您需要为每个新公寓调用
    CoreRegisterClassObject
    。要了解有关新公寓的信息,您可以使用

    您应该在第一次调用
    CoInitialize[Ex]
    之前调用它

    在接口的实现中:

    HRESULT CRegisterClassesSpy::后初始化(HRESULT hrCoInit、DWORD dwCoInit、DWORD dwNewThreadAptRefs)
    {
    if(hrCoInit==S_OK&&dwNewThreadAptRefs==1){
    如果(dwCoInit==COINIT_公寓)||
    (dwCoInit==COINIT\u多线程&&
    联锁增量(&m线程)==1){
    hrCoInit=RegisterClassObjects();
    }
    }
    返回它;
    }
    HRESULT CRegisterClassesSpy::预取消初始化(DWORD dwCurThreadAptRefs)
    {
    HRESULT hr=S_正常;
    if(dwCurThreadAptRefs==1){
    APTTYPE APTTYPE;
    APTTYPEQUALIFIER APTTYPEQUALIFIER;
    hr=CoGetPartmentType(&aptType,&aptTypeQualifier);
    如果成功(hr)&&
    (aptType==aptType\u STA||
    aptType==aptType\u MAINSTA||
    (aptType==aptType\u MTA和&interlocateddecrement(&m\u MTAThreads)==0))){
    hr=RevokeClassObjects();
    }
    }
    返回人力资源;
    }
    
    因为初始化间谍是每个线程的,所以需要检测新线程。唯一(容易?支持?)的方法是使用DLL

    下面是一个示例(为清晰起见,无错误检查):

    BOOL WINAPI DllMain(HINSTANCE hinstDLL、DWORD fdreason、LPVOID lpvReserved)
    {
    如果(fdareason==DLL\u进程\u附加){
    g_tlsIndex=TlsAlloc();
    TlsSetValue(g_tlsIndex,HeapAlloc(GetProcessHeap(),HEAP_ZERO_内存,sizeof(ULARGE_整数));
    }
    如果(fdreason==DLL_进程_附加| | fdreason==DLL_线程_附加){
    CRegisterClassesSpy*spy=new CRegisterClassesSpy();
    IIInitializeSpy*pSpy;
    spy->QueryInterface(IID_IIIalizeSpy,重新解释演员阵容(&pSpy));
    间谍->释放();
    ULARGE_INTEGER*pCookie=重新解释转换(TlsGetValue(g_tlsIndex));
    CoreRegisterInitializeSpy(pSpy,pCookie));
    pSpy->Release();
    }
    else if((fdreason==DLL_进程_分离&&lpReserved==NULL)| | fdreason==DLL_线程_分离){
    ULARGE_INTEGER*pCookie=重新解释转换(TlsGetValue(g_tlsIndex));