2009-06-27 17 views
6

Cランタイムに依存する "オブジェクト"(FILE *、mallocによって返されるポインタなど)を渡す問題を扱うdllのためのC APIを設計する最良の方法は何ですか? 。たとえば、2つのDLLがランタイムの異なるバージョンにリンクされている場合、私の理解は、FILE *を1つのDLLから他のDLLに安全に渡すことができないことです。Cランタイムオブジェクト、dll境界

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

答えて

0

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

しかし、小さなラッパーインターフェイスを作成すると、それは本当に傷つくことはありません。

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

class IFile { 

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

    virtual delete() = 0; 
} 

これは、どこにでもdllの境界を渡って渡されるのを防ぎ、本当に傷つけることはありません。

P.:Dllの境界を越えて例外をスローする場合は注意が必要です。これは、あなたがWindows OS上でいくつかのデザインの作成を完了したが、他のいくつかで失敗する場合は、静かにうまく動作します。

1

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

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

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

注:DLL間のポインタを使用することができます。ポインタはメモリを指すだけです。それは問題である無料です。

これはうまくいくことがわかりますが、そうであれば運が単なる運勢です。これは将来問題を引き起こす可能性があります。

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

注:私は、DLL間でCRTデータ構造を渡すのはベストプラクティスではないことをお勧めします。物事をより良いものにすることができるかどうかを知りたいかもしれません。

私はLinux/Unixのエキスパートではありませんが、これらのOSでも同じ問題が発生します。

+0

私はこの問題の答えを求めています:)私は、既存のC API(署名などのFILE *)を変更することを想定していないソリューションを期待していましたが、同じCランタイムとリンクするためのすべてを保証できない場合はどうですか? 問題は理論的にはUnixでも同じですが、Cランタイムが1つしかないため問題になることはほとんどありません。ライブラリ間のファイル記述子をFILE *に渡すという問題は一度もありませんでした。多くのC APISはこのように設計されており、これらのOSで完璧に動作します。 –

+0

APIの署名にFILE *があることが良い習慣ではない場合、ファイルストリームをどう扱うのですか?あなたが呼び出すdllがfprintfとFILE *を期待する他の関数を内部的に呼び出すいくつかの関数を持っている場合、ファイルをオープンして閉じる関数をエクスポートする必要がありますか? –

+0

私は解決策を提案しました:) CRTに静的にリンクしないでください。 MSVCRT.DLLへのリンク。 Linux、Unix、またはMAC上のCRTライブラリがすべて問題なく動作することが保証されていれば、私はかなり驚いています。私はあなたもそこに幸運だったと思う。 – Foredecker

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ではなくクリーンアップ機能を使用していることを確認することです。これは、別の質問に値するいくつかのトリックを使って行うことができます...

2

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

Cでこの種のものを行うための通常の方法(複数可)は次のとおりです。

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

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

あなたがホストCRTのあなたのCのDLLインタフェースは完全に独立させることができ、このようないくつかの簡単なトリックで

- あるいは、実際には、CまたはC++ですべて書き込まれるホストが必要です。