2010-03-05 79 views
11

我有.lib文件及其頭文件(.h)文件。這個文件有一些需要在C#應用程序中使用的函數。將靜態鏈接庫轉換爲動態DLL

谷歌搜索後,我發現我需要從這個靜態庫中創建一個動態DLL,並使用interop從C#代碼調用這個動態DLL。

  1. 我創建了一個win32項目並選擇了類型DLL。
  2. 包含頭文件並將.lib添加到其他依賴項。

    我能夠看到靜態庫中定義的功能(當我按Ctrl +空格時)。

作爲一個總的新手,我不知道我怎麼可以導出的功能,這是在與.LIB以下簽名:

void testfun(char* inp_buff, unsigned short* inp_len, char* buffer_decomp,unsigned *output_len,unsigned short *errorCode) 

我想在我的DLL動態簽名相同與不同名稱。

在頭文件和.cpp文件中寫什麼?

+0

你想爲導出的函數使用不同的名稱嗎?或.dll文件的不同名稱? – 2010-03-05 06:33:04

回答

6

如果您可以重新編譯您的lib,只需將__declspec(dllexport)添加到您想要導出的所有函數的簽名。

void __declspec(dllexport) testfun(char* inp_buff, unsigned short* inp_len, char* buffer_decomp,unsigned *output_len,unsigned short *errorCode) 

如果你不能這樣做,那麼你可以通過編寫一個.def文件來導出它們。使用def文件,您甚至可以在導出函數時更改它的名稱。 http://msdn.microsoft.com/en-us/library/28d6s79h.aspx

---- mylib.def的內容----

LIBRARY 

EXPORTS 
    testfun 
    newname=testfun2 

然後當你鏈接的dll,mylib.def包括

link /dll /machine:x86 /def:mylib.def mylib.lib 

EDIT2:

請注意,pinvoke假定您導入的函數將具有_stdcall調用約定,除非您另有說明。所以你可能也需要在你的C#代碼中這樣做。

[DllImport("mylib.dll", CallingConvention=CallingConvention.Cdecl)] 

或者,你可以改變你的C++代碼是__stdcall

void __declspec(dllexport) __stdcall testfun(char* inp_buff, ... 
+0

我創建了dll。但是當我從C#調用它時,它說 「無法在DLL'demo.dll'中找到名爲'testfun2'的入口點'」 當我看到使用DLL導出的導出函數列表查看器 它顯示函數名稱爲「?testfun2 @@ YAXPADPAG0PAI @ Z」 會是什麼問題? – Manjoor 2010-03-05 07:30:48

+0

@ Manjoor:可能是。你使用了def文件還是_declspec?如果您使用了_declspec,那麼您可能只需修復C#dllImport語句。看到一些代碼會很有幫助。 – 2010-03-05 08:18:21

+0

我已添加原始代碼。請看一看 – Manjoor 2010-03-05 09:04:42

3

使用Visual Studio應用程序嚮導創建新的Dll項目,並在其中一個嚮導步驟中選中「導出符號」。它創建了導出類,函數和變量的樣本Dll。你可以從這個例子中學習如何做到這一點。 通常,每個導出的函數都被聲明爲__declspec(dllexport)。在客戶端項目中,它被聲明爲__declspec(dllimport)。 Dll代碼使用在Dll項目中被玷污爲__declspec(dllexport)的常量,而在其他任何地方使用__declspec(dllimport)。

3

這是你可以做什麼

  1. 你.h文件中添加以下代碼。「MYPROJECT」 重命名爲您的項目名稱

    #ifdef MYPROJECT_EXPORTS 
    #define MYPROJECT_API __declspec(dllexport) 
    #else 
    #define MYPROJECT_API _declspec(dllimport) 
    #endif 
    
  2. 進入屬性 - > C++ - >預處理器,並添加defenition - MYPROJECT_EXPORTS

  3. 添加MYPROJECT_API給你想要的所有DLL暴露例如功能:

    MYPROJECT_API void Test(); 
    
  4. 轉到項目屬性常規 - >配置類型將其更改爲動態的Dll

你完成了

+0

我已經做到了,正如你們告訴我的那樣。 DLL創建。但我無法從我的C#應用​​程序調用它。看到我上面發表的評論。 – Manjoor 2010-03-05 08:00:21

+0

嗨你看到的函數名稱是奇怪的,因爲C++名稱mangling 嘗試把:extern「C」放在你的函數前,並重新編譯 – SysAdmin 2010-03-05 08:35:01

+0

正如你所說我在我的頭文件中添加了extern「C」之前的函數。但沒有運氣(請參閱下面的代碼) – Manjoor 2010-03-05 08:41:23

3

我寫的目標dll是流行的lzo庫的封裝。 我已經創建了名爲LZO的項目。

這裏是它在我的真實應用程序中的外觀。

LZO.h

#ifdef LZO_EXPORTS 
    #define LZO_API __declspec(dllexport) 
    #else 
    #define LZO_API __declspec(dllimport) 
    #endif 

    extern "C" LZO_API void Decompress(char* inp_buff, 
unsigned short* inp_len, char* buffer_decomp,unsigned *output_len); 

LZO.cpp

 #include "stdafx.h" 
     #include "LZO.h" 
     #include "lzo1z.h" 
     #include "lzoconf.h" 
     #include "lz_decomp.c" 

     LZO_API void Decompress(char* inp_buff, unsigned short* inp_len, char* 
    buffer_decomp,unsigned *output_len) 
     { 
      //Calling from static library 
      lzo_decomp (inp_buff,inp_len,buffer_decomp,output_len,NULL); 
     } 

而finaly我的C#代碼

//P/Invoke declaration 
[DllImport("LZO.dll")] 
private static extern void Decompress(
    byte[] inp_buff, 
    int inp_len, 
    byte[] buffer_decomp, 
    ref int output_len 
);   

//And calling it as below 
Decompress(src, src.Length, dst, ref outlen); 
// src is byte [] 
// dst is also a byte [] 
// oulen is int 

我在哪裏wrog?

+0

在.H和「Decompress」中存在拼寫錯誤「Decoompress」.Cpp – SysAdmin 2010-03-05 08:45:18

+0

我已更正它(請參閱編輯的代碼),但問題仍然存在。 – Manjoor 2010-03-05 09:04:05

+0

我加了一些東西試試我的原始答案 – 2010-03-05 10:01:46

1

有LIB的兩個版本可以生成, 拳頭是動態LIB,(源文件+報頭+報動態IIb)的 - >來訪問DLL

或靜態庫=(動態LIB + DLL ) - >(源文件+頭文件) - >來訪問DLL。

,如果您有動態庫>有沒有辦法來創建DLL(你不能無中生有),動態lib只是一個接口,

,但如果你有靜態庫則沒有需要DLL來訪問它是函數。

0

看看我對this question的回答,尋找可能的解決方案。幾乎肯定這會適合你...

簡而言之:啓用鏈接器設置中的「使用庫依賴項輸入」選項。如果設置爲「true」,它將強制鏈接所有符號&在每個指定爲輸入的LIB中聲明的代碼作爲項目。

+0

儘管這在理論上可以回答這個問題,但[這將是更可取的](// meta.stackoverflow.com/q/8259)在這裏包括答案的基本部分,並提供了供參考的鏈接。 – 2015-08-18 23:35:39

+0

@AntonK完成 - 增加了答案的重要部分。 – 2015-08-20 17:53:06

0

這裏的問題不是代碼是如何裝飾的,它是創建一個包含所有入口點的靜態庫的額外步驟,並且試圖從中構建dll。

如果使用__delcspec方法並首先構建靜態庫,然後在構建DLL時嘗試鏈接到它,則必須解決死代碼剝離問題。

鏈接時,obj srcs用於查找所有已裝飾的導出,並且依賴關係已解決,其他所有內容都已刪除。如果你沒有DLL src,那麼沒有obj文件(除了可能是一個dll主),你要導出的lib中的所有代碼都將被刪除(不管屬性如何)。

所以,你要麼必須:

  1. 告訴鏈接不剝離未使用的代碼,這可能是要給你很多你不想要的東西。
  2. 使用def文件手動公開出口
  3. 將dll鏈接到用於創建lib的obj文件,而不是直接鏈接到lib。
  4. 或者可能創建一個虛擬代碼,引用您要導出的某些功能。