tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル繰り返しJpeg保存時にGDI+汎用エラー
記事No11428
投稿日: 2015/05/23(Sat) 16:48
投稿者Kobaちゃん
実験のため3万回繰り返しあるurlにアクセスし、取得したWeb画像を保存するソフトを作成しています。
約13000くらいで、「GDI+ で汎用エラーが発生しました。」が必ず出て、その後、繰り返しが完了
する3万回まで継続します。どなたか、ご教授お願いしたい。ソースコードは下記のとおりです。
※ネット上でもbmp.save実行時にGDI+エラーが出る報告が出ていますが参考にしていますがうまくい
きません。

1.動作環境:Win7(IE11)+VB2008

2.大まかな処理の流れ

(1)webCam(WebBrowser)にてurlにアクセスし画像を取得
(2)webCamのイメージをBitmapオブジェクトにコピー
(3)Bitmapをjpeg形式で保存 <-ここでエラー発生


3.ソースコード

    ・
    ・
  Me.webCam.Navigate(strUrl)
    ・
    ・
  'WebBrowserのサイズに合わせてBitmap生成
   webCam.Width = webCam.Document.Body.ScrollRectangle.Width   'WebBrowserのウィンドウサイズ(横)をWEBページの本文サイズにあわせる
   webCam.Height = webCam.Document.Body.ScrollRectangle.Height 'WebBrowserのウィンドウサイズ(縦)をWEBページの本文サイズにあわせる

   Dim bmp As New Bitmap(webCam.Width, webCam.Height)
   Dim gra As Graphics = Graphics.FromImage(bmp)  'BitmapのGraphicsを取得
   Dim hdc As IntPtr = gra.GetHdc       'BitmapのGraphicsのHdcを取得
   Dim web As IntPtr = _
       System.Runtime.InteropServices.Marshal.GetIUnknownForObject( _
       webCam.ActiveXInstance)          'WebBrowser(WEBページ)のオブジェクト取得

   Dim rect As Rectangle = New Rectangle(0, 0, bmp.Width, bmp.Height)
   OleDraw(web, pDVASPECT_CONTENT, hdc, rect)      'WebBrowser(WEBページ)のイメージをBitmapにコピー
   System.Runtime.InteropServices.Marshal.Release(web) 'WebBrowser(WEBページ)のオブジェクト使用終了
   gra.Dispose()  ' BitmapのGraphicsの使用終了

   ' Bitmapをjpeg形式で保存
   bmp.Save(pstrLogImgDir & "\" & strBmpFile, System.Drawing.Imaging.ImageFormat.Jpeg)
   ↑
 ここで、エラーが発生。(必ずではなく、約13000まではエラーなしです。 一度エラーが出ると終わりまで継続します)

[ツリー表示へ]
タイトルRe: 繰り返しJpeg保存時にGDI+汎用エラー
記事No11429
投稿日: 2015/05/24(Sun) 18:08
投稿者花ちゃん

>    ' Bitmapをjpeg形式で保存
>    bmp.Save(pstrLogImgDir & "\" & strBmpFile, System.Drawing.Imaging.ImageFormat.Jpeg)
>    ↑
>  ここで、エラーが発生。(必ずではなく、約13000まではエラーなしです。 一度エラーが出ると終わりまで継続します)

未確認ですが!
この後のコードが投稿されていませんが、bmp オブジェクトは、使い終わったら Dispose メソッドを
呼び出してリソースを解放しておられますか?
リソースを解放しても同様のエラーが発生しますか?

[ツリー表示へ]
タイトルRe^2: 繰り返しJpeg保存時にGDI+汎用エラー
記事No11430
投稿日: 2015/05/24(Sun) 22:27
投稿者Kobaちゃん
>
> 未確認ですが!
> この後のコードが投稿されていませんが、bmp オブジェクトは、使い終わったら Dispose メソッドを
> 呼び出してリソースを解放しておられますか?
> リソースを解放しても同様のエラーが発生しますか?

bmp.Dispose()
で開放しています。後半にコードを投稿しています。

1.一度起きると、VBを再起動してもだめで、Windowsの再起動が必要です。
  bmp = nothingは不要と思って入れていませんが、追加してやってみます。
  
2.当初はbmpオブジェクトを直接PictureBoxに代入した後bmp.saveで保存していました。
  タスクマネージャーで確認した結果、GDI+オブジェクトが増加していっていたので、bmpオブジェクト
  の直接PictureBox代入をやめて、jpgに保存した後、保存した画像をPictureBoxにLoadするようにしま
  した。GDI+オブジェクトは増加しなくなりましたが、エラーは解消しませんでした。


<<後半のコードは以下の通りです。>>

        '保存したファイルをロードする前に確認(ファイルサイズが小さければエラー)
        Dim fs As New FileInfo(pstrLogImgDir & "\" & strBmpFile)
        For i = 1 To 100
            If fs.Length >= Val(3000) Then Exit For
            Threading.Thread.Sleep(50)
            Application.DoEvents()
        Next
        If i >= 100 Then
      '100回チェックしてもファイルサイズが3000byteより小さければ読出しエラー
            GetCamCap = "Cam Img保存失敗"
            Exit Function
        End If
        
       '保存したファイルをWeb画像表示用PictureBox(picCamImg)にロードして表示
        picCamImg.SizeMode = PictureBoxSizeMode.AutoSize
        picCamImg.Load(pstrLogImgDir & "\" & strBmpFile)

        bmp.Dispose() <- 最後にオブジェクトを開放しています
        GetCamCap = "OK"
        Exit Function  

[ツリー表示へ]
タイトルRe^3: 繰り返しJpeg保存時にGDI+汎用エラー
記事No11431
投稿日: 2015/05/25(Mon) 17:39
投稿者花ちゃん
> bmp.Dispose()
> で開放しています。後半にコードを投稿しています。

>         If i >= 100 Then
>       '100回チェックしてもファイルサイズが3000byteより小さければ読出しエラー
>             GetCamCap = "Cam Img保存失敗"
>             Exit Function
>         End If

上記の場合はどこで、解放していますか?


>        
>        '保存したファイルをWeb画像表示用PictureBox(picCamImg)にロードして表示
>         picCamImg.SizeMode = PictureBoxSizeMode.AutoSize
>         picCamImg.Load(pstrLogImgDir & "\" & strBmpFile)

上記場合の解放しょりは?
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=16560
http://www.hanatyan.sakura.ne.jp/vb2005/vb2013picturebox01.htm

又、下記のような処理も好ましくありません、どのような問題が発生するかわかりません。
>             Threading.Thread.Sleep(50)
>             Application.DoEvents()


コードを投稿して頂くならこま切れのようなコードでなく事象の再現できるコードを投稿してください。
今回のように何回かに1回エラーが発生するような場合ならなおさら。

[ツリー表示へ]
タイトルRe^4: 繰り返しJpeg保存時にGDI+汎用エラー
記事No11432
投稿日: 2015/05/25(Mon) 20:06
投稿者Kobaちゃん
指摘頂いた項目を盛り込んで再トライしてみます。

> 上記の場合はどこで、解放していますか?
解放していませんでしたので追加しました。

        If i >= 100 Then
      '100回チェックしてもファイルサイズが3000byteより小さければ読出しエラー
            GetCamCap = "Cam Img保存失敗"
            bmp.Dispose()   <- 追加しました
            bmp = Nothing
            Exit Function
        End If

> 上記場合の解放しょりは?
紹介頂いたURLを参照して追加しました。
画像差替え前のPictureBox.Imageプロパティ値をDisposeする必要があるのを知りませんでした。
アドバイスありがとうございました。

        picCamImg.SizeMode = PictureBoxSizeMode.AutoSize  'BitmapをPictureBoxに表示
        Dim ImgOld As Bitmap = picCamImg.Image <- 差替え前のImageプロパティを取得
        picCamImg.Load(pstrLogImgDir & "\" & strBmpFile)
        If ImgOld IsNot Nothing Then
            ImgOld.Dispose() <- 差替え前のImageプロパティをDispose
            ImgOld = Nothing
        End If

> 又、下記のような処理も好ましくありません、どのような問題が発生するかわかりません。
> >             Threading.Thread.Sleep(50)
> >             Application.DoEvents()
MsgWaitForMultipleObjectsを使ったタイマーに変更します

> コードを投稿して頂くならこま切れのようなコードでなく事象の再現できるコードを投稿してください。
上記修正を加えて、下記コードで再トレイしています。長いコードですみません。

<GDI+エラーが発生するコード>
    'カメラ画像取得と保存
    Private Function GetCamCap(ByVal strUrl As String, ByVal strBmpFile As String) As String
        Dim i As Integer
        Const DEF_WEB_W As Long = 54    '初期WebBrowser幅
        Const DEF_WEB_H As Long = 44    '初期WebBrowser高さ
        Const WEB_UP_LIM As Long = 1000 'WebBrowser更新待ち

        On Error GoTo ErrExit

        pblnWebUpdate = False
        Me.webCam.Width = DEF_WEB_W
        Me.webCam.Height = DEF_WEB_H
        Me.webCam.Navigate(strUrl)  'カメラから画像を取得
        lblMsg.Visible = True
        Call WaitTim(20)

        For i = 1 To WEB_UP_LIM
            lblMsg.Text = "画像取得中 " & i.ToString & " / " & WEB_UP_LIM.ToString
            If pblnWebUpdate = True Then Exit For
            Call WaitTim(20)
            Me.Refresh()
        Next
        lblMsg.Visible = False
        If i >= WEB_UP_LIM Then
            GetCamCap = "NG(Web取得失敗)"
            Exit Function
        End If

        'WebBrowserのサイズに合わせてBitmap生成
        webCam.Width = webCam.Document.Body.ScrollRectangle.Width   'WebBrowser横サイズあわせ
        webCam.Height = webCam.Document.Body.ScrollRectangle.Height 'WebBrowser縦サイズあわせ

        Dim bmp As New Bitmap(webCam.Width, webCam.Height)
        Dim gra As Graphics = Graphics.FromImage(bmp)       'BitmapのGraphicsを取得
        Dim hdc As IntPtr = gra.GetHdc                      'BitmapのGraphicsのHdcを取得
        Dim web As IntPtr = _
            System.Runtime.InteropServices.Marshal.GetIUnknownForObject( _
            webCam.ActiveXInstance)              'WebBrowser(WEBページ)のオブジェクト取得

        Dim rect As Rectangle = New Rectangle(0, 0, bmp.Width, bmp.Height)
        OleDraw(web, pDVASPECT_CONTENT, hdc, rect)  'WebBrowserイメージをBitmapにコピー
        System.Runtime.InteropServices.Marshal.Release(web) 'WebBrowserのオブジェクト使用終了
        gra.Dispose()       ' BitmapのGraphicsの使用終了

        'Bitmapをjpg形式で保存()
        bmp.Save(pstrLogImgDir & "\" & strBmpFile, System.Drawing.Imaging.ImageFormat.Jpeg)
        bmp.Dispose()
        bmp = Nothing

        Dim fs As New FileInfo(pstrLogImgDir & "\" & strBmpFile)
        For i = 1 To 100
            If fs.Length >= Val(txtImgFileSize.Text) Then Exit For
            Call WaitTim(50)    '50msecタイマー(10msec単位でDoEvents実行)
        Next
        If i >= 100 Then
            GetCamCap = "Cam Img保存失敗"
            bmp.Dispose()
            bmp = Nothing
            Exit Function
        End If

        picCamImg.SizeMode = PictureBoxSizeMode.AutoSize  'BitmapをPictureBoxに表示
        Dim ImgOld As Bitmap = picCamImg.Image
        picCamImg.Load(pstrLogImgDir & "\" & strBmpFile)
        If ImgOld IsNot Nothing Then
            ImgOld.Dispose()
            ImgOld = Nothing
        End If

        GetCamCap = "OK"
        Call WaitTim(gWAIT_TIM)  'Waitタイマー
        Exit Function

ErrExit:
        GetCamCap = "NG(" & Err.Description & ")"
        If InStr(GetCamCap, "GDI+") <> 0 Then
            MsgBox("GDI+ で汎用エラーが発生しました。", MsgBoxStyle.Exclamation)
        End If
        If bmp IsNot Nothing Then
            bmp.Dispose()
            bmp = Nothing
        End If
        If ImgOld IsNot Nothing Then
            ImgOld.Dispose()
            ImgOld = Nothing
        End If

    End Function

[ツリー表示へ]
タイトルRe^5: 繰り返しJpeg保存時にGDI+汎用エラー
記事No11433
投稿日: 2015/05/26(Tue) 09:15
投稿者Kobaちゃん
前回の修正版(Re^4)のコードを実行してみました。若干改善されましたが、やはりエラーが出ます。
解放忘れを調べてみますが、私の知見では見つけきれそうにありません。
再度アドバイス頂ければ助かります。
※画像差替え前のPictureBox.Imageプロパティ値をDisposeするのが効いたようです。

      変更前                変更後
約13000回でエラー発生(実行8時間後) -> 約20000回でエラー発生(実行10時間後)

[ツリー表示へ]
タイトルRe^6: 繰り返しJpeg保存時にGDI+汎用エラー【解決】
記事No11434
投稿日: 2015/05/30(Sat) 10:43
投稿者Kobaちゃん
FAT32フォルダのファイル数上限を超えていたのが根本原因でした。
ファイルの保存数を制限した結果、解決しました。

Jpegファイル保存先をUSBメモリにしていましたが、このため、FAT32の最大ファイル数の制限を受けてい
ました。下記URLによるとファイル名が8.3形式だと65534個までですが、ファイル名を大文字小文字交じりで
45文字でしたので1ファイルで5エントリ使っていたようです。このため、保存数は約13000個が上限となって
いました。

hhttps://support.microsoft.com/de-ch/kb/436213/ja

※保存操作をビットマップオブジェクトのbmp.saveで行っていたので、保存ファイル上限エラーが「GDI+汎用
エラー」として出力されたようです。

[ツリー表示へ]
タイトルRe^7: 繰り返しJpeg保存時にGDI+汎用エラー【解決】
記事No11435
投稿日: 2015/06/01(Mon) 19:41
投稿者魔界の仮面弁士
本題とは関係の無いところに反応…


> https://support.microsoft.com/de-ch/kb/436213/ja

上記はスイスドイツ語版のサイトですね。(コンテンツは日本語ですが)
内容は同じですが、念のため下記の日本語版 URL を紹介しておきます。

https://support.microsoft.com/ja-jp/kb/436213/ja


(元の URL を開いたら、いきなりドイツ語のアンケートが表示されて焦りました…)

[ツリー表示へ]
タイトルRe^8: 繰り返しJpeg保存時にGDI+汎用エラー【解決】
記事No11439
投稿日: 2015/06/06(Sat) 09:17
投稿者Kobaちゃん
> 内容は同じですが、念のため下記の日本語版 URL を紹介しておきます。
> hhttps://support.microsoft.com/ja-jp/kb/436213/ja

魔界の仮面弁士さんお騒がせしました。
And フォローありがとうございました。 

[ツリー表示へ]