Как передать ссылку на void * из C ++ / CLI в нативную функцию C - PullRequest
0 голосов
/ 03 апреля 2019

Я пытаюсь вызвать собственный API-интерфейс Windows из управляемого C ++ / CLI.Один из аргументов является недействительным **.Идея состоит в том, что функция будет выделять структуру памяти и возвращать пустую указатель вызывающей стороне, которая должна быть передана обратно в API при следующем вызове.Поэтому мне нужно выделить хранилище для указателя на управляемой стороне и передать ссылку на C API.Я не могу понять, как это сделать.

Я пытался объявить void * в вызывающей стороне и передать ссылку через различные операторы: &, internal_ptr <>, pin_ptr <>.Я сделал то же самое с IntPtr.Я получаю сообщения о том, что компилятор не может преобразовать это в пустоту **.

Вот одна попытка с использованием IntPtr и pin_ptr.Я получаю следующую ошибку компиляции в строке 28 (строка, которая объявляет pin_ptr):

E0144 значение типа "interior_ptr<System::IntPtr>" не может использоваться для инициализации объекта типа "cli::pin_ptr<void *>"

#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System;

namespace CLRStorage
{
    public ref class CompoundFile
    {
    private:
        String ^ pathname;
        IntPtr pRootStorage;
    public:
        CompoundFile CompoundFile::Create(String^ path)
        {
            STGOPTIONS stgOptions;
            stgOptions.usVersion = 1;
            stgOptions.reserved = 0;
            stgOptions.ulSectorSize = 4096;
            stgOptions.pwcsTemplateFile = NULL;

            auto cf = gcnew CompoundFile();
            cf->pathname = path;
            marshal_context^ context = gcnew marshal_context();
            pin_ptr<void*> ppRootStorage = &cf->pRootStorage;
            StgCreateStorageEx(
                context->marshal_as<WCHAR*>(path),
                STGM_READWRITE & STGM_CREATE,
                STGFMT_DOCFILE,
                0,
                &stgOptions,
                NULL,
                IID_IStorage,
                ppRootStorage);
        }
    };
}

1 Ответ

0 голосов
/ 03 апреля 2019

IntPtr можно преобразовать в void* и из него, но это не тот же тип.

Поскольку параметр является только внешним, простое решение заключается в использовании временного:

void* pRootStorage;
StgCreateStorageEx(
            context->marshal_as<WCHAR*>(path),
            STGM_READWRITE & STGM_CREATE,
            STGFMT_DOCFILE,
            0,
            &stgOptions,
            NULL,
            IID_IStorage,
            &pRootStorage);
cf->pRootStorage = IntPtr(pRootStorage);

На самом деле это будет немного быстрее, потому что пиннинг не требуется.

У вас также есть отдельная проблема с синтаксисом неверных функций-членов.Вы хотите

static CompoundFile^ Create(String^ path)

вместо

CompoundFile CompoundFile::Create(String^ path)

и не забудьте

return cf;

Тогда marshal_context не является ref class, поэтомуэта строка неверна:

marshal_context^ context = gcnew marshal_context();

Вместо этого используйте

marshal_context context;

и, поскольку это не указатель,

context.marshal_as<WCHAR*>(path)
...