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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

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

DirectX

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

Q&A

解決済

2回答

3208閲覧

【C#】画像がロードできない【Direct2D】

aridai1221

総合スコア45

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

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

DirectX

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

0グッド

0クリップ

投稿2016/07/07 08:40

編集2016/07/08 01:25

###前提・実現したいこと
Direct2D (Windows Imaging Component利用) で
画像を読み込む処理を行う関数をDLL化して
C#側でDllImportして利用したいです。

###発生している問題・エラーメッセージ
画像を読み込むことができませんでした。
また、AccessViolationException も発生しました。

###該当のソースコード

C++

1bool init() 2{ 3 // COMを初期化する 4 HRESULT result = CoInitializeEx(NULL, /*COINIT_MULTITHREADED*/COINIT_APARTMENTTHREADED); 5 6 // WICイメージングファクトリを生成する 7 result = CoCreateInstance( 8 CLSID_WICImagingFactory, 9 NULL, 10 CLSCTX_INPROC_SERVER, 11 IID_IWICImagingFactory, 12 (LPVOID*)&wicImagingFactory); 13 14 // いろいろと省略してます! 15} 16 17int loadImage(const wchar_t* fileName) 18{ 19 IWICBitmapDecoder* wicBitmapDecoder = NULL; 20 IWICBitmapFrameDecode* wicBitmapFrame = NULL; 21 IWICFormatConverter* wicFormatConverter = NULL; 22 ID2D1Bitmap* bitmap = NULL; 23 24 // Bitmapデコーダを生成する 25 HRESULT result = wicImagingFactory->CreateDecoderFromFilename( 26 fileName, 27 NULL, 28 GENERIC_READ, 29 WICDecodeMetadataCacheOnLoad, 30 &wicBitmapDecoder); 31 32 // 画像からフレームを読み込む 33 result = wicBitmapDecoder->GetFrame(0, &wicBitmapFrame); 34 35 // フォーマットコンバータを生成する 36 result = wicImagingFactory->CreateFormatConverter(&wicFormatConverter); 37 38 // コンバータの初期化をする 39 result = wicFormatConverter->Initialize( 40 wicBitmapFrame, 41 GUID_WICPixelFormat32bppPBGRA, 42 WICBitmapDitherTypeNone, 43 NULL, 44 0, 45 WICBitmapPaletteTypeCustom); 46 47 // Bitmapを生成する 48 result = renderTarget->CreateBitmapFromWicBitmap( 49 wicFormatConverter, 50 NULL, 51 &bitmap); 52 53 // いろいろと省略してます! 54 // ちなみに読み込まれたbitmapはC++側でコレクションに保持されて 55 // 認識番号をつけてその認識番号を返すような実装にしています! 56}

C#

1using System.Runtime.InteropServices; 2 3static class Hoge 4{ 5 6 // 原因は不明だが、CallingConvention.Cdeclはつけないとデバッグビルド時にエラーが起こる (こちらの方も教えてくれたら嬉しいです!) 7 [DllImport("Native.dll", CallingConvention = CallingConvention.Cdecl)] 8 public static extern int loadImage(string fileName); 9}

###試したこと
COMの設定が悪いと思ったので
CoIntializeEX関数の第2引数を変えてみたり、
C#のMain関数に
[STAThread] をつけたり消したりしましたが、
例外が発生したり
例外が発生しなかったものの読み込みができていなかったりしました。

7/8追記
こちらCoInitializeは不要であるようなことが書かれていたので
CoInitializeを呼ばずに実行してみましたが、
やはりダメでした。
また、wicImaginigFactoryはNULLではなかったので
COM関係では問題ないようですが、
Bitmapデコーダの生成では
HRESULTがS_OKでなかったようなのでここで失敗しているようです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

P/Invoke と Win32 API の両方で文字コードの罠にはまった話 によると、DllImport のデフォルトは CharSet.Ansi だそうです。したがって、wchar_t* を要求する関数に ANSI 文字列を渡していることになります。

ここでは CharSet.Auto を推奨されていますが、CharSet.Unicode を指定してみてください。

投稿2016/07/08 06:25

Zuishin

総合スコア28656

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

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

aridai1221

2016/07/08 06:28

解決しました!! ありがとうございます!!
guest

0

C++の関数をDLLでエクスポートするには、コンパイラーにその旨を教える必要があります。

int loadImage(const wchar_t* fileName)

この部分を

C++

1extern "C" __declspec(dllexport) int __stdcall loadImage(const wchar_t* fileName)

このようにしてみてください。
C++の関数をDLLにしてC#でDllImportしたい場合はextern "C"__declspec(dllexport)は必須です。DEFファイルに書いてリンカーに渡すという方法もありますが、面倒くさいのでお勧めはできません。
また、__stdcallを付けると、C#側のDllImport属性CallingConvention = CallingConvention.Cdeclが不要になります。

投稿2016/07/07 09:47

catsforepaw

総合スコア5938

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

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

aridai1221

2016/07/07 10:58

回答ありがとうございます。 ヘッダファイル側には extern "C"と__declspec(dllexport)は書いてあります。 __stdcallは知りませんでした。参考にさせていただきます。
catsforepaw

2016/07/07 11:26

そうでしたか。問題は別のところようですね。 提示されているソースだけでは原因は判りません。C++単体での動作は正しく行えているのでしょうか? 各メソッドの戻り値を捨てていますが、エラーチェックはした方が良いです。
catsforepaw

2016/07/07 14:22

リンク先を見てみましたが、よく判りません。実際に動かしながらデバッグしないと無理そうです。 一つ気になるところがあります。DLL内のinitializeDirect2D/finalizeDirect2D関数でそれぞれCoInitialize/CoUninitializeを呼んでいますが、それは得策ではありません。まともにやろうとすると戻り値をきっちりとハンドリングしないと思わぬトラブルを起こします。DLL内では呼ばずに、C#側でMainに[STAThread]などを付けるようにしてください(フォームアプリの場合は自動で付きます)。
aridai1221

2016/07/07 19:23 編集

ありがとうございます。 > DLL内では呼ばずに これは CoInitialize のことですか?
catsforepaw

2016/07/08 01:48

> これは CoInitialize のことですか? そうです。
aridai1221

2016/07/08 06:09 編集

[DllImport("ole32.dll")] public static extern int CoInitialize(IntPtr pvReserved); のようにDllImportを書き、 CoInitialize(IntPtr.Zero); を呼びましたが、画像のロードが失敗しました。
catsforepaw

2016/07/08 06:25

そうではなくて、CoInitialize呼び出しに関しては、C#のMainメソッドに[STAThread]と付けることでMainメソッドの実行時にC#が内部的にCoInitializeを呼んでいるので、C++側では不要ということです。紛らわしい書き方になっててすみません。
aridai1221

2016/07/08 06:45 編集

なるほど、内部的なことだったのですね。 [STAThread] ってそんなこともしてくれているのですね。 ありがとうございました。 :)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問