質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

Q&A

解決済

3回答

4896閲覧

【Direct2D】BitmapをReleaseするときに強制終了してしまう【WIC】

aridai1221

総合スコア45

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

0グッド

0クリップ

投稿2016/07/03 10:47

編集2016/07/04 14:00

###前提・実現したいこと
Direct2Dで画像を読み込んで描画するという処理を書いています。
WICを利用して画像を読み込み、ID2D1Bitmapを生成して、
ID2D1HwndRenderTargetのdrawBitmapで描画する
といった感じで画像の描画はできました。
しかし、ID2D1BitmapのReleaseを行うときに強制終了してします。
なんとかして強制終了をさせずに終了させたいです。

###発生している問題・エラーメッセージ

例外がスローされました:読み取りアクセス違反。 this->wicImagingFactory-> が 0x6D211E90 でした。

###該当のソースコード
7/4更新
(実際はファイルを分けてコードを書いてあります。)

C++

1#include <d2d1.h> 2#include <wincodec.h> 3#include <map> 4 5#pragma comment(lib, "d2d1.lib") 6#pragma comment(lib, "dxguid.lib") 7#pragma comment(lib, "windowscodecs.lib") 8 9// ウィンドウの幅 10extern int WINDOW_WIDTH; 11 12// ウィンドウの高さ 13extern int WINDOW_HEIGHT; 14 15// アプリケーションのインスタンスハンドル 16extern HINSTANCE applicationInstance; 17 18// ウィンドウハンドル 19extern HWND windowHandle; 20 21// Direct2Dファクトリ 22ID2D1Factory*direct2DFactory = NULL; 23 24// レンダーターゲット 25ID2D1HwndRenderTarget* renderTarget = NULL; 26 27// ブラシ 28ID2D1SolidColorBrush* brush = NULL; 29 30// Direct2Dの初期化処理を行う 31void initializeDirect2D() 32{ 33 // Direct2Dファクトリを生成する 34 D2D1CreateFactory( 35 D2D1_FACTORY_TYPE_SINGLE_THREADED, 36 &direct2DFactory); 37 38 // レンダーターゲットを生成する 39 direct2DFactory->CreateHwndRenderTarget( 40 D2D1::RenderTargetProperties(), 41 D2D1::HwndRenderTargetProperties( 42 windowHandle, 43 D2D1::SizeU(WINDOW_WIDTH, WINDOW_HEIGHT)), 44 &renderTarget); 45 46 // ブラシを生成する 47 renderTarget->CreateSolidColorBrush(D2D1::ColorF(0, 0, 0), &brush); 48} 49 50// Direct2Dの終了処理を行う 51void finalizeDirect2D() 52{ 53 OutputDebugString("brushをReleaseします!\n"); 54 if (brush != NULL) 55 brush->Release(); 56 OutputDebugString("renderTargetをReleaseします!\n"); 57 if (renderTarget != NULL) 58 renderTarget->Release(); 59 OutputDebugString("direct2DFactoryをReleaseします!\n"); 60 if (direct2DFactory != NULL) 61 direct2DFactory->Release(); 62} 63 64class Image 65{ 66public: 67 Image(const wchar_t*); 68 ~Image(); 69 void draw(float x, float y); 70 71private: 72 IWICImagingFactory* wicImagingFactory = NULL; 73 IWICBitmapDecoder* wicBitmapDecoder = NULL; 74 IWICBitmapFrameDecode* wicBitmapFrame = NULL; 75 IWICFormatConverter* wicFormatConverter = NULL; 76 ID2D1Bitmap* bitmap = NULL; 77}; 78 79Image::Image(const wchar_t* fileName) 80{ 81 // WICイメージングファクトリを生成する 82 CoCreateInstance( 83 CLSID_WICImagingFactory, 84 NULL, 85 CLSCTX_INPROC_SERVER, 86 IID_IWICImagingFactory, 87 (LPVOID*)&wicImagingFactory); 88 89 // Bitmapデコーダを生成する 90 wicImagingFactory->CreateDecoderFromFilename( 91 fileName, 92 NULL, 93 GENERIC_READ, 94 WICDecodeMetadataCacheOnLoad, 95 &wicBitmapDecoder); 96 97 // 画像からフレームを読み込む 98 wicBitmapDecoder->GetFrame(0, &wicBitmapFrame); 99 100 // フォーマットコンバータを生成する 101 wicImagingFactory->CreateFormatConverter(&wicFormatConverter); 102 103 // コンバータの初期化をする 104 wicFormatConverter->Initialize( 105 wicBitmapFrame, 106 GUID_WICPixelFormat32bppPBGRA, 107 WICBitmapDitherTypeNone, 108 NULL, 109 0, 110 WICBitmapPaletteTypeCustom); 111 112 // Bitmapを生成する 113 renderTarget->CreateBitmapFromWicBitmap( 114 wicFormatConverter, 115 NULL, 116 &bitmap); 117} 118 119Image::~Image() 120{ 121 OutputDebugString("bitmapをReleaseします!\n"); 122 if (bitmap != NULL) 123 bitmap->Release(); 124 OutputDebugString("wicFormatConverterをReleaseします!\n"); 125 if (wicFormatConverter != NULL) 126 wicFormatConverter->Release(); 127 OutputDebugString("wicBitmapFrameをReleaseします!\n"); 128 if (wicBitmapFrame != NULL) 129 wicBitmapFrame->Release(); 130 OutputDebugString("wicBitmapDecoderをReleaseします!\n"); 131 if (wicBitmapDecoder != NULL) 132 wicBitmapDecoder->Release(); 133 OutputDebugString("wicImagingFactoryをReleaseします!\n"); 134 if (wicImagingFactory != NULL) 135 wicImagingFactory->Release(); 136} 137 138void Image::draw(float x, float y){}

C++

1int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 2{ 3 // ウィンドウを生成する 4 initializeWin32API(); 5 6 // Direct2Dの初期化処理を行う 7 initializeDirect2D(); 8 9 // DirectInputの初期化処理を行う 10 initializeDirectInput(); 11 12 Image* image = new Image(L"hoge.png"); 13 14 // 終了メッセージが送られるまでループする 15 while (checkMessage()) 16 { 17 beginRendering(); 18 19 clearScreen(1, 1, 1); 20 image->draw(0, 0); 21 22 endRendering(); 23 } 24 25 delete image; 26 27 // Direct2Dの終了処理を行う 28 finalizeDirect2D(); 29 30 // DirectInputの終了処理を行う 31 finalizeDirectInput(); 32 33 return 0; 34}

###試したこと
Release行う順番が良くないかと思い、
bitmapのReleaseを最初に行うように変更してみましたが、
アクセス違反が発生していました。

7/4追記
別のマシンでコンパイル・実行したところ
特に強制終了することなく動作しました。
マシンA … 最初に試したマシン => コンパイル・実行 => 実行時に強制終了
マシンB … 次に試したマシン => コンパイル・実行 => 異常なし
マシンC … その次に試したマシン => マシンAとマシンBでビルドしたexeを実行 => どちらも異常なし
マシンD … その後試したマシン => マシンAとマシンBでビルドしたexeを実行 => どちらも実行時に強制終了

その後マシンAを再起動させてもう一度コンパイル・実行したところ
実行時に強制終了してしまいました。

###補足情報(言語/FW/ツール等のバージョンなど)
Visual Studio Commnunity 2015
Direct2D (d2d1.h) (d2d1.lib) (dxguid.lib)
WIC (wincodec.h) (windowscodecs.lib)

マシンA (Windows 7 Ultimate x64)
マシンB (Windows 10 Pro x64)
マシンC (Windows 10 Home x86)
マシンD (Windows 7 Professional x64)

###解決策 (by catsforepawさん)
CoInitializeCoUninitializeを呼ぶようにする。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

提示されているコードでは判りませんね。COMオブジェクトは参照カウントでインスタンスの生存管理をしているのでReleaseの順番にはさほど厳密さは要求されませんし、最終的に必要なもの(bitmap)以外は使い終わった時点でReleaseしてしまっても問題ありません。

気になるのは、

例外がスローされました:読み取りアクセス違反。
this->wicImagingFactory-> が 0x6D211E90 でした。

このアドレスが異様に大きいように思います。32bit版でのユーザーアドレス空間は0~7FFFFFFFなので、ほぼ目一杯使っていることになりますが、実際にはアクセス違反でエラーになっています。
もしかしたら、どこかでポインタの値が書き換わってしまったのかもしれません。オブジェクトを作ったところとReleaseするところでポインタの値を表示させて、書き換わっていないかどうか調べた方が良さそうです。

投稿2016/07/03 21:43

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aridai1221

2016/07/04 06:25

回答ありがとうございます。 アドレスの値を出力させるようにして確認してみます。
aridai1221

2016/07/04 12:06

今調べてみました。 生成したときとReleaseするときとでは アドレスの値は書き換わっていないようです。
catsforepaw

2016/07/04 13:24

もしかして、CoInitialize/CoUninitialize を呼んでいなかったりします? それなしで各インターフェイスを作ってReleaseしようとすると確かに落ちます。COMコンポーネントを使う場合は、必ずプログラムの開始時(COMインターフェイス取得前)に`CoInitialize(NULL)`を呼び出し、終了時に`CoUninitialize()`を呼んでください。
aridai1221

2016/07/04 13:52

ありがとうございます! うまくいきました!
guest

0

こんにちは。

DirectXは触ったことがないので直接の回答はできないのですが、このように原因不明で落ちる時はコードを減らしていって、現象が発生する時としない時の境目を絞り込んでいくと結構バグが見つかります。

ご提示されたソースの場合なら、

①コンストラクタとデストラクタ以外の処理は全て中身をコメントアウトする
この時点で異常終了しないようなら、コメントアウトしたメソッドのどれかが原因ですので、1つ1つ潰していく。
②同様にコンストラクタの中身を最後の方から1つ1つコメントアウトする

という感じです。
手間はかかりますが、ほぼ必ず原因にたどり着けます。(コンパイラのバグでexeサイズが原因のようなケースでは中々大変ですが。)

投稿2016/07/04 12:50

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

そのソースだけじゃわからないけど,renderTarget より後に Image を破棄してませんか?

ID2D1Bitmap はデバイス (ID2D1RenderTarget) 依存リソースだから,
renderTarget より先に解放しないとまずいはず.

renderTarget の方を先に解放していたとすると,

(1) renderTarget->Release()

renderTarget から作成したデバイス依存リソース (bitmap など) が全部無効になる.

(2) Image::~Image

bitmap->Release() ← bitmap は既に無効になっているので二重解放エラーになる.

投稿2016/07/03 15:25

noocyte

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aridai1221

2016/07/03 19:15

回答ありがとうございます。 OutputDebugStringでRelease処理前に 「○○を解放します」という出力をするようにして確かめましたが、 ちゃんとrenderTargetより先にbitmapをReleaseしようとしています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問