6

Cランタイムに依存する「オブジェクト」(FILE *、mallocによって返されるポインターなど)を渡す問題を処理するDLL用のC APIを設計する最良の方法は何ですか. たとえば、2 つの dll が異なるバージョンのランタイムにリンクされている場合、ある dll から別の dll に FILE* を安全に渡すことはできないと理解しています。

Windows 依存の API (DLL 間で動作することが保証されている) を使用する唯一のソリューションはありますか? C API はすでに存在し、成熟していますが、ほとんどが UNIX の POV から設計されています (もちろん、UNIX でも動作する必要があります)。

4

4 に答える 4

2

あなたはC++ソリューションではなくCを求めました。

Cでこの種のことを行うための通常の方法は次のとおりです。

  • モジュールAPIを設計して、CRTオブジェクトを単純に必要としないようにします。生のCタイプで渡されるものを取得します。つまり、コンシューマーにファイルをロードさせ、ポインターを渡すだけです。または、内部で開かれ、読み取られ、閉じられる完全修飾ファイル名をコンシューマーに渡してもらいます。

  • 他のcモジュール、MSキャビネットSD、およびOpenSSLライブラリiircの一部で使用されるアプローチが思い浮かび、消費するアプリケーションに関数へのポインターを初期化関数に渡すようにします。したがって、初期化中のある時点でFILE *を渡すAPIは、fread、fopenなどのシグネチャに一致する関数ポインタを持つ構造体へのポインタを取得します。外部FILE *を処理する場合、dllは常に渡されたものを使用します。 CRT関数ではなく関数。

このようないくつかの簡単なトリックを使用すると、C DLLインターフェイスをホストCRTから完全に独立させることができます。または、実際には、ホストをCまたはC++で記述する必要があります。

于 2009-06-29T07:39:05.203 に答える
1

既存の答えはどちらも正しくありません: Windows で次のことを考えると、2 つの DLL があり、それぞれが C/C++ 標準ライブラリの 2 つの異なるバージョンに静的にリンクされています。

この場合、ある DLL 内の C/C++ 標準ライブラリによって作成された構造体へのポインターを別の DLL に渡してはなりません。その理由は、これらの構造が2 つの C/C++ 標準ライブラリの実装間で異なる可能性があるためです。

他にすべきでないことは、new または malloc によって割り当てられたポインターを、別の DLL で割り当てられた DLL から解放することです。ヒープ マネージャーも別の方法で実装される場合があります。

DLL 間でポインターを使用できることに注意してください。ポインターはメモリを指すだけです。問題になるのは無料です。

これでうまくいくかもしれませんが、うまくいくとしたら、それはただの運です。これにより、将来的に問題が発生する可能性があります。

問題の潜在的な解決策の 1 つは、CRTに動的にリンクすることです。たとえば、MSVCRT.DLL に動的にリンクできます。そうすれば、DLL は常に同じ CRT を使用します。

DLL 間で CRT データ構造を渡すことはベスト プラクティスではないことに注意してください。物事をより良く因数分解できるかどうかを確認したい場合があります。

私は Linux/Unix の専門家ではありませんが、これらの OS でも同じ問題が発生することに注意してください。

于 2009-06-27T16:20:19.940 に答える
0

C API が存在し、成熟している場合は、純粋な Win32 API を使用して内部で CRT をバイパスすると、道半ばになります。残りの半分は、DLL のユーザーが対応する Win32 API 関数を使用していることを確認することです。これにより、使用とドキュメントの両方で、API の移植性が低下します。また、CRT 関数と Win32 関数の両方が void* を処理するメモリ割り当てをこのように行ったとしても、依然としてファイルに関する問題が発生します。Win32 API はハンドルを使用し、FILE 構造については何も知りません。

FILE* の制限が何であるかはよくわかりませんが、問題はモジュール間の CRT 割り当てと同じであると思います。MSVCRT は Win32 を内部的に使用してファイル操作を処理し、基になるファイル ハンドルは同じプロセス内のすべてのモジュールから使用できます。うまくいかない可能性があるのは、別のモジュールによって開かれたファイルを閉じることです。これには、おそらく別の CRT で FILE 構造を解放することが含まれます。

API の変更がまだオプションである場合、私が行うことは、DLL 内で作成された可能性のある「オブジェクト」のクリーンアップ関数をエクスポートすることです。これらのクリーンアップ関数は、その DLL 内で作成された方法に対応する方法で、指定されたオブジェクトの破棄を処理します。これにより、DLL は使用に関して完全に移植可能になります。唯一の心配は、DLL のユーザーが通常の CRT ではなくクリーンアップ関数を実際に使用していることを確認することです。これは、別の質問に値するいくつかのトリックを使用して行うことができます...

于 2009-06-27T16:58:02.730 に答える
0

FILE* 構造体は Windows システム上の 1 つのランタイムに属しているため、異なるランタイムの問題は解決できません。

しかし、小さなラッパー インターフェイスを作成すれば、それで問題はありません。

stdcall IFile* IFileFactory(const char* filename, const char* mode);

class IFile {

  virtual fwrite(...) = 0;
  virtual fread(...) = 0;

  virtual delete() = 0; 
}

これは、どこでも dll 境界を越えて渡されるための保存であり、実際には害はありません。

PS: dll の境界を越えて例外をスローし始める場合は注意してください。これは、Windows OS でいくつかの設計基準を満たす場合は静かに機能しますが、他のいくつかの基準では失敗します。

于 2009-06-27T10:22:19.170 に答える