Я пытаюсь заставить COM запустить мой внепроцессный COM-сервер .NET.Это работает, если серверный процесс скомпилирован с x64, но если я использую AnyCPU (что я и хочу), то он на некоторое время зависает и в конечном итоге дает сбой с 0x80080005 (CO_E_SERVER_EXEC_FAILURE).Как мне заставить это работать?
- Я работаю на 64-разрядной машине: Windows 7 с Visual Studio 2008 SP1.
- Я вижу в диспетчере задач, что он делаетзапустить мой сервер.Поэтому, я думаю, проблема в связи между COM и сервером (регистрация класса).
- Мое тестовое клиентское приложение написано на C #, но не имеет значения, скомпилировано ли оно для x86 или x64.Проблема также возникает с чем-то, написанным на 32-битном C ++.
- Если я перекомпилирую сервер с использованием x64 и запусту его, а затем перестрою обратно как AnyCPU, тогда COM сможет его запустить.Перезагрузка вернет меня к исходной ситуации.Возможно, COM заранее не знает, какая битность будет использоваться, и предыдущее выполнение помогает.
- Я нашел сообщение в блоге Энди Макмаллена и попытался передать CLSCTX_ACTIVATE_64_BIT_SERVER в CoCreateInstance (), ноэто вызывает ошибку раньше: 0x80040154 (REGDB_E_CLASSNOTREG).Я делаю что-то не так в своей регистрации COM?Ниже вы можете увидеть, что это очень просто.Регистрация происходит при работе в 64 битах, и проблема возникает, когда клиент 64 бит, поэтому Wow6432Node не должен быть задействован.
У другого главы была похожая проблема , ноответ MSFT сбивает с толку.Кажется, он предполагает, что он может работать только через DCOM (см. Ссылку) или COM +.Я подозреваю, что либо это будет ужасно много работы, и существенно хуже, чем распространение моего .exe, созданного как x64 и x86.
Вы можете быть удивлены, почему я реализую IPersistFile.Это потому, что моя настоящая проблема заключается в том, чтобы заставить BindMoniker () работать из 32-битной программы C ++ в моей программе AnyCPU .Net.Я сократил мою проблему до более простого примера, представленного здесь.
Вот код клиента:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
static extern object CoCreateInstance(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
CLSCTX dwClsContext,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);
[Flags]
enum CLSCTX : uint
{
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000,
}
private void Form1_Load(object sender, EventArgs e)
{
IPersistFile pf = (IPersistFile)CoCreateInstance(
new Guid("1984D314-FC8D-44bc-9146-8A13500666A6"),
null,
CLSCTX.CLSCTX_LOCAL_SERVER,
new Guid("0000010b-0000-0000-C000-000000000046")); // IPersistFile
pf.Load("c:\\bozo", 0);
}
}
, а вот сервер:
static class Program
{
[STAThread]
static void Main()
{
if (Environment.CommandLine.Contains("/reg")) {
RegistryKey cls = Registry.LocalMachine.CreateSubKey(String.Format(
"SOFTWARE\\Classes\\CLSID\\{0}", PersistFile.ClassID.ToString("B")));
cls.SetValue("InprocHandler32", "Ole32.dll");
RegistryKey ls32 = cls.CreateSubKey("LocalServer32");
ls32.SetValue(null, '"' + Application.ExecutablePath + '"');
ls32.SetValue("ServerExecutable", Application.ExecutablePath);
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
RegistrationServices reg = new RegistrationServices();
reg.RegisterTypeForComClients(
typeof(PersistFile),
RegistrationClassContext.LocalServer,
RegistrationConnectionType.MultipleUse);
Application.Run(new Form1());
}
}
[ComVisible(true),
Guid("1984D314-FC8D-44bc-9146-8A13500666A6"),
ClassInterface(ClassInterfaceType.None)]
public class PersistFile : IPersistFile
{
public static Guid ClassID
{
get
{
GuidAttribute a = (GuidAttribute)typeof(PersistFile).GetCustomAttributes(typeof(GuidAttribute), false)[0];
return new Guid(a.Value);
}
}
#region IPersistFile
public void GetClassID(out Guid pClassID)
{
MessageBox.Show("GetClassID");
pClassID = ClassID;
}
public int IsDirty()
{
MessageBox.Show("IsDirty");
return 1;
}
public void Load(string pszFileName, int dwMode)
{
MessageBox.Show(String.Format("Load {0}", pszFileName));
}
public void Save(string pszFileName, bool fRemember)
{
MessageBox.Show("Save");
throw new NotImplementedException();
}
public void SaveCompleted(string pszFileName)
{
MessageBox.Show("SaveCompleted");
throw new NotImplementedException();
}
public void GetCurFile(out string ppszFileName)
{
MessageBox.Show("GetCurFile");
throw new NotImplementedException();
}
#endregion
}