Tôi đang cố gắng để COM khởi động máy chủ .NET COM ngoài quy trình của mình. Nó hoạt động nếu quá trình máy chủ được biên dịch với x64, nhưng nếu tôi sử dụng AnyCPU (đó là những gì tôi muốn) thì nó treo trong một thời gian và cuối cùng thất bại với 0x80080005 (CO_E_SERVER_EXEC_FAILURE). Làm cách nào tôi có thể làm việc này?COM không thể bắt đầu quá trình xử lý. Máy chủ Net được biên dịch thành AnyCPU
- Tôi đang chạy trên máy tính 64 bit: Windows 7 có Visual Studio 2008 SP1.
- Tôi có thể thấy trong Trình quản lý tác vụ rằng nó khởi động máy chủ của tôi. Vì vậy, tôi đoán vấn đề là trong giao tiếp giữa COM và máy chủ (đăng ký lớp học).
- Ứng dụng khách thử nghiệm của tôi được viết bằng C#, nhưng không quan trọng liệu nó được biên dịch cho x86 hay x64. Vấn đề cũng xảy ra với một cái gì đó được viết bằng C++ 32-bit.
- Nếu tôi xây dựng lại máy chủ bằng cách sử dụng x64 và chạy nó, và sau đó xây dựng lại như AnyCPU, sau đó COM có thể khởi động nó. Việc khởi động lại sẽ đưa tôi trở lại tình huống ban đầu. Có lẽ COM không biết trước những gì bitness sẽ được sử dụng, và thực hiện trước đó sẽ giúp.
- Tôi đã tìm thấy Andy McMullen's blog post và đã thử chuyển CLSCTX_ACTIVATE_64_BIT_SERVER sang CoCreateInstance(), nhưng điều này gây ra lỗi trước đó: 0x80040154 (REGDB_E_CLASSNOTREG). Tôi có làm gì sai trong đăng ký COM không? Bạn có thể thấy bên dưới là nó rất đơn giản. Đăng ký xảy ra khi chạy trong 64 bit, và vấn đề xảy ra khi khách hàng là 64 bit, do đó, không nên tham gia Wow6432Node.
Một chap khác có số similar problem, nhưng câu trả lời MSFT khó hiểu. Dường như anh ta cho rằng nó chỉ có thể hoạt động thông qua DCOM (xem link) hoặc COM +. Tôi nghi ngờ hoặc sẽ là một công việc khủng khiếp, và tồi tệ hơn nhiều so với việc phân phối .exe của tôi được xây dựng như x64 và x86.
Bạn có thể thắc mắc tại sao tôi đang triển khai IPersistFile. Đó là bởi vì vấn đề thực sự của tôi là làm cho BindMoniker() làm việc từ một chương trình C++ 32 bit cho chương trình AnyCPU .Net của tôi. Tôi đã giảm vấn đề của mình xuống ví dụ đơn giản hơn được trình bày ở đây.
Đây là mã khách hàng:
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);
}
}
và đây là máy chủ:
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
}
Âm thanh như một cái gì đó trong thế giới AnyCPU được mặc định là x86, và nó sẽ chỉ mất một rogue để scupper toàn bộ điều. Tôi tưởng tượng rằng việc vượt qua CLSCTX_ACTIVATE_64_BIT_SERVER trong cuộc gọi kích hoạt của bạn sẽ không hoạt động trừ khi bạn cũng đã chuyển nó trong cuộc gọi đăng ký của bạn đến RegisterTypeForComClients.Và tôi nghi ngờ rằng việc xây dựng là x64 và chạy, sau đó xây dựng lại cho x86, hoạt động vì bạn đăng ký đối tượng lớp nhưng không hủy đăng ký đối tượng đó và vì vậy việc đăng ký vẫn tồn tại trong bảng đối tượng lớp chung. Tôi đã tìm thấy AnyCPU là một nỗi đau, và tôi chỉ sử dụng nó trong 100% dự án .NET (nghĩa là hầu như không bao giờ!) –
Cảm ơn @Ciaran, có lẽ nó đến COM không đủ thông minh để diễn giải cờ AnyCPU trong CLR .exe tiêu đề thông minh. Tôi đã thử vượt qua CLSCTX_ACTIVATE_64_BIT_SERVER để RegisterTypeForComClients, nhưng nó đã ném E_INVALIDARG. Tôi không ngạc nhiên bởi vì vào thời điểm tôi thực hiện cuộc gọi, tôi đã chạy 64 bit, chức năng này có thể dễ dàng xác định, vậy điều gì sẽ là điểm? –
Tôi đã xem qua các tài liệu tham khảo của bạn chi tiết hơn hôm nay và nó thực sự trông giống như có thứ gì đó bị hỏng trong cơ sở hạ tầng. Vì vậy, miễn cưỡng tôi kết luận rằng điều này chỉ là không làm việc cho bạn, và bạn sẽ chỉ phải từ bỏ AnyCPU. Tin tốt là một khi bạn đã từ bỏ sự dị giáo đó, bạn sẽ cảm thấy tốt hơn rất nhiều! –