DLLを呼び出すとLabVIEWがクラッシュして例外0xc0000005が発生する

更新しました Aug 18, 2023

使用製品

ソフトウェア

  • LabVIEW

問題

  • DLLを呼び出すとLabVIEWがクラッシュして、メモリアクセス違反が発生したというエラーメッセージが表示されます(例外コード: 0xc0000005)。
  • LabVIEWを32ビット版から64ビット版に変更しました。それにより、アプリケーションがランダムにクラッシュしして例外コード(0xc0000005)が発生します。

解決策

DLL関数を呼び出す際にLabVIEWがクラッシュするいくつかの理由があり、それを防ぐ方法を下記にリストしています。

1. DLLと同じ呼び出し規約を使用していることを確認する
ライブラリ関数呼び出しノードの呼び出し規約がDLLの呼び出し規約と一致しない場合、クラッシュが発生します。呼び出し規約は、以下に示すように、ライブラリ関数呼び出しノードウィンドウの右下で指定します。
 

 

2. ライブラリ関数呼び出しノードのすべての入力と出力を配線していることを確認する
ライブラリ関数呼び出しノードの入出力のすべてを配線しないと、DLL関数は割り当てられていないメモリを上書きし、LabVIEWをクラッシュさせます。

メモ: 2番目の入力が最初の入力へのポインタである場合、最初の入力は出力を必要としません。


3. DLL関数がLabVIEWメモリを上書きしていないことを確認する
十分なメモリが割り当てられていない場合、またはDLL関数が割り当て済みより多くの書き込みをおこなった場合、DLLは予約済みのLabVIEWメモリ空間を上書きし、LabVIEWをクラッシュさせます。DLLから配列、文字列、または波形を渡して読み取る前に、メモリが適切に割り当てられていることを確認します。


4. LabVIEWが予期している形式で関数にパラメータを渡していることを確認してください
間違ったパラメータのデータタイプ(値、参照、ハンドルなど)でLabVIEWからDLL関数を呼び出すと、関数が間違ったメモリ位置を意図せずに指定することがあり、データやLabVIEWやWindowsのクラッシュが発生する可能性があります。


5. 関数呼び出し自体が不適切である
関数が不適切な操作を実行しようとすると、LabVIEWがクラッシュする可能性があります。関数の作成者でない場合は、関数の作者に問い合わせてください。

追加情報

  1. Cの呼び出し規約を使用する場合、呼び出し元はスタックをクリーンアップする必要があります。標準の呼び出し規約を使用する場合、呼び出された関数はスタックのクリーンアップを行います。呼び出し元(LabVIEW)と呼び出されたDLL関数が同じ呼び出し規約を使用していない場合は、スタックから取り除かれるか、どちらも実行されません。いずれの状況でも、呼び出された関数が復帰したときにLabVIEWがクラッシュする可能性があります。
  2. 入力を配線しないと、DLL関数は割り当てられていないメモリを上書きします。出力を配線しない場合、LabVIEWはDLL関数が入力側で渡された割り当てられたメモリを必要としないとみなし、それを他のリソースで使用します。
  3. 多くのDLL関数は割り当てられたメモリを取り、ポインタまたは値によって渡され、このメモリに書き込んでそれを返します。メモリが正しく割り当てられていないと、クラッシュする可能性があります。たとえば、次の関数を考えます。

    double *Waveform (double *waveform, uInt32 size); 

    この場合、メモリを割り当てる適切な方法は、空の配列を渡すのではなく、sizeパラメータで指定された要素数で配列を初期化することです。以下の画像は、適切な方法を示しています。


LabVIEWでDLLを作成し、DLL VIのフロントパネルを表示する場合は、次の2つの要件があります。
  1. DLL呼び出しが任意のスレッドで実行できるようにライブラリ関数呼び出しノードを設定する必要があります。これは、スレッドラジオボタンをUIスレッドで実行から任意のスレッドで実行に変更することによって設定されます。
メモ: LabVIEWで作成された共有ライブラリへの呼び出しは、任意のスレッドで実行を指定する必要があります。 LabVIEWで作成した共有ライブラリを使用してライブラリ関数呼び出しノードを設定し、UIスレッドで実行を指定すると、LabVIEWがハングアップして再起動する必要があります。詳細については、ライブラリ関数呼び出しダイアログボックスを参照してください。
 
  1. 呼び出しVIは、ユーザインタフェーススレッドで実行されていてはいけません。プルダウンメニューからファイル>>VIプロパティを選択して、カテゴリリストから実行を選択し、推奨する実行システム標準計測器I/Oデータ集録その他1その他2であることを確認できます。親VIがユーザインタフェーススレッドで実行されている可能性があるため、発呼者と同じオプションを選択しないでください。
LabVIEW 7.1以前のバージョンで他のプログラミング言語とともにLabVIEWコードを使用する方法については、Using External Code in LabVIEWマニュアルを参照してください。LabVIEW 8.0以降では、詳細については、LabVIEWヘルプの目次にある基本機能セクションを参照してください。

メモ: これらの手順を行わずに、VIがまだ開発モードで実行されている可能性があります。ただし、アプリケーションを作成する場合は、上記のように呼び出しVIを任意のスレッドで実行するように設定してください。


LabVIEWが閉じられるまでクラッシュしない場合
最も可能性の高い問題は、呼び出されているDLL関数がメモリを破損していることです。配列または文字列をDLLに渡すと、DLL関数は配列サイズを動的に変更できません。配列または文字列の最後の要素を超えて書き込むとメモリが破損する可能性があり、LabVIEWが閉じられるまで分かりません。

エラーチェック — エラーチェックタブを使用して、ライブラリ関数呼び出しノードのエラーチェックレベルを指定します。

このタブには、次のコンポーネントが含まれています。
  • エラーチェックレベル - 次のオプションがあります。
    •  最大 - ライブラリ関数呼び出しノードのエラーチェックの最大レベルを有効にします。最大レベルのエラーチェックを有効にすると、ライブラリ関数呼び出しノードは、関数タブで選択した呼び出し規約が、共有ライブラリまたはDLLで呼び出している関数の呼び出し規約と一致しない場合にエラーを返します。共有ライブラリまたはDLLで呼び出されている関数が、指定された文字列または配列パラメータに割り当てられた領域を超えて書き込みを行う場合、エラーチェックの最大レベルも警告を返します。エラーチェックの最大レベルにより、呼び出される共有ライブラリまたはDLLの実行中に発生した未処理の例外からLabVIEWが復旧することができます。
メモ: エラーチェックタブの最大制御器を選択すると、実行速度が低下して、ライブラリ関数呼び出しノードのメモリ使用量が増加します。したがって、ライブラリ関数呼び出しノードの設定をデバッグする場合にのみ、最大制御器を選択する必要があります。
 
  • デフォルト - ライブラリ関数呼び出しノードのエラーチェックのデフォルトレベルを有効にします。エラーチェックのデフォルトレベルでは、呼び出された共有ライブラリまたはDLLの実行中に発生した未処理の例外からLabVIEWを復旧できます。
  • 無効 - ライブラリ関数呼び出しノードのエラーチェックを無効にします。ライブラリ関数呼び出しノードのエラーチェックを無効にすると、ライブラリ関数呼び出しノードの実行速度が向上します。ただし、特定のエラーが発生すると、LabVIEWがランダムにシャットダウンすることがあります。エラーチェックを無効にする前に、ライブラリ関数呼び出しノードが参照する関数が未処理の例外を返していないことを確認してください。