web-dev-qa-db-ja.com

静的ライブラリのVC ++リソース

静的ライブラリにリソースを構築し、ライブラリとリンクするだけでそれらを再利用することは可能ですか?

私は主に、ライブラリ内の関数を呼び出してリソースにアクセスする場合について考えています。

37
sharkin

それは可能ですが、それは非常に苦痛です。静的ライブラリとリンクするだけではそれを行うことはできません。

これを考慮してください。リソースはEXEまたはDLLに埋め込まれています。静的ライブラリ内の一部のコードが(たとえば)LoadIconを呼び出すと、EXEまたはリンク先のDLL)からリソースを取得します。

したがって、静的ライブラリでリソースを利用できるようにする必要がある場合は、いくつかのオプションがあります。

  1. ライブラリにその場でビルドさせてから、(例)CreateDialogIndirectを使用できます。 Raymond Chenの "実行時のダイアログテンプレートの作成" を参照してください。
  2. それらを単純な配列(つまり)char my_dialog_resource[] = { .... };としてライブラリに埋め込んでから、(たとえば)CreateDialogIndirectを使用することができます。おそらく、.RESファイルから.CPPファイルに変換するユーティリティを見つける(または作成する)必要があります。
  3. LIBファイルは、リソーススクリプト(.RCファイル)および対応するヘッダーファイルとともに出荷できます。次に、関連するものとして#includeします。 LIBが使用するリソースIDの範囲を予約して、メインのEXEまたはDLLのリソースIDと衝突しないようにする必要があります。これは、MFCが静的ライブラリとして使用されるときに行うことです。または、文字列リソースIDを使用できます(これはSTRINGTABLEリソースには機能しません)。
  4. 静的ライブラリには、個別のリソースDLLが付属しています。
25
Roger Lipscombe

Visual C++(2008)の静的ライブラリでリソース(画像、ダイアログなど)を使用するために必要なのは、次のことだけです。 静的ライブラリに関連付けられた.resファイルを含める あなたのプロジェクトで。これは、「プロジェクト設定/リンカー/入力/追加の依存関係」で実行できます。

このソリューションでは、静的ライブラリのリソースが.exeにパックされるため、追加のDLLは必要ありません。残念ながら、Visual Studioには.libファイルの場合のように.resファイルが自動的に含まれません( "プロジェクトの依存関係"機能を使用する場合)が、この小さな追加の手順は許容できると思います。

私はこの解決策を非常に長い間探していましたが、今では驚くほど簡単です。唯一の問題は、完全に文書化されていないことです。

59
Dimitri C.

私はMSVisualStudioコンパイラでこれを実行しました。一部のレガシープロジェクトをDLLから静的ライブラリに変換していました。これらのDLLのいくつかには、ダイアログまたは文字列リソースが埋め込まれていました。これらのDLLの.RCスクリプトを「TEXTINCLUDE」メカニズムを介してメインアプリケーションのRCスクリプトファイルに含めることで、これらのDLLをメインアプリケーションにコンパイルすることができました。 RCファイルを直接編集することでこれを行うのが最も簡単であることがわかりましたが、VisualStudioはもう少し「奇妙な」メカニズムも提供します。実装は、他のコンパイラではおそらく異なります。


メインのRCスクリプトを直接操作するには:

.1。 「2TEXTINCLUDE」セクションに、ライブラリのリソースIDを定義するヘッダーファイルを含めます。構文は

2 TEXTINCLUDE 
BEGIN
    "#include ""my_first_lib_header.h""\r\n"
    "#include ""my_second_lib_header.h""\0" 
END

.2。 「3 TEXTINCLUDE」セクションに、ライブラリのRCスクリプトを含めます。

3 TEXTINCLUDE
BEGIN
    "#include ""my_first_library.rc""\r\n"
    "#include ""my_second_library.rc""\0"
END

手順3と4は自動的に実行されるはずですが、Microsoftのリソーススクリプトコンパイラに依存して処理するよりも、自分で入力する方が信頼性が高いことがわかりました。

.3。ライブラリリソース定義を含むヘッダーファイルを読み取り専用シンボルリストに追加します。このリストは通常​​、ファイルの先頭近くにあります。

#define APSTUDIO_READONLY_SYMBOLS
#include "my_first_lib_header.h"
#include "my_second_lib_header.h"
#undef APSTUDIO_READONLY_SYMBOLS

.4。ライブラリのRCスクリプトをAPSTUDIO_INVOKEDセクションに含めます。これは通常、ファイルの最後にあります。

#ifndef APSTUDIO_INVOKED
#include "my_first_library.rc"
#include "my_second_library.rc"
#endif 

Visual Studio IDEを使用してこれらすべてを自動的に実行することもできますが、期待したときに常に適用されるとは限りませんでした。

  1. VisualStudioで[リソースビュー]ウィンドウを開きます。
  2. メインアプリケーションのリソースファイルを右クリックし、コンテキストメニューから[リソースに含まれるもの...]を選択します。
  3. 「読み取り専用シンボルディレクティブ」というラベルの付いたボックスに、ライブラリのリソースIDを定義する.hファイルのincludeステートメントを追加します。
  4. 「コンパイル時ディレクティブ」というラベルの付いたボックスに、ライブラリの.rcスクリプトのincludeステートメントを追加します。
  5. [OK]をクリックします。また、RCスクリプトのコンパイルを手動でトリガーして、それが発生することを確認することもできます。

ライブラリのリソーススクリプトがディスク上のファイル(テキストファイル、アイコンファイルなど)を参照している場合は、メインアプリケーションプロジェクトがそれらの場所を認識していることを確認する必要があります。これらのファイルをアプリケーションが見つけられる場所にコピーするか、コンパイラ設定に追加のインクルードパスを追加することができます。

インクルードパスを追加するには:

  1. メインアプリケーションのプロパティダイアログを開きます。
  2. 左側のナビゲーションペインから[構成プロパティ/リソース/全般]を選択します。
  3. プロパティリストで、[追加のインクルードディレクトリ]の横に関連するパスを入力します。
11
jeff_t

Visual Studio 2010によると、Microsoftの開発ツールは、静的ライブラリ内のコンパイル済みリソースデータを適切に処理できないようです。

コンパイルされたリソースファイル(.resファイル)を配布するには、2つの選択肢があります。

  1. .resファイルを個別に配布し、それらに対してリンクするようにクライアントコードに指示します。
  2. cvtresを使用して、複数の.resファイルを単一のオブジェクト(.obj)ファイルにマージし、個別に提供します。

cvtresで作成されたオブジェクトファイルをlibすることはできないことに注意してください。複数のオブジェクトファイルが提供されている場合、libは複数の.resファイルが指定されているかのように文句を言います。単一のオブジェクトファイルが提供されている場合、libは文句を言いませんが、リンカはlibファイルに埋め込まれたリソースデータを単に無視します。

リソースデータは実際にライブラリで利用可能であるため(コマンドラインオプション、セクション操作などを使用して)、リンカにリソースデータ内のlibbedを読み取ってリンクさせる方法がある場合があります( dumpbinが明らかにします)。これまでのところ、解決策は見つかりませんでした。開発ツールをハックする意思がない限り、この単純な解決策よりも優れたものは、おそらく努力する価値がありません。

静的ライブラリ(この場合、with静的ライブラリ)でリソースデータを送信する唯一の方法は、リソースを個別に配布し、クライアントコードで明示的にリンクすることです。 cvtresを使用すると、分散リソースファイルが多数ある場合に、それらの数を1つに減らすことができます。

2
alecov

私はそうは思いません。静的ライブラリには独自のHINSTANCEはありません。そのコードは、DLLまたはそれをリンクするEXEのコンテキストで実行されます。そのため、静的ライブラリのコードからロードしようとするすべてのリソースは、DLL/EXEを囲むものになります。

私はDLLを使用してそのようなリソースの再利用を行いましたが、独自のアドレス空間がある限り、DLLのHINSTANCEでLoadResourceを呼び出すことができます。

1
Ivan Krechetov

次の方法を使用すると、任意のリソース(この例ではアイコン)を静的ライブラリの不可欠な部分として使用でき、そのようなライブラリは、コンソールアプリケーション(を持たない)を含むすべてのタイプのアプリケーションで使用できます。任意のリソースセグメント)。

  1. アイコンはBYTEの静的配列に変換されます。 bin2c を使用できます。
  2. データはHICONハンドルに変換されます。これが私がそれをした方法です:

    _HICON GetIcon()
    { 
       DWORD dwTmp;
       int offset;
       HANDLE hFile;
       HICON hIcon = NULL;
       offset = LookupIconIdFromDirectoryEx(s_byIconData, TRUE, 0, 0, LR_DEFAULTCOLOR);
       if (offset != 0)
       {
          hIcon = CreateIconFromResourceEx(s_byIconData + offset, 0, TRUE, 0x00030000, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
       }
       return hIcon;  
    }
    _
  3. LoadIconの代わりにGetIconが使用されます。呼び出す代わりに:

m_hIcon = ::LoadIcon(hInstanceIcon, MAKEINTRESOURCE(pXMB->nIcon));

次に、

_m_hIcon = GetIcon()
_
0

推奨される方法は、ライブラリと一緒にリソースをdllに提供することです。

0
Mihai Nita