Saya ingin contoh sederhana mengekspor fungsi dari C ++ Windows DLL.
Saya ingin melihat header, .cpp
file, dan .def
file (jika benar-benar diperlukan).
Saya ingin nama yang diekspor tidak didekorasi . Saya ingin menggunakan konvensi pemanggilan paling standar ( __stdcall
?). Saya ingin menggunakannya __declspec(dllexport)
dan tidak harus menggunakan .def
file.
Sebagai contoh:
//header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}
//cpp
int __stdcall foo(long bar)
{
return 0;
}
Saya mencoba untuk menghindari linker menambahkan garis bawah dan / atau angka (jumlah byte?) Ke nama.
Saya setuju dengan tidak mendukung dllimport
dan dllexport
menggunakan tajuk yang sama. Saya tidak ingin informasi apa pun tentang mengekspor metode kelas C ++, hanya fungsi global gaya-c.
MEMPERBARUI
Tidak termasuk konvensi pemanggilan (dan penggunaan extern "C"
) memberi saya nama ekspor sesuka saya, tapi apa artinya? Apakah konvensi pemanggilan default apa pun yang saya dapatkan adalah pinvoke (.NET), menyatakan (vb6), dan GetProcAddress
harapkan? (Saya kira untuk GetProcAddress
itu akan tergantung pada penunjuk fungsi yang dibuat pemanggil).
Saya ingin DLL ini digunakan tanpa file header, jadi saya tidak terlalu membutuhkan banyak fasilitas #defines
untuk membuat header dapat digunakan oleh pemanggil.
Saya baik-baik saja dengan jawaban bahwa saya harus menggunakan *.def
file.
sumber
extern C
akan menghapus dekorasi yang menjelaskan jenis parameter fungsi, tetapi bukan dekorasi yang menjelaskan konvensi pemanggilan fungsi; b) untuk menghapus semua dekorasi Anda perlu menentukan nama (tanpa dekorasi) dalam file DEF.Jawaban:
Jika Anda menginginkan ekspor C biasa, gunakan proyek C, bukan C ++. DLL C ++ mengandalkan pengaturan nama untuk semua isme C ++ (ruang nama, dll ...). Anda dapat mengkompilasi kode Anda sebagai C dengan masuk ke pengaturan proyek Anda di bawah C / C ++ -> Advanced, ada opsi "Compile As" yang sesuai dengan switch compiler / TP dan / TC.
Jika Anda masih ingin menggunakan C ++ untuk menulis internal lib tetapi mengekspor beberapa fungsi yang tidak diubah ukurannya untuk digunakan di luar C ++, lihat bagian kedua di bawah.
Mengekspor / Mengimpor Libs DLL di VC ++
Apa yang benar-benar ingin Anda lakukan adalah menentukan makro bersyarat di header yang akan disertakan di semua file sumber di proyek DLL Anda:
Kemudian pada fungsi yang ingin Anda ekspor Anda gunakan
LIBRARY_API
:Dalam proyek pembangunan perpustakaan Anda membuat mendefinisikan
LIBRARY_EXPORTS
ini akan menyebabkan fungsi Anda akan diekspor untuk membangun DLL Anda.Karena
LIBRARY_EXPORTS
tidak akan ditentukan dalam proyek yang menggunakan DLL, ketika proyek itu menyertakan file header perpustakaan Anda, semua fungsi akan diimpor sebagai gantinya.Jika perpustakaan Anda akan lintas platform, Anda dapat mendefinisikan LIBRARY_API sebagai tidak ada ketika tidak di Windows:
Saat menggunakan dllexport / dllimport anda tidak perlu menggunakan file DEF, jika menggunakan file DEF anda tidak perlu menggunakan file dllexport / dllimport. Kedua metode menyelesaikan tugas yang sama dengan cara yang berbeda, saya percaya bahwa dllexport / dllimport adalah metode yang disarankan dari keduanya.
Mengekspor fungsi yang tidak diubah dari C ++ DLL untuk LoadLibrary / PInvoke
Jika Anda memerlukan ini untuk menggunakan LoadLibrary dan GetProcAddress, atau mungkin mengimpor dari bahasa lain (misalnya PInvoke dari .NET, atau FFI dengan Python / R dll), Anda dapat menggunakan
extern "C"
inline dengan dllexport Anda untuk memberi tahu compiler C ++ agar tidak merusak nama. Dan karena kita menggunakan GetProcAddress daripada dllimport, kita tidak perlu melakukan tarian ifdef dari atas, cukup dllexport sederhana:Kode:
Dan inilah tampilan ekspor dengan Dumpbin / ekspor:
Jadi kode ini berfungsi dengan baik:
sumber
Untuk C ++:
Saya baru saja menghadapi masalah yang sama dan saya pikir ada baiknya menyebutkan masalah muncul ketika seseorang menggunakan keduanya
__stdcall
(atauWINAPI
) danextern "C"
:Seperti yang Anda ketahui
extern "C"
menghapus dekorasi sehingga bukan:Anda mendapatkan nama simbol tanpa dekorasi:
Namun
_stdcall
(= makro WINAPI, yang mengubah konvensi pemanggilan) juga menghiasi nama sehingga jika kita menggunakan keduanya kita mendapatkan:dan keuntungan
extern "C"
hilang karena simbolnya dihias (dengan _ @bytes)Ini sangat rumit jika Anda menargetkan platform x86 dan x64.
Dua solusi
Gunakan file definisi. Tetapi ini memaksa Anda untuk mempertahankan status file def.
cara paling sederhana: tentukan makro (lihat msdn ):
dan kemudian masukkan pragma berikut ke dalam fungsi tubuh:
Contoh Lengkap:
Ini akan mengekspor fungsi tanpa dekorasi untuk target x86 dan x64 sambil mempertahankan
__stdcall
konvensi untuk x86. The__declspec(dllexport)
tidak diperlukan dalam hal ini.sumber
__FUNCTION__
makro hanya berfungsi dalam fungsi.Saya memiliki masalah yang persis sama, solusi saya adalah menggunakan file definisi modul (.def) daripada
__declspec(dllexport)
menentukan ekspor ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Saya tidak tahu mengapa ini berhasil, tetapi berhasilsumber
.def
file ekspor modul memang berfungsi, tetapi dengan mengorbankan kemampuan untuk memberikanextern
definisi di file header misalnya untuk data global — dalam hal ini, Anda harus memberikanextern
definisi secara manual dalam penggunaan internal data itu. (Ya, ada kalanya Anda membutuhkannya.) Lebih baik secara umum dan terutama untuk kode lintas platform cukup digunakan__declspec()
dengan makro sehingga Anda dapat menyerahkan data secara normal.__stdcall
, maka tidak__declspec(dllexport)
akan menghapus dekorasi. Namun menambahkan fungsi ke wasiat..def
Saya pikir _naked mungkin mendapatkan apa yang Anda inginkan, tetapi itu juga mencegah kompilator menghasilkan kode manajemen tumpukan untuk fungsi tersebut. extern "C" menyebabkan dekorasi nama gaya C. Hapus itu dan itu akan menghilangkan _'s Anda. Linker tidak menambahkan garis bawah, kompilator tidak. stdcall menyebabkan ukuran tumpukan argumen ditambahkan.
Untuk lebih lanjut, lihat: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx
Pertanyaan yang lebih besar adalah mengapa Anda ingin melakukan itu? Apa yang salah dengan nama yang hancur?
sumber