佳能 EDSDK MemoryStream 图像

Way*_*man 2 c# dll unmanaged edsdk

我已经和 Canon EDSDK 斗争了一段时间了。我可以成功地让库将文件直接保存到磁盘,但是,我无法在内存中获取图像字节[]。每当我尝试将 EDSDK Stream Marshal.Copy() 到 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;
        }
Run Code Online (Sandbox Code Playgroud)

断点显示(通过 EdsDirectoryItemInfo 对象)图像确实存在,我只是不知道为什么我会得到这样的异常。我一直在考虑接受失败,只是从磁盘读取结果图像,它很容易通过 CreateFileStream 方法写入,但我真的应该能够在内存中操作图像。

有任何想法吗?

更新:我在 2.5 和 2.6 版本中都看到了这种行为。

Dan*_*ker 5

我刚刚搜索EdsCreateMemoryStream找到了一个示例,其中有另一个调用从“内存流”获取指针。

IntPtr pointerToBytes;
EDSDKLib.EDSDK.EdsGetPointer(stream, out pointerToBytes);
Run Code Online (Sandbox Code Playgroud)

然后您可以用作pointerToBytes从 in 中读取的源Marshal.Copy

所以我猜测您当前正在做的事情是尝试从 指向的一些小控制结构的地址开始复制大量字节stream,因此您正在读取该结构的末尾。

编辑:顺便说一句,您的代码看起来好像有人告诉您应该只有一个 return 语句!这是与 Fortran 和 C 等语言相关的旧建议;这在现代语言中没有意义。如果每次失败时立即返回错误代码,您的代码会更清晰(至少在本例中):

if ((err = EDSDK.EdsBlahBlah(...)) != EDSDK.EDS_ERR_OK)
    return err;
Run Code Online (Sandbox Code Playgroud)

(更好的是,抛出一个包含错误代码和解释您要执行的操作的字符串的特定异常类。)


use*_*191 5

我意识到这是一篇旧文章,但这是一个完整的 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;
        }
Run Code Online (Sandbox Code Playgroud)