Попытка создать экземпляр локального COM-сервера .NET завершается с ошибкой 0x80080005 (CO_E_SERVER_EXEC_FAILURE).C#

Место общения программистов C#
Anonymous
Попытка создать экземпляр локального COM-сервера .NET завершается с ошибкой 0x80080005 (CO_E_SERVER_EXEC_FAILURE).

Сообщение Anonymous »

У меня есть саморегистрирующийся локальный .NET COM-сервер x64 для Windows, написанный на C#, и простой COM-клиент, написанный на C++.

Репозиторий решений

Сервер создает все необходимое записи реестра и регистрирует класс COM с помощью реализации IClassFactory. Клиент вызывает CoCreateInstance для класса COM и интерфейса, который возвращает CO_E_SERVER_EXEC_FAILURE. Ошибка регистрации журнала событий Windows с кодом события 10010 (сервер не зарегистрировался в DCOM в течение требуемого времени ожидания).

Реализация на локальном сервере:

Код: Выделить всё

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using static NetComServer.Helpers.Win32Helper;
using static NetComServer.Helpers.RegistryHelper;
using static NetComServer.Helpers.EnvironmentHelper;
using static NetComServer.ComServerConstants;
using static NetComServer.ComLocalServer;
using IClassFactory = NetComServer.Helpers.Win32Helper.IClassFactory;
using WriteLineDelegate = NetComServer.Helpers.WriteLineDelegate;

return NetComServer.Program.Main(args);

namespace NetComServer
{
public partial class Program
{
[STAThread]
public static int Main(string[] args)
{
int exitCode = -1;
string[]? arguments = string.Join("", args)?.ToLower()?.Split(['/', '-'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
Update = arguments?.Contains("update") == true;
KeepConsole = arguments?.Contains("keepconsole") == true;
if(arguments?.Contains("unregister") == true)
{
exitCode = UnRegisterServer() ? 0 : -1;
}
else if(Update || arguments?.Contains("register") == true)
{
exitCode = RegisterServer() ? 0 : -1;
}
else
{
ComLocalServer localServer = new ComLocalServer();
WriteLine("NetComServer is running...");
exitCode = localServer.RegisterClassObject() ? 0 : -1;
WriteLine("RegisterClassObject is " + (exitCode == 0 ? "successeed." : "failed."));
if(exitCode == 0)
{
localServer.IsServerRunning = true;
Thread threadRunServer = new Thread(localServer.Run);
WriteLine("Message loop is start.");
MSG msg;
while(GetMessage(out msg, nint.Zero, 0, 0) > 0)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
WriteLine("Message loop is end.");
exitCode = localServer.UnRegisterClassObject() ? 0 : -1;
WriteLine("UnRegisterClassObject is " + (exitCode == 0 ? "successeed."  : "failed."));
WriteLine("Wait for server stop...");
localServer.IsServerRunning = false;
localServer.ServerStopEvent.WaitOne();
localServer.ServerStopEvent.Reset();
WriteLine("Server is stoped.");
}
if(HasConsole)
{
Console.WriteLine("Press any key to exit");
Console.ReadLine();
if(!KeepConsole)
{
FreeConsole();
}
}
}
return exitCode;
}
}
[ComVisible(true)]
[Guid(CLSID_Factory)]
public class ComServerClassFactory : IClassFactory
{
public int QueryInterface([In] ref Guid riid, [Out] out nint ppvObject)
{
int hr = S_OK;
ppvObject = nint.Zero;
string? strIId = riid.ToString()?.ToUpper()?.Trim();
switch(strIId)
{
case IID_IComServer:
ppvObject = Marshal.GetComInterfaceForObject(this);
hr = Marshal.GetLastSystemError();
break;
case IID_IClassFactory:
ppvObject = Marshal.GetComInterfaceForObject(this);
hr = Marshal.GetLastSystemError();
break;
case IID_IDispatch:
ppvObject = Marshal.GetIDispatchForObject(this);
hr = Marshal.GetLastSystemError();
break;
case IID_IUnknown:
ppvObject = Marshal.GetIUnknownForObject(this);
hr = Marshal.GetLastSystemError();
break;
default:
hr = E_NOINTERFACE;
break;
}
return hr;
}
public int CreateInstance([In, MarshalAs(UnmanagedType.IUnknown)] nint pUnkOuter, [In] ref Guid riid, [Out] out nint ppvObject)
{
int hr = S_OK;
ppvObject = nint.Zero;
if(pUnkOuter == nint.Zero)
{
string? strIId = riid.ToString()?.ToUpper()?.Trim();
switch(strIId)
{
case IID_IComServer:
ppvObject = Marshal.GetComInterfaceForObject(new ComServer());
hr = Marshal.GetLastSystemError();
break;
case IID_IDispatch:
ppvObject = Marshal.GetIDispatchForObject(new ComServer());
hr = Marshal.GetLastSystemError();
break;
case IID_IUnknown:
ppvObject = Marshal.GetIUnknownForObject(new ComServer());
hr = Marshal.GetLastSystemError();
break;
default:
hr = E_NOINTERFACE;
break;
}
}
else
{
hr = CLASS_E_NOAGGREGATION;
}
return hr;
}
public int LockServer([In] bool fLock)
{
return S_OK;
}
}
public class ComLocalServer : IDisposable
{
public static ReadLineDelegate? ReadLine { get; set; }
public static WriteLineDelegate? WriteLine { get; set; }
private static uint ClassId;
private bool isRunning = false;
public bool IsServerRunning
{
get
{
lock(this)
{
return isRunning;
}
}
set
{
lock(this)
{
value = isRunning;
}
}
}
public static bool Update { get; set; } = false;
public static bool HasConsole { get; set; } = false;
public static bool KeepConsole { get; set; } = false;
private bool disposed = false;
public ManualResetEvent ServerStopEvent { get; set;  } = new ManualResetEvent(false);
public ComLocalServer()
{
HasConsole = HasConsole || ShowConsole(true);
WriteLine = HasConsole ? Console.WriteLine : new WriteLineDelegate((string? message) => Debug.WriteLine(message));
ReadLine = HasConsole ? Console.ReadLine : null;
}
public static bool RegisterServer()
{
bool isRegistered = false;
try
{
string strPublishDirectory = GetPublishDirectory(typeof(ComLocalServer));
string strModuleName = typeof(ComLocalServer).Module.Name.Replace(".dll", ".exe");
if(!string.IsNullOrWhiteSpace(strModuleName) && !string.IsNullOrWhiteSpace(strPublishDirectory))
{
string strServerPath = Path.Combine(strPublishDirectory, strModuleName);
isRegistered = ComServer.RegisterServer(strServerPath, Update, KeepConsole);
}
}
catch(Exception e)
{
isRegistered = false;
Debug.WriteLine(e);
throw;
}
return isRegistered;
}
public static bool UnRegisterServer()
{
bool isUnregistered = false;
try
{
isUnregistered = ComServer.UnregisterServer(KeepConsole);
}
catch(Exception e)
{
isUnregistered = false;
Debug.WriteLine(e);
throw;
}
return isUnregistered;
}
public bool RegisterClassObject()
{
Guid clsidComServer = new Guid(CLSID_ComServer);
ComServerClassFactory factory = new ComServerClassFactory();
bool isRegistered = CoRegisterClassObject(ref clsidComServer, factory, CLSCTX.LOCAL_SERVER, REGCLS.MULTIPLEUSE | REGCLS.SUSPENDED, out ClassId) == S_OK;
if(isRegistered)
{
isRegistered = CoResumeClassObjects() == S_OK;
}
return isRegistered;
}
public bool UnRegisterClassObject()
{
return ClassId == 0 || CoRevokeClassObject(ClassId) == S_OK;
}
public void Run()
{
while(IsServerRunning)
{
GC.Collect();
Thread.Sleep(2000);
}
ServerStopEvent.Set();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!disposed)
{
if(disposing)
{
UnRegisterClassObject();
if(HasConsole && !KeepConsole)
{
FreeConsole();
}
}
disposed = true;
}
}
}
}
COM-клиент:

Код: Выделить всё

int main(int argc, char *argv[])
{
try
{
HRESULT hr = CoInitializeEx(0, COINITBASE_MULTITHREADED);
if(!FAILED(hr))
{
IComServer* pComServer = NULL;
HRESULT hr = CoCreateInstance(CLSID_ComServer, NULL, CLSCTX_LOCAL_SERVER, IID_IComServer, (LPVOID*)&pComServer);
if(!FAILED(hr) &&  pComServer != NULL)
{
BSTR lpwszAssembly = SysAllocString(L"C:\\inetpub\\wwwroot\\forumengine\\ForumEngine.dll");
BSTR lpwszTypeName = SysAllocString(L"ForumEngine.ForumEngineUser");
hr = pComServer->LoadAssembly(lpwszAssembly);
if(!FAILED(hr))
{
IDispatch* pdisp = NULL;
hr = pComServer->CreateNetInstance(lpwszTypeName, &pdisp);
}
SysFreeString(lpwszAssembly);
SysFreeString(lpwszTypeName);
}
CoUninitialize();
}
}
catch(exception e)
{
OutputDebugStringA(e.what());
throw;
}
}
Записи реестра COM-сервера:

Код: Выделить всё

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{467e7566-bef4-4138-a619-035d3171afcf}\1.0
@ = NetComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{467e7566-bef4-4138-a619-035d3171afcf}\1.0\0\win64
@ = C:\inetpub\wwwroot\netcomserver\ComInprocServer\lib\NetComServer.tlb
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{467e7566-bef4-4138-a619-035d3171afcf}\1.0\FLAGS
@ = 8
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{467e7566-bef4-4138-a619-035d3171afcf}\1.0\HELPDIR
@ = C:\inetpub\wwwroot\netcomserver\ComInprocServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{e62a1cb0-86a7-40ae-afe4-75562c32a498
@ = IComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{e62a1cb0-86a7-40ae-afe4-75562c32a498}\ProxyStubClsid32
@ = {00020424-0000-0000-c000-000000000046}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{e62a1cb0-86a7-40ae-afe4-75562c32a498}\TypeLib
@ = {467e7566-bef4-4138-a619-035d3171afcf}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{e62a1cb0-86a7-40ae-afe4-75562c32a498}\TypeLib
Version = 1.0
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}
@ = NetComServer.ComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}
AppID = {c6819a04-046e-4ea2-9750-949760cb26f9}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}\LocalServer32
@ = C:\inetpub\wwwroot\netcomserver\ComLocalServer\ComLocalServer.exe
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}\ProgId
@ = NetComServer.ComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}\Version
@ = 1.0
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c6819a04-046e-4ea2-9750-949760cb26f9}\TypeLib
@ = {467e7566-bef4-4138-a619-035d3171afcf}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\NetComServer.ComServer
@ = NetComServer.ComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\NetComServer.ComServer\CLSID
@ = {c6819a04-046e-4ea2-9750-949760cb26f9}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{c6819a04-046e-4ea2-9750-949760cb26f9}
@ = NetComServer
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{c6819a04-046e-4ea2-9750-949760cb26f9}
AccessPermission =
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{c6819a04-046e-4ea2-9750-949760cb26f9}
LaunchPermission =
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{c6819a04-046e-4ea2-9750-949760cb26f9
RunAs = Interactive User
Разрешения DCOM:



Учетная запись
Разрешения




BUILTIN\Администраторы
локальный доступ, удаленный доступ, выполнение локально, выполнение удаленно, активация локально, активация удаленно


NT AUTHORITY\SYSTEM
локальный доступ, удаленный доступ, локальное выполнение, выполнить удаленно, активировать локально, активировать удаленно


САМ
локальный доступ, удаленно доступ, выполнение локально, выполнение удаленно, активация локально, активация удаленно


NT AUTHORITY\LocalService
локальный доступ, выполнение локально, активация локально


NT AUTHORITY\Interactive
локальный доступ, выполнение локально, активация локально


ВСТРОЕННЫЕ\Пользователи
локальный доступ, выполнить локально, активировать локально



Я тоже пробовал несколько раз вызывать CoCreateInstance и устанавливать ожидание потока локального сервера. Но это не дало никакого эффекта.

Есть идеи?

Подробнее здесь: https://stackoverflow.com/questions/790 ... -0x8008000

Вернуться в «C#»