Изображение Canon EDSDK MemoryStream

Я уже некоторое время борюсь с Canon EDSDK. Я могу успешно заставить библиотеку сохранять файл непосредственно на диск, однако я не могу получить изображение byte[] в памяти. Всякий раз, когда я пытаюсь выполнить Marshal.Copy() поток EDSDK в byte[], я всегда получаю следующую ошибку:

AccessViolationException: Попытка чтения или записи защищенной памяти. Часто это указывает на то, что другая память повреждена.

Ниже приведен один из вариантов кода, который я использовал, чтобы попытаться получить поток:

        private uint downloadImage(IntPtr directoryItem)
        {
            uint err = EDSDK.EDS_ERR_OK;
            IntPtr stream = IntPtr.Zero;

            // Get information of the directory item.
            EDSDK.EdsDirectoryItemInfo dirItemInfo;
            err = EDSDK.EdsGetDirectoryItemInfo(directoryItem, out dirItemInfo);

            // Create a file stream for receiving image.
            if (err == EDSDK.EDS_ERR_OK)
            {
                err = EDSDK.EdsCreateMemoryStream(dirItemInfo.Size, out stream);
            }

            //  Fill the stream with the resulting image
            if (err == EDSDK.EDS_ERR_OK)
            {
                err = EDSDK.EdsDownload(directoryItem, dirItemInfo.Size, stream);
            }

            //  Copy the stream to a byte[] and 
            if (err == EDSDK.EDS_ERR_OK)
            {
                byte[] buffer = new byte[dirItemInfo.Size];

                GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                // The following line is where it blows up...
                Marshal.Copy(stream, buffer, 0, (int)dirItemInfo.Size);

                // ... Image manipulation, show user, whatever
            }

            return err;
        }

Точки останова показывают (через объект EdsDirectoryItemInfo), что изображение действительно существует, я просто не знаю, почему я получаю исключение, которое я получаю. Я обдумывал идею смириться с поражением и просто считывал результирующий образ с диска, который он так охотно записывает с помощью метода CreateFileStream, но на самом деле я должен просто уметь манипулировать изображением в памяти.

Любые идеи?

ОБНОВЛЕНИЕ: я вижу такое поведение в обеих версиях 2.5 и 2.6.


person Wayne Hartman    schedule 05.07.2009    source источник
comment
Не могли бы вы опубликовать свой код (где-нибудь), чтобы загрузить изображение, которое вы только что записали на диск? Я даже не могу зайти так далеко. В частности, я не могу заставить его вызывать функцию обработчика событий объекта.   -  person andrewrk    schedule 29.07.2009


Ответы (2)


Я только что погуглил EdsCreateMemoryStream и нашел образец, в котором есть еще один звонок, чтобы получить указатель из "потока памяти".

IntPtr pointerToBytes;
EDSDKLib.EDSDK.EdsGetPointer(stream, out pointerToBytes);

Затем вы можете использовать pointerToBytes в качестве источника для чтения в Marshal.Copy.

Итак, я предполагаю, что вы сейчас пытаетесь скопировать большое количество байтов, начиная с адреса некоторой небольшой управляющей структуры, на которую указывает stream, и, следовательно, вы читаете дальше конца этой структуры.

Редактировать: Кстати, ваш код выглядит так, как будто кто-то сказал вам, что у вас должен быть только один оператор возврата! Это старый совет, относящийся к таким языкам, как Fortran и C; это не имеет смысла в современных языках. Ваш код был бы чище (по крайней мере, в этом случае), если бы вы немедленно возвращали код ошибки каждый раз, когда сталкивались с ошибкой:

if ((err = EDSDK.EdsBlahBlah(...)) != EDSDK.EDS_ERR_OK)
    return err;

(Еще лучше создать определенный класс исключения, содержащий код ошибки и строку, объясняющую, что вы пытались сделать.)

person Daniel Earwicker    schedule 05.07.2009
comment
Этот конкретный метод является всего лишь методом-оболочкой (причем тестовым) для EDSDK, что следует отметить. Я дам указатель, чтобы прочитать попытку, когда я вернусь домой. - person Wayne Hartman; 05.07.2009

Я понимаю, что это старый пост, но это полный фрагмент C# для загрузки из потока памяти. Это может быть полезно для кого-то еще. Для камеры необходимо установить значение EDSDK.EdsSaveTo.Host или EDSDK.EdsSaveTo.Both.

        uint error = EDSDK.EDS_ERR_OK;
        IntPtr stream = IntPtr.Zero;

        EDSDK.EdsDirectoryItemInfo directoryItemInfo;

        error = EDSDK.EdsGetDirectoryItemInfo(this.DirectoryItem, out directoryItemInfo);

        //create a file stream to accept the image
        if (error == EDSDK.EDS_ERR_OK)
        {
            error = EDSDK.EdsCreateMemoryStream(directoryItemInfo.Size, out stream);
        }


        //down load image
        if (error == EDSDK.EDS_ERR_OK)
        {
            error = EDSDK.EdsDownload(this.DirectoryItem, directoryItemInfo.Size, stream);
        }

        //complete download
        if (error == EDSDK.EDS_ERR_OK)
        {
            error = EDSDK.EdsDownloadComplete(this.DirectoryItem);
        }


        //convert to memory stream
        IntPtr pointer; //pointer to image stream
        EDSDK.EdsGetPointer(stream, out pointer);

        uint length = 0;
        EDSDK.EdsGetLength(stream, out length);

        byte[] bytes = new byte[length];

        //Move from unmanaged to managed code.
        Marshal.Copy(pointer, bytes, 0, bytes.Length);

        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes);
        Image image = System.Drawing.Image.FromStream(memoryStream);

        if (pointer != IntPtr.Zero)
        {
            EDSDK.EdsRelease(pointer);
            pointer = IntPtr.Zero;
        }


        if (this.DirectoryItem != IntPtr.Zero)
        {
            EDSDK.EdsRelease(this.DirectoryItem);
            this.DirectoryItem = IntPtr.Zero;
        }

        if (stream != IntPtr.Zero)
        {
            EDSDK.EdsRelease(stream);
            stream = IntPtr.Zero;
        }
person user1659191    schedule 27.09.2012