Изображение потока памяти Canon EDSDK
Вопрос
Я уже некоторое время сражаюсь с Canon EDSDK.Я могу успешно заставить библиотеку сохранять файл непосредственно на диск, однако я не могу получить доступ к байту изображения [] в памяти.Всякий раз, когда я пытаюсь выполнить маршалирование.Скопируйте() поток 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.
Решение
Я только что погуглил для EdsCreateMemoryStream
и найден образец в котором есть еще один вызов для получения указателя из "потока памяти".
IntPtr pointerToBytes;
EDSDKLib.EDSDK.EdsGetPointer(stream, out pointerToBytes);
Затем вы можете использовать pointerToBytes
в качестве источника для чтения в Marshal.Copy
.
Итак, я бы предположил, что то, что вы сейчас делаете, пытается скопировать некоторое большое количество байтов, начиная с адреса некоторой небольшой управляющей структуры, на которую указывает stream
, и, следовательно, вы читаете дальше конца этой структуры.
Редактировать: Кстати, ваш код выглядит так, как будто кто-то сказал вам, что у вас должен быть только один оператор return!Это старый совет, относящийся к таким языкам, как Fortran и C;это не имеет смысла в современных языках.Ваш код был бы понятнее (по крайней мере, в этом случае), если бы вы немедленно возвращали код ошибки каждый раз, когда получали сбой:
if ((err = EDSDK.EdsBlahBlah(...)) != EDSDK.EDS_ERR_OK)
return err;
(А еще лучше, создайте определенный класс исключений, содержащий код ошибки и строку, объясняющую, что вы пытались сделать.)
Другие советы
Я понимаю, что это старый пост, но это полный фрагмент C # для загрузки из потока памяти.Это может быть полезно для кого-то другого.Камера должна быть настроена на EDSDK.EdsSaveTo.Хост или EDSDK.EdsSaveTo.Оба
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;
}