Domanda

Creato base C ++ DLL e nomi esportati utilizzando file di definizione del modulo (MYDLL.DEF). Dopo la compilazione verifico i nomi delle funzioni esportate utilizzando dumpbin.exe Mi aspetto di vedere:

SomeFunction

ma vedo questo, invece:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

Perché?

La funzione esportata appare non decorati (soprattutto rispetto a non utilizzare il file modulo Def), ma cosa succede con l'altra roba?

Se io uso dumpbin.exe contro una DLL da qualsiasi applicazione commerciale, si ottiene la pulizia:

SomeFunction

e niente altro ...

Inoltre ho provato a rimuovere la definizione del modulo e l'esportazione dei nomi utilizzando lo stile "C" di esportazione, vale a dire:

extern "C" void __declspec(dllexport) SomeFunction();

(Semplicemente usando "extern "C" non ha creato una funzione esportata)

Tuttavia, questo crea ancora la stessa uscita, vale a dire:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

Ho provato anche l'opzione #define dllexport __declspec(dllexport) e creato un LIB senza alcun problema. Tuttavia, io non voglio avere a fornire un file LIB per le persone che utilizzano la DLL nella loro applicazione C #.

E 'un plain vanilla C ++ DLL (codice non gestito), compilato con C ++ nient'altro che un colpo di testa semplice e codice. Senza modulo Def vengo straziati funzioni esportate (posso creare una libreria statica e utilizzare il LIB nessun problema. Sto cercando di evitare quello). Se uso extern "C" __declspec(dllexport) o di una definizione di modulo ottengo quello che sembra essere un nome di funzione non decorato ... l'unico problema è che è seguita da un "=" e quello che sembra una versione decorata del funzione. Voglio sbarazzarsi della roba dopo il "=" - o almeno a capire perché è lì.

Allo stato attuale, sono abbastanza sicuro che posso chiamare la funzione da C # utilizzando un P / Invoke ... voglio solo evitare che spazzatura, alla fine della "=".

Sono aperto a suggerimenti su come modificare il progetto / impostazioni del compilatore, ma ho appena usato il Visual Studio DLL modello standard - niente di speciale.

È stato utile?

Soluzione

È possibile ottenere ciò che si vuole spegnendo generazione informazioni di debug. Progetto + Proprietà, Linker, Debug, Genera informazioni di debug = No.

Naturalmente, si desidera solo fare questo per la build di rilascio. Quando l'opzione è già impostato in quel modo.

Altri suggerimenti

Invece di usare file di DEF proprio inserto pragma comment come questo

#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")

Edit: O ancora più semplice: All'interno del corpo della funzione di utilizzo

#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)

. . . se avete problemi a trovare il nome della funzione decorato. Quest'ultimo pragma può essere ulteriormente ridotto con una semplice definizione di macro.

È necessario dichiarare le funzioni come extern "C" se non vogliono che i loro nomi siano alterati.

Per esperienza, fate attenzione se si utilizza __stdcall nella tua firma funzione. Con __stdcall, il nome resterà maciullato in una certa misura (si scopriranno abbastanza rapidamente). A quanto pare, ci sono due livelli di pressare, uno le offerte extern "C" a livello C ++, ma non si tratta di un altro livello di mutilazione dei nomi causata da __stdcall. La mutilazione aggiuntivo è apparentemente rilevante per sovraccarico -. Ma non sono certo di che

Ci scusiamo per rispondere a un thread vecchio, ma quello che è stato contrassegnato come la risposta non ha funzionato per me.

Come un certo numero di persone hanno fatto notare, la decorazione extern "C" è importante. Modifica il "Progetto / Proprietà / Linker / Debug / Genera informazioni di debug" impostazione fatta assolutamente alcuna differenza per i nomi alterati essere generati per me sia in modalità Debug o di uscita.

Configurazione: VS2005 compilazione di un progetto di Visual C ++ Class Library. Stavo controllando l'output DLL compilato con lo strumento Dependency Walker di Microsoft.

Ecco una ricetta di esempio che ha lavorato per me ...

In project.h:

#define DllExport extern "C" __declspec( dllexport )

DllExport bool API_Init();
DllExport bool API_Shutdown();

In project.cpp:

#include "project.h"

bool API_Init()
{
  return true;
}

bool API_Shutdown()
{
  return true;
}

Poi viene chiamato da C # codice gestito, 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();
    }
}

fare quanto sopra ha impedito i nomi alterati sia in modalità debug e rilascio, indipendentemente dalla impostazione di debug Genera informazioni. Buona fortuna.

Anche senza il mangling, il 32-bit e 64-bit costruisce esportazioni nome diverso, anche con extern "C". Check it out con Depends.exe.

Questo può significare grossi guai a qualsiasi cliente che fa un LoadLibrary + GetProcAdress per l'accesso la vostra funzione.

Così, in cima a tutte le altre utilizzare un file di definizione del modulo come segue:

LIBRARY MYDLL
EXPORTS
myFunction=myFunction

Yeap, è un po 'di dolore per mantenere, ma poi quante funzioni esportate si fa a scrivere un giorno?

Inoltre, di solito modificare le macro come mostrato di seguito, dal momento che i miei DLL esportare le funzioni non classi C ++ e voglio loro di essere richiamabile dalla maggior parte degli ambienti di programmazione:

#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);

L'ultima riga utilizzato per confondere VisualAssistX un paio di anni fa, non so se digerisce correttamente subito: -)

so quante volte ho provato a forzare i nomi delle funzioni utilizzando il codice e # pragma di. E finisco sempre con esattamente stessa cosa, usando Module-Definition File (* .def) alla fine. Ed ecco il motivo:

//---------------------------------------------------------------------------------------------------
// 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.

Mi chiedo perché nessuno ha fatto questo, mi ci sono voluti solo 10 minuti per testare tutti i casi.

il SomeFunction @@@ 23mangledstuff # @@@@ è storpiato per dare i tipi e di classe della funzione di C ++. Le semplici esportazioni sono funzioni che sono richiamabili dal C cioè sono scritti in C oppure sono dichiarati extern "C' nel codice C ++. Se è si desidera una semplice interfaccia devi fare le funzioni si esporta essere utilizzato solo tipo C e renderli funzioni non membro dello spazio dei nomi globale.

In sostanza, quando si utilizzano le funzioni in C ++, parti dei loro nomi includono ora la loro firma e simili, al fine di facilitare le caratteristiche come il sovraccarico lingua.

Se si scrive una DLL utilizzando __declspec (dllexport), allora dovrebbe anche produrre un lib. Collegamento a quella lib, e si verrà automaticamente collegati e le funzioni registrate dalla CRT al momento di start-up (se vi siete ricordati di cambiare tutti i tuoi importazioni alle esportazioni). Non è necessario essere informato in nome storpiatura se si utilizza questo sistema.

Nel caso in cui non era chiaro dalle centinaia di righe di cialda in materia di esportazioni alterati. Ecco il mio 2c pena:)

Dopo aver creato un progetto chiamato Win32Project2 utilizzando VS 2012 e la scelta di esportare tutti i simboli della procedura guidata. Si dovrebbe avere 2 file chiamati Win32Project2.cpp e Win32project2.h

Entrambi questi farà riferimento un esempio variabile esportabile e una funzione di esempio esportata.

In Win32Project2.h si avrà il seguente:

#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);

Per modificare unmangle le ultime due righe a extern dichiarazioni "C" a:

extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);

In Win32Project2.cpp si avrà anche le definizioni seguenti predefiniti:

// 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;
}

Per modificare unmangle queste per:

// 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;
}

In sostanza è necessario utilizzare l'extern prefisso "C" di fronte a dichiarazioni al fine di forzare il linker per la produzione di C unmangled come i nomi.

Se si preferisce utilizzare nomi alterati per quel po 'di confusione in più (nel caso in cui le informazioni pressare è utile a qualcuno in qualche modo) l'uso "dumpbin / export Win32Project2.dll" dalla riga di comando VC di ricercare i nomi di riferimento attuali. Avrà la forma "? FnWind32Project2 @ [param bytes] @ [altre informazioni]. Ci sono anche altri strumenti di visualizzazione DLL in giro se si esegue una shell di comando VC non galleggia la vostra barca.

Esattamente perché MS non di default per questa convenzione è un mistero. I mezzi di informazione effettiva mutilazione qualcosa (come dimensione in byte del parametro e più), che potrebbero essere utili per la convalida e il debug, ma è al contrario guff.

Per importare la funzione DLL sopra in C # progetto (in questo caso un semplice applicazione C # Windows con una forma su di esso che contiene il pulsante "Button1") ecco qualche esempio di codice:

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();
        }
      }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top