2012-02-16 23 views
8

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 
} 
+1

Â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ờ!) –

+1

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? –

+2

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! –

Trả lời

1

Cố gắng sử dụng lớp RegistrationServices đăng ký lắp ráp com của bạn. Nó cũng sẽ chọn các đường dẫn đăng ký chính xác và thực hiện một số việc khác.

Ví dụ:

Assembly currentAssembly = Assembly.GetExecutingAssembly(); 
System.Runtime.InteropServices.RegistrationServices regAsm = new System.Runtime.InteropServices.RegistrationServices(); 
bool isRegistered = regAsm.RegisterAssembly(currentAssembly, System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase); 

Ngoài ra tôi nghĩ, đó là cụm NET khách hàng có một số rắc rối theo NET com máy chủ, nhưng tôi không thể tìm thấy bất kỳ tài nguyên cho nó ...

Hope , nó sẽ giúp ...

+0

Tôi đã sử dụng RegistrationServices để đăng ký lớp thực hiện IPersistFile (xem câu hỏi). Khi tôi đọc nó, RegisterAssembly() đăng ký * mọi lớp * COM được kích hoạt trong assembly, nhưng tôi không thấy cách đăng ký đó sẽ khác nhau (chỉ các tên lớp). Tuy nhiên tôi sẽ thử nó và đăng lại. –

+0

Thật không may là nó không giúp được gì. –

+0

Hmm, xin lỗi vì điều này. –

1

Tôi đoán vấn đề là vào thời gian chạy. Tôi đã tạo ra một máy chủ COM mà đăng ký bằng cách sử dụng một thư viện C + + (đăng ký được thực hiện hoàn hảo). Tôi đã gặp sự cố khi chuyển sang AnyCPU từ .NET (CS).

Kiến trúc:

  • Thư viện C++ interfacing COM (xây dựng trên cả hai nền tảng x64 và x86)
  • NET thư viện wrapper (CS) (instantiates một cách chính xác các yêu cầu x64/x86 C++ thư viện)
  • Ứng dụng .NET (CS) - máy khách COM hoặc máy chủ COM

Điều xấu xí xảy ra khi đăng ký ứng dụng .NET được xây dựng là "AnyCPU". Khi COM Client gọi COM Server thông qua DCOM, ứng dụng máy chủ khởi động nhưng máy khách nhận được lỗi rằng COM Server không thể khởi động được.

tôi đã đi một số bước tiếp theo, phân tích dữ liệu đăng ký với ProcMon và các công cụ khác và tôi đi đến kết luận giống nhau:

  • x86 đăng ký các lớp trong LỚP \ Wow6432Node
  • x64 và AnyCPU đăng ký các lớp học trong các lớp (trên máy tính Windows x64, chính xác các phím tương tự; tôi đặt cược rằng x86 và AnyCPU sẽ đăng ký giống nhau trên máy x86)

Bây giờ, tôi đã thực hiện thêm một số thử nghiệm: x86/x64/AnyCPU COM Client có thể kết nối không có vấn đề gì với bất kỳ x86/x64 COM Server nhưng nó không thể kết nối dù sao đi nữa đến một AnyCPU COM Server ...

tôi sau đó thực hiện các trường hợp kiểm tra sau:

  1. Có Server đăng ký x86 COM, thay thế các thực thi với AnyCPU COM Máy chủ: COM Client đã bắt đầu máy chủ COM x86, nhưng không có liên lạc ... nó đã bắt đầu lại từ máy chủ ..
  2. Đăng ký Máy chủ COM x64, thay thế tệp thi hành bằng Máy chủ COM AnyCPU: COM Client cũ bắt đầu máy chủ COM x64, nhưng không có thông tin liên lạc ... nó đã bắt đầu lại nhiều lần máy chủ ..
  3. Hav e Đăng ký máy chủ COM AnyCPU, thay thế tệp thực thi bằng máy chủ COM x86: COM Client có thể khởi động thành công và kết nối với máy chủ COM x86.
  4. Đăng ký máy chủ COM AnyCPU, thay thế tệp thực thi bằng máy chủ COM x64: COM Client có thể khởi động thành công và kết nối với máy chủ COM x64.
  5. Đăng ký máy chủ COM x86, thay thế tệp thực thi bằng máy chủ COM x64: COM Client có thể khởi động thành công và kết nối với máy chủ COM x64.
  6. Đăng ký máy chủ COM x64, thay thế tệp thực thi bằng máy chủ COM x86: COM Client có thể khởi động thành công và kết nối với máy chủ COM x86.

Trường hợp địa ngục là vấn đề liên lạc ở đâu? Điều này rất kỳ quặc ... Không có giải pháp nào được trình bày (CLSCTX_ACTIVATE_64_BIT_SERVER, PreferredServerBitness hoặc corflags) đã giúp.

Bất kỳ ai khác đã thực hiện một số tiến bộ về vấn đề này? Chúng ta có nên liên hệ với Microsoft không?

+0

Tôi đã kết luận rằng cách duy nhất để chuyển tiếp cho kịch bản .Net của tôi là phân phối hai tệp nhị phân (x86, x64), nếu tôi muốn giải quyết vấn đề. Sẽ rất thú vị khi hỏi Microsoft. –

Các vấn đề liên quan