2

私はキヤノンEDSDKとしばらく戦っています。ライブラリにファイルを直接ディスクに保存させることはできますが、イメージbyte[]をメモリに保持することはできません。EDSDKストリームをbyte[]にMarshal.Copy()しようとすると、常に次のエラーが発生します。

AccessViolationException:保護されたメモリの読み取りまたは書き込みを試みました。これは多くの場合、他のメモリが破損していることを示しています。

以下は、ストリームを取得するために使用したコードのバリエーションの1つです。

        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の両方でこの動作が見られます。

4

2 に答える 2

4

グーグルでEdsCreateMemoryStream検索したところ、「メモリストリーム」からポインタを取得するための別の呼び出しがあるサンプルが見つかりました。

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

pointerToBytesその後、で読み取るためのソースとして使用できますMarshal.Copy

したがって、現在行っているのは、が指す小さな制御構造のアドレスから始まる多数のバイトをコピーしようとしていることだと思いますstream。したがって、その構造の終わりを超えて読んでいます。

編集:ちなみに、あなたのコードは、誰かがあなたにreturnステートメントを1つだけ持つべきだと言ったかのように見えます!これは、FortranやCなどの言語に関する古いアドバイスです。現代語では意味がありません。失敗するたびにエラーコードをすぐに返すと、コードは(少なくともこの場合は)より明確になります。

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

(さらに良いことに、エラーコードと何をしようとしていたかを説明する文字列を含む特定の例外クラスをスローします。)

于 2009-07-05T08:34:44.740 に答える
4

これは古い投稿だと思いますが、これはメモリストリームからダウンロードするための完全な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;
        }
于 2012-09-27T00:49:46.077 に答える