C ++ DLLのエクスポート:装飾/マングルされた名前
-
25-09-2019 - |
質問
基本的なC ++ DLLを作成し、モジュール定義ファイル(MyDLL.def)を使用して、名前を輸出しました。
コンパイルの後、私はdumpbin.exe
を使用してエクスポート関数名を確認します
私が見ることを期待します:
SomeFunction
私は、代わりにこの参照してください。
をSomeFunction = SomeFunction@@@23mangledstuff#@@@@
なぜ?
エクスポートされた関数は、(特にモジュールDEFファイルを使用していないために比較して)装飾のない表示されますが、他のものと何までですか?
私は、任意の商用アプリケーションからDLLに対してdumpbin.exe
を使用している場合、あなたはクリーン取得:
SomeFunction
何もない...
私はまた、モジュール定義を削除し、輸出の「C」スタイル、すなわちを使用して名前を輸出しようとしました
extern "C" void __declspec(dllexport) SomeFunction();
(単純にエクスポートされた関数を作成していない「のextern "C" を使用して)
しかし、これはまだすなわち、同じ出力を作成します:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
私はまた#define dllexport __declspec(dllexport)
オプションを試してみましたが、問題なくLIBを作成しました。しかし、私は彼らのC#アプリケーションでDLLを使用している人々にLIBファイルを提供する必要がありますする必要はありません。
これは、C ++は何もなく、シンプルなヘッダとコードでコンパイルされたプレーンバニラC ++ DLL(アンマネージコード)、です。モジュールデフ私は、エクスポート機能を台無しに取得することなく、(私は静的ライブラリを作成し、LIBに何の問題を使用することはできません。私はそれを避けるためにしようとしています)。 I使用extern "C" __declspec(dllexport)
OR の私は装飾のない関数名のように見えるものを手に入れるモジュール定義なら...唯一の問題は、それが「=」が続いていることにあるとの装飾が施されたバージョンのように見えるもの関数。私は、「=」の後のものを取り除きたい - またはそれがある理由を、少なくとも理解しています。
現状では、私はP /呼び出しを使用してC#から機能を呼び出すことができることをかなり確信している...私はちょうど「=」の末尾にそのジャンクを避けたいです。
私は、プロジェクト/コンパイラの設定を変更する方法についての提案を開いてんだけど、私はただ、標準のVisual StudioのDLLテンプレートを使用 - 何も特別なの。
解決
あなたはデバッグ情報生成オフにすることで、あなたが欲しいものを得ることができます。プロジェクト+ [プロパティ、リンカ、デバッガ、デバッグ情報=いいえを生成します。
当然のことながら、あなただけのリリースビルドのためにこれをやってみたいです。オプションは、すでにそのように設定されているところます。
他のヒント
代わりに.defファイルを使用して、このような単なる挿入pragma comment
#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")
編集:またはさらに簡単:内部機能使用のボディ
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
。 。 。あなたは装飾された関数名を見つけるのトラブルを持っている場合。この最後のプラグマは、さらに簡単なマクロ定義を低減することができます。
あなたは自分の名前を台無しにしたくない場合はextern "C"
としての機能を宣言する必要があります。
__stdcall
を使用する場合は、経験から、注意してください。 __stdcall
で、名前は(あなたは十分にすぐに見つけるだろう)ある程度まで台無しにされたままになります。どうやら、そこにマングリングの二つのレベル、C ++レベルで持つ1つのextern "C"
お得な情報がありますが、それは__stdcall
によって引き起こさマングル名の別のレベルを扱っていません。余分なマングリングが過負荷にに明らかに関連している - 。しかし、私はそれの特定のはないです。
古いスレッドに返信するために申し訳ありませんが、どのような答えは私のために動作しませんでしたとしてマークされています。
人々の数が指摘したように、は、EXTERN「C」装飾が重要です。 「プロジェクト/プロパティ/リンカ/デバッグ/デバッグ情報を生成する」設定変更することはいずれかのデバッグまたはリリースビルドモードで私のために生成されてマングルされた名前には全く差は行われません。
セットアップ:VS2005は、Visual C ++クラスライブラリプロジェクトをコンパイルします。私はMicrosoftの依存関係ウォーカーツールを使用してコンパイルされた.dll出力をチェックしてます。
ここでは私のために働いた例レシピがある...
project.hで
#define DllExport extern "C" __declspec( dllexport )
DllExport bool API_Init();
DllExport bool API_Shutdown();
project.cppで
#include "project.h"
bool API_Init()
{
return true;
}
bool API_Shutdown()
{
return true;
}
そして、C#のマネージコード、class.csから呼び出されます:
using System.Runtime.Interopservices;
namespace Foo
{
public class Project
{
[DllImport("project.dll")]
public static extern bool API_Init();
[DllImport("project.dll")]
public static extern bool API_Shutdown();
}
}
は関係なく、生成デバッグ情報の設定、デバッグとリリースモードの両方で防止マングルされた名前の上に行います。幸運ます。
でもマングリングせずに、32ビットおよび64ビットが偶数のextern「C」で、異なる名前の輸出を構築します。 Depends.exeはでそれをチェックしてください。
これはあなたの機能にアクセスするためのLoadLibrary + GetProcAdressを行う任意のクライアントへのBIGトラブルを意味することができます。
次のようにそうでは、すべての上に他の人がモジュール定義ファイルを使用します:
LIBRARY MYDLL
EXPORTS
myFunction=myFunction
Yeap、それは維持するために、痛みのビットだが、その後、あなたは一日どのように多くのエクスポート機能を書くのですか?
私のDLLが機能していないC ++のクラスをエクスポートし、私は彼らがほとんどのプログラミング環境で呼び出し可能にしたいので、また、私は通常、以下に示すようなマクロを変更します。
#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif
WTS_API(int) fnWTS(void);
最後の行は数年前VisualAssistXを混乱させるために使用されることが適切に今それを消化した場合、私は知らない: - )
私は、コードと#プラグマのを使用して関数名を強制しようとした回数を知っています。 そして、私はいつも最後にモジュール定義ファイル(* .defファイル)を使用して、まったく同じことで終わります。 そして、ここではその理由があります:
//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
// || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4
__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z
//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.
// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
SetCallback
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback
__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback
// And by far this is most acceptable as it will reproduce exactly same exported function name
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.
私は、誰がこれをやっていない理由、それはすべてのケースをテストするために私にだけ10分を要したのだろうか。
はSomeFunction @@@ 23mangledstuff位@@@@タイプとC ++の関数のクラスを与えるためにマングルされています。シンプルな輸出はCで書かれているか、他のC ++コード内でextern「C」宣言されているCすなわちから呼び出し可能な機能です。あなたはエクスポート機能を使用することだけでC型を作り、それをしなければならないインタフェースの場合は、あなたがシンプルにしたいれますグローバル名前空間内の非メンバ関数ます。
あなたがC ++で関数を使用する場合、基本的に、自分の名前の部分は今の言語を容易にするために、自分の署名とそのようなものが含まれるが過負荷状態に似ています。
あなたは__declspec(dllexport)を使用してDLLを作成する場合は、、それはまた、libが生じるはずです。そのLIBへのリンク、あなたは自動的にリンクされ、(あなたが輸出にすべての輸入を変更するために覚えている場合)起動時にCRTによって登録された関数。あなたはこのシステムを使用する場合、名前マングリングについて知る必要はありません。
ケースでは、マングルされた輸出の対象にワッフルの行数百人から明確ではありませんでした。ここに私の2cは価値があります。)
ウィザードのすべてのシンボルをVS 2012を使用してエクスポートを選択Win32Project2と呼ばれるプロジェクトを作成した後、。あなたは、2つのファイルがWin32Project2.cppとWin32project2.h
と呼ばれる必要があります、それらの両方は、例えば、エクスポート変数と例エクスポートされた関数を参照します。
でWin32Project2.hあなたは次のようになります。
を#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif
extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);
unmangleに変更することにはextern "C" 宣言への最後の2行:
extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);
でWin32Project2.cppあなたはまた、次のデフォルトの定義があります。
// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;
// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
return 42;
}
これらにunmangle変更するには:
// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;
// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
return 42;
}
を基本的にあなたが名前のようなunmangled Cを生成するために、リンカを強制するために、宣言の前にはextern「C」の接頭辞を使用しなければなりません。の
あなたは余分な難読化のそのビットのためのマングルされた名前を使用する場合は、は、実際の参照名をルックアップするためにVCコマンドラインから「/輸出Win32Project2.dll DUMPBIN」使用(場合にマングリング情報は、何らかの形で誰かに便利です)。それは?」の形を持つことになりますfnWind32Project2 @ [PARAMバイト] @ [その他の情報]。他のDLL閲覧ツールもあります周りにあなたのボートをフロートしないVCコマンドシェルを実行している場合。
MSは、この規則をデフォルトとしない正確な理由は謎です。検証とデバッグのために有用であるが、それ以外guffである可能性があります。
(パラメータのバイト単位のサイズなどのような)実際のマングリング情報手段の何かここではいくつかのサンプルコードを示します(ボタン「ボタン1」を含むその上にフォームで、この場合には、基本的なC#のWindowsアプリケーションを)C#プロジェクトにDLL関数を上にインポートするには
using System.Runtime.InteropServices;
namespace AudioRecApp
{
public partial class Form1 : Form
{
[ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")]
public static extern int fnWin32Project2();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int value;
value = fnWin32Project2();
}
}
}