2015-12-16 1 views
0

Я пытаюсь проверить, что класс, который я пытаюсь использовать через COM, работает, как ожидалось. К сожалению, кажется, чтобы преуспеть на вызов, который должен FAIL:Функция вызова из класса ComImport не работает, как ожидалось

enum X509CertificateEnrollmentContext 
{ 
    ContextUser = 0x1, 
    ContextMachine = 0x2, 
    ContextAdministratorForceMachine = 0x3 
} 

[ComImport(), Guid("884e2045-217d-11da-b2a4-000e7bbb2b09")] 
class Cenroll { } 

[Guid("728ab35d-217d-11da-b2a4-000e7bbb2b09")] 
interface IX509CertificateRequestCmc2 
{ 
    void InitializeFromTemplate(
     [In] X509CertificateEnrollmentContext Context, 
     [In] IX509EnrollmentPolicyServer pPolicyServer, 
     [In] IX509CertificateTemplate pTemplate); 
} 

static void Main(string[] args) 
{ 
    var cr = new Cenroll(); 
    var cmc2 = (IX509CertificateRequestCmc2)cr; 
    cmc2.InitializeFromTemplate(X509CertificateEnrollmentContext.ContextUser, null, null); 
} 

Отливки из Cenroll к интерфейсным работ, что свидетельствует о том, что идентификаторы GUID в порядке. (и он не выполняет литье других гидов, так что это не случайный успех)

Но когда я звоню InitializeFromTemplate, оба параметра установлены на null, он преуспевает. documentation говорит, что результат должен быть E_POINTER ошибка:

Return code - Description 
E_POINTER - The pPolicyServer and pTemplate parameters cannot be NULL. 

Так почему же я не вижу исключение?

ответ

3

Проблема в том, что вы обновляете интерфейс, а новое определение отличается от оригинала.

Гиды в порядке, но ниже, QueryInterface реализация проверяет GUID и возвращает указатель на реализацию - это интерфейс vtable и адреса метода вычисляются относительно этого адреса (когда компиляция вызова метода, смещение этот метод добавляется к этому адресу, чтобы получить адрес активации).

В вашей реализации InitializeFromTemplate - это первый метод, и сгенерированный клиентский код вызывает метод в начале vtable.

Однако в оригинальном интерфейсе, есть 56 других методов до InitializeFromTemplate, потому что есть цепочка наследования:

IX509CertificateRequest (25 methods) 
| 
+-> IX509CertificateRequestPkcs7 (8 methods) 
    | 
    +-> IX509CertificateRequestCmc (23 methods) 
     | 
     +-> IX509CertificateRequestCmc2 

Функциональные адреса в certenroll.dll придерживаться этой схемы, так что, когда вы звоните InitializeFromTemplate, как объявленный в вашем интерфейсе, вы вызываете первый метод в цепочке, который на самом деле IX509CertificateRequest::Initialize.

В качестве эксперимента, если добавить 56 фиктивных методы, прежде чем InitializeFromTemplate в вашей IX509CertificateRequestCmc2 вы правильно получить исключение:

[Guid("728ab35d-217d-11da-b2a4-000e7bbb2b09")] 
interface IX509CertificateRequestCmc 
{ 
    void fn1(); 
    void fn2(); 
    ... 
    void fn56(); 
    void InitializeFromTemplate(...); 
} 

Вызов отбросит: CertEnroll::CX509CertificateRequestCmc::InitializeFromTemplate: Invalid pointer 0x80004003 (-2147467261)

Конечно, решение не является для добавления фиктивных методов :) Вы должны использовать созданные типы взаимодействия, а не предоставлять свои собственные. Поскольку вы ссылаетесь на сборку certenroll, я не понимаю, почему вы просто не используете эти сгенерированные классы взаимодействия. Вот полный пример, который ведет себя, как и ожидалось:

using CERTENROLLLib; 

namespace comcerttest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // If you are embedding the interop types, note that you must 
      // remove the `Class` suffix from generated type name in order 
      // to instantiate it. See link at the bottom for explanation: 
      var cr = new CX509CertificateRequestCmc(); 
      var cmc2 = (IX509CertificateRequestCmc2)cr; 
      cmc2.InitializeFromTemplate(X509CertificateEnrollmentContext.ContextUser, null, null); 
     } 
    } 
} 

Проблема с использованием класса против типа интерфейса объясняется здесь: Using embedded interop types

+0

Спасибо, что действительно решает этот вопрос! Почему я не использовал созданные классы взаимодействия: документация настолько плоха, что мне потребовалось несколько дней, чтобы понять, что я могу. И это после выяснения xenroll-vs-certenroll, использования COM и т. Д. – viraptor

+0

Это может быть сложно, это правда :) –