2009-07-05 30 views
2

我一直在與佳能EDSDK戰鬥了一段時間。我可以成功地讓庫將文件直接保存到磁盤,但是,我無法在內存中保留圖像byte []。每當我試圖Marshal.Copy()的EDSDK流爲byte [],我總是得到以下錯誤:佳能EDSDK MemoryStream圖片

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中看到此行爲。

+0

你介意張貼代碼(的地方),下載您只是把磁盤的圖片?我甚至無法達到這個目標。具體來說,我不能讓它調用我的對象事件處理函數。 – andrewrk 2009-07-29 01:05:58

回答

4

我剛剛搜索了EdsCreateMemoryStreamfound a sample,其中有另一個調用從「內存流」獲取指針。

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; 

(更重要的是,拋出一個特定的異常類含有錯誤代碼和一個字符串,解釋你試圖做什麼。)

+0

對於EDSDK,這個特殊的方法只是一個包裝器方法(測試之一),所以請注意。當我回家時,我會給指針讀一下。 – 2009-07-05 14:26:28

3

我意識到這是一箇舊的帖子,但這是一個完整的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; 
     } 
相關問題