В каких случаях параметры должны быть закреплены при выполнении вызова P / Invoke - PullRequest
2 голосов
/ 08 марта 2012

У меня есть DLL, из которой мне нужно P / Invoke следующий метод C:

int DAOpen(HANDLE *hOpen, UNIT *flags, void *callback, char *userData)

Я придумал следующую подпись C #:

[DllImportAttribute("<libName>", EntryPoint="DAOpen")]  
    static extern  int DAOpen(  
    out IntPtr hOpen,  
    ref uint flags,  
    IntPtr callback,  
    IntPtr userData);

Предполагая, что собственный код сохраняет ссылку на все параметры дольше, чем продолжительность вызова P / Invoke:

  1. Помимо хранения экземпляра hOpen, я должен также прикрепить его?

  2. Должен ли я сохранить ссылку на переменную flags? Должен ли я также прикрепить его, поскольку он передается в качестве ссылки в данном конкретном случае?

  3. Я назначаю своего callback делегата следующим образом:

    private IntPtr callBackOnNativeEvents;
    ...
    this.callBackOnNativeEvents = Marshal.GetFunctionPointerForDelegate(
    new CallBack(this.CallBackOnNativeEvents));

    Должен ли я хранить ссылку на делегат внутри себя (не только указатель)? Должен ли я также прикрепить его?

  4. Наконец, я определяю параметр userData следующим образом:

    private IntPtr userData;
    ...
    string userName = "test";
    this.userData = Marshal.StringToHGlobalAnsi(userName);

    Должен ли я сохранить ссылку на строку? Должен ли я также закрепить это? В документации API говорится, что он копирует содержимое строки в неуправляемую память, но я не уверен, копирует ли он содержимое ссылки.

1 Ответ

2 голосов
/ 08 марта 2012
  1. Нет необходимости закреплять hOpen, он имеет семантику типа значения.
  2. Если DLL выполняет запись по адресу, указанному flags, и делает это после возврата исходной функции, тогдавам необходимо закрепить его тем или иным образом (а также сохранить его в целости и сохранности из муфт ГХ).
  3. Указатель функции обратного вызова уже эффективно закреплен.Вам нужно сохранить ссылку на делегата в действии, но вам не нужно его закреплять, потому что собственный thunk выделен из неуправляемой кучи .
  4. Вам не нужно делатьничего особенного, потому что вы передаете IntPtr, а память за ним закреплена.Вам не нужно поддерживать ссылку на строку в живых, потому что она полностью отключена от IntPtr, возвращаемого StringToHGlobalAnsi.У него просто есть копия содержимого строки в точке вызова StringToHGlobalAnsi.

Я должен сказать, что я все еще не уверен, что эта DLL действительно может делать то, что вы говоритеделается.Я подозреваю, что что-то еще идет не так, что вы неправильно диагностируете, поскольку DLL удерживает параметры указателя в одном вызове, а затем изменяет их содержимое во время последующих вызовов.Мне очень трудно в это поверить, но, конечно, только вы можете знать.Если бы я был на вашем месте, я бы просто задал вопрос поставщику DLL.

...