亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

ASP.net/C#中如何調用動態鏈接庫DLL

2019-11-14 16:10:51
字體:
來源:轉載
供稿:網友

動態鏈接庫(也稱為DLL,即為“Dynamic Link Library”的縮寫)是Microsoft Windows最重要的組成要素之一,打開Windows系統文件夾,你會發現文件夾中有很多DLL文件,Windows就是將一些主要的系統功能以DLL模塊的形式實現。 
動態鏈接庫是不能直接執行的,也不能接收消息,它只是一個獨立的文件,其中包含能被程序或其它DLL調用來完成一定操作的函數(方法。注:C#中一般稱為“方法”),但這些函數不是執行程序本身的一部分,而是根據進程的需要按需載入,此時才能發揮作用。
DLL只有在應用程序需要時才被系統加載到進程的虛擬空間中,成為調用進程的一部分,此時該DLL也只能被該進程的線程訪問,它的句柄可以被調用進程所使用,而調用進程的句柄也可以被該DLL所使用。在內存中,一個DLL只有一個實例,且它的編制與具體的編程語言和編譯器都沒有關系,所以可以通過DLL來實現混合語言編程。DLL函數中的代碼所創建的任何對象(包括變量)都歸調用它的線程或進程所有。
下面列出了當程序使用 DLL 時提供的一些優點:[1]
1)        使用較少的資源
當多個程序使用同一個函數庫時,DLL 可以減少在磁盤和物理內存中加載的代碼的重復量。這不僅可以大大影響在前臺運行的程序,而且可以大大影響其他在 Windows 操作系統上運行的程序。 
2)        推廣模塊式體系結構
DLL 有助于促進模塊式程序的開發。這可以幫助您開發要求提供多個語言版本的大型程序或要求具有模塊式體系結構的程序。模塊式程序的一個示例是具有多個可以在運行時動態加載的模塊的計帳程序。 
3)        簡化部署和安裝
當 DLL 中的函數需要更新或修復時,部署和安裝 DLL 不要求重新建立程序與該 DLL 的鏈接。此外,如果多個程序使用同一個 DLL,那么多個程序都將從該更新或修復中獲益。當您使用定期更新或修復的第三方 DLL 時,此問題可能會更頻繁地出現。 
每種編程語言調用DLL的方法都不盡相同,在此只對用C#調用DLL的方法進行介紹。首先,您需要了解什么是托管,什么是非托管。一般可以認為:非托管代碼主要是基于win 32平臺開發的DLL,activeX的組件,托管代碼是基于.net平臺開發的。如果您想深入了解托管與非托管的關系與區別,及它們的運行機制,請您自行查找資料,本文件在此不作討論。 
(一)     調用DLL中的非托管函數一般方法
首先,應該在C#語言源程序中聲明外部方法,其基本形式是:
[DLLImport(“DLL文件”)]
修飾符 extern 返回變量類型 方法名稱 (參數列表)
其中:
DLL文件:包含定義外部方法的庫文件。
修飾符: 訪問修飾符,除了abstract以外在聲明方法時可以使用的修飾符。
返回變量類型:在DLL文件中你需調用方法的返回變量類型。
方法名稱:在DLL文件中你需調用方法的名稱。
參數列表:在DLL文件中你需調用方法的列表。
注意:需要在程序聲明中使用System.Runtime.InteropServices命名空間。
      DllImport只能放置在方法聲明上。
DLL文件必須位于程序當前目錄或系統定義的查詢路徑中(即:系統環境變量中Path所設置的路徑)。
返回變量類型、方法名稱、參數列表一定要與DLL文件中的定義相一致。
若要使用其它函數名,可以使用EntryPoint屬性設置,如:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
其它可選的 DllImportAttribute 屬性:阿
CharSet 指示用在入口點中的字符集,如:CharSet=CharSet.Ansi;
SetLastError 指示方法是否保留 Win32"上一錯誤",如:SetLastError=true;
ExactSpelling 指示 EntryPoint 是否必須與指示的入口點的拼寫完全匹配,如:ExactSpelling=false;
PReserveSig指示方法的簽名應當被保留還是被轉換, 如:PreserveSig=true;
CallingConvention指示入口點的調用約定, 如:CallingConvention=CallingConvention.Winapi;
此外,關于“數據封送處理”及“封送數字和邏輯標量”請參閱其它一些文章[2]。
C#例子:

1.       啟動VS.NET,新建一個項目,項目名稱為“Tzb”,模板為“Windows 應用程序”。
2.       在“工具箱”的“ Windows 窗體”項中雙擊“Button”項,向“Form1”窗體中添加一個按鈕。
3.       改變按鈕的屬性:Name為 “B1”,Text為 “用DllImport調用DLL彈出提示框”,并將按鈕B1調整到適當大小,移到適當位置。
4.       在類視圖中雙擊“Form1”,打開“Form1.cs”代碼視圖,在“namespace Tzb”上面輸入“using System.Runtime.InteropServices;”,以導入該命名空間。
5.       在“Form1.cs[設計]”視圖中雙擊按鈕B1,在“B1_Click”方法上面使用關鍵字 static 和 extern 聲明方法“MsgBox”,將 DllImport 屬性附加到該方法,這里我們要使用的是“user32.dll”中的“MessageBoxA”函數,具體代碼如下:
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);

然后在“B1_Click”方法體內添加如下代碼,以調用方法“MsgBox”:
MsgBox(0," 這就是用 DllImport 調用 DLL 彈出的提示框哦! "," 挑戰杯 ",0x30);
6.       按“F5”運行該程序,并點擊按鈕B1,便彈出如下提示框:

7.代碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsapplication1
{

    public partial classForm1 : Form
    {
        [DllImport("user32.dll",EntryPoint = "MessageBoxA")]
        static extern int MsgBox2(int hWnd,string msg, string caption, int type);
        public Form1()
        {
           InitializeComponent();
        }

       private void Form1_Load(object sender, EventArgs e)
        {

       }

        
        private void button1_Click(objectsender, EventArgs e)
        {
            MsgBox2(0," 這就是用 DllImport 調用 DLL 彈出的提示框哦! ", " 挑戰杯 ", 0x30);
        }

       private void button2_Click(object sender, EventArgs e)
        {
            MsgBox2(0," 這就是用 DllImport 調用 DLL 彈出的提示框哦222222f! ", " 222222 ", 0x30);

       }
    }
}

(二)     動態裝載、調用DLL中的非托管函數
在上面已經說明了如何用DllImport調用DLL中的非托管函數,但是這個是全局的函數,假若DLL中的非托管函數有一個靜態變量S,每次調用這個函數的時候,靜態變量S就自動加1。結果,當需要重新計數時,就不能得出想要的結果。下面將用例子說明:
1.        DLL的創建
1)        啟動Visual C++ 6.0;
2)        新建一個“Win32 Dynamic-Link Library”工程,工程名稱為“Count”;
3)        在“Dll kind”選擇界面中選擇“A simple dll project”;
4)        打開Count.cpp,添加如下代碼:
// 導出函數,使用“ _stdcall ” 標準調用
extern "C" _declspec(dllexport)int _stdcall count(int init);
int _stdcall count(int init)
{//count 函數,使用參數 init 初始化靜態的整形變量 S ,并使 S 自加 1 后返回該值
static int S=init;
S++;
return S;
}

5)       按“F7”進行編譯,得到Count.dll(在工程目錄下的Debug文件夾中)。
2.         用DllImport調用DLL中的count函數
1)        打開項目“Tzb”,向“Form1”窗體中添加一個按鈕。
2)        改變按鈕的屬性:Name為 “B2”,Text為 “用DllImport調用DLL中count函數”,并將按鈕B1調整到適當大小,移到適當位置。
3)        打開“Form1.cs”代碼視圖,使用關鍵字 static 和 extern 聲明方法“count”,并使其具有來自 Count.dll 的導出函數count的實現,代碼如下:

[DllImport("Count.dll")]
static extern int count(int init);

4)       在“Form1.cs[設計]”視圖中雙擊按鈕B2,在“B2_Click”方法體內添加如下代碼:
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, n 傳入的實參為 0 ,得到的結果是: "+count(0).ToString()," 挑戰杯 ");
MessageBox.Show(" 用 DllImport 調用 DLL 中的 count 函數, n 傳入的實參為 10 ,得到的結果是: "+count(10).ToString()+"n 結果可不是想要的 11 哦?。?! "," 挑戰杯 ");
MessageBox.Show(" 所得結果表明: n 用 DllImport 調用 DLL 中的非托管 n 函數是全局的、靜態的函數?。?! "," 挑戰杯 ");
5)        把Count.dll復制到項目“Tzb”的binDebug文件夾中,按“F5”運行該程序,并點擊按鈕B2,便彈出如下三個提示框:

  
第1個提示框顯示的是調用“count(0)”的結果,第2個提示框顯示的是調用“count(10)”的結果,由所得結果可以證明“用DllImport調用DLL中的非托管函數是全局的、靜態的函數”。所以,有時候并不能達到我們目的,因此我們需要使用下面所介紹的方法:C#動態調用DLL中的函數。
  
3.        C#動態調用DLL中的函數
因為C#中使用DllImport是不能像動態load/unload assembly那樣,所以只能借助API函數了。在kernel32.dll中,與動態庫調用有關的函數包括[3]:
①LoadLibrary(或MFC 的AfxLoadLibrary),裝載動態庫。
②GetProcAddress,獲取要引入的函數,將符號名或標識號轉換為DLL內部地址。
③FreeLibrary(或MFC的AfxFreeLibrary),釋放動態鏈接庫。
它們的原型分別是:
HMODULE LoadLibrary(LPCTSTR lpFileName);
FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
BOOL FreeLibrary(HMODULE hModule);
現在,我們可以用IntPtr hModule=LoadLibrary(“Count.dll”);來獲得Dll的句柄,用IntPtrfarProc=GetProcAddress(hModule,”_count@4”);來獲得函數的入口地址。
但是,知道函數的入口地址后,怎樣調用這個函數呢?因為在C#中是沒有函數指針的,沒有像C++那樣的函數指針調用方式來調用函數,所以我們得借助其它方法。經過研究,發現我們可以通過結合使用System.Reflection.Emit及System.Reflection.Assembly里的類和函數達到我們的目的。為了以后使用方便及實現代碼的復用,我們可以編寫一個類。
1)        dld類的編寫:
1.       打開項目“Tzb”,打開類視圖,右擊“Tzb”,選擇“添加”-->“類”,類名設置為“dld”,即dynamic loading dll 的每個單詞的開頭字母。
2.       添加所需的命名空間及聲明參數傳遞方式枚舉:
using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空間
using System.Reflection; // 使用 Assembly 類需用此 命名空間
using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空間

         在“public class dld”上面添加如下代碼聲明參數傳遞方式枚舉:
/// <summary>
/// 參數傳遞方式枚舉 ,ByValue 表示值傳遞 ,ByRef 表示址傳遞
/// </summary>
public enum ModePass
{
ByValue = 0x0001,
ByRef = 0x0002
}
3.       聲明LoadLibrary、GetProcAddress、FreeLibrary及私有變量hModule和farProc:
/// <summary>
/// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
/// <returns> 函數庫模塊的句柄 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
/// <summary>
/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTRlpProcName);
/// </summary>
/// <param name="hModule"> 包含需調用函數的函數庫模塊的句柄 </param>
/// <param name="lpProcName"> 調用函數的名稱 </param>
/// <returns> 函數指針 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/// <summary>
/// 原型是 : BOOL FreeLibrary(HMODULE hModule);
/// </summary>
/// <param name="hModule"> 需釋放的函數庫模塊的句柄 </param>
/// <returns> 是否已釋放指定的 Dll</returns>
[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
/// <summary>
/// Loadlibrary 返回的函數庫模塊的句柄
/// </summary>
private IntPtr hModule=IntPtr.Zero;
/// <summary>
/// GetProcAddress 返回的函數指針
/// </summary>
private IntPtr farProc=IntPtr.Zero;
4.       添加LoadDll方法,并為了調用時方便,重載了這個方法:

/// <summary>
/// 裝載 Dll
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
public void LoadDll(string lpFileName)
{
hModule=LoadLibrary(lpFileName);
if(hModule==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpFileName+"." ));
}
          若已有已裝載Dll的句柄,可以使用LoadDll方法的第二個版本:
public void LoadDll(IntPtr HMODULE)
{
if(HMODULE==IntPtr.Zero)
throw(new Exception(" 所傳入的函數庫模塊的句柄 HMODULE 為空 ." ));
hModule=HMODULE;
}
5.       添加LoadFun方法,并為了調用時方便,也重載了這個方法,方法的具體代碼及注釋如下:
/// <summary>
/// 獲得函數指針
/// </summary>
/// <param name="lpProcName"> 調用函數的名稱 </param>
public void LoadFun(string lpProcName)
{ // 若函數庫模塊的句柄為空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函數庫模塊的句柄為空 , 請確保已進行 LoadDll 操作 !"));
// 取得函數指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));
}
/// <summary>
/// 獲得函數指針
/// </summary>
/// <param name="lpFileName"> 包含需調用函數的 DLL 文件名 </param>
/// <param name="lpProcName"> 調用函數的名稱 </param>
public void LoadFun(string lpFileName,string lpProcName)
{ // 取得函數庫模塊的句柄
hModule=LoadLibrary(lpFileName);
// 若函數庫模塊的句柄為空,則拋出異常
if(hModule==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpFileName+"." ));
// 取得函數指針
farProc = GetProcAddress(hModule,lpProcName);
// 若函數指針,則拋出異常
if(farProc==IntPtr.Zero)
throw(new Exception(" 沒有找到 :"+lpProcName+" 這個函數的入口點 "));
}
6.       添加UnLoadDll及Invoke方法,Invoke方法也進行了重載:
/// <summary>
/// 卸載 Dll
/// </summary>
public void UnLoadDll()
{
FreeLibrary(hModule);
hModule=IntPtr.Zero;
farProc=IntPtr.Zero;
}

 

 

asp.net 如何生成DLL文件,并調用


發表日期:2009-12-3

新浪微博QQ空間QQ微博百度搜藏騰訊朋友QQ收藏百度空間人人網開心網

 

 

使用csc命令將.cs文件編譯成.dll的過程

很多時候,我們需要將.cs文件單獨編譯成.dll文件, 操作如下:

打開命令窗口->輸入cmd到控制臺->cd C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322

轉到vs.net安裝的該目錄下->執行csc命令csc /target:library File.cs->在該目錄下產生一個對應名字的.dll文件(前提:把.cs文件放到C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322目錄下)

csc命令的方式很多,請參考以下

譯 File.cs 以產生 File.exe

csc File.cs 編譯 File.cs 以產生 File.dll

csc /target:library File.cs 編譯 File.cs 并創建 My.exe

csc /out:My.exe File.cs 通過使用優化和定義 DEBUG 符號,編譯當前目錄中所有的 C# 文件。輸出為 File2.exe

csc /define:DEBUG /optimize /out:File2.exe *.cs 編譯當前目錄中所有的 C# 文件,以產生 File2.dll 的調試版本。不顯示任何徽標和警告

csc /target:library /out:File2.dll /warn:0 /nologo /debug *.cs 將當前目錄中所有的 C# 文件編譯為 Something.xyz(一個 DLL)

csc /target:library /out:Something.xyz *.cs 編譯 File.cs 以產生 File.dll

csc /target:library File.cs這個就是我們使用最多的一個命令,其實可以簡單的寫成csc /t:library File.cs,另外的一個寫法是 csc /out:mycodebehind.dll /t:library mycodebehind.cs,這個可以自己指定輸出的文件名。

csc /out:mycodebehind.dll /t:library mycodebehind.cs mycodebehind2.cs,這個的作用是把兩個cs文件裝到一個.dll文件里

舉例(摘于網絡)

一、 動態鏈接庫

        什么是動態鏈接庫?DLL三個字母對于你來說一定很熟悉吧,它是Dynamic Link Library 的縮寫形式,動態鏈接庫 (DLL) 是作為共享函數庫的可執行文件。動態鏈接提供了一種方法,使進程可以調用不屬于其可執行代碼的函數。函數的可執行代碼位于一個 DLL 中,該 DLL 包含一個或多個已被編譯、鏈接并與使用它們的進程分開存儲的函數。DLL 還有助于共享數據和資源。多個應用程序可同時訪問內存中單個 DLL 副本的內容。

  和大多數程序員一樣,你一定很使用過DLL吧。也曾感受到它的帶給你程序設計和編碼上的好錯吧今天我想和大家探討一個主題:如何在C#創建和調用DLL(動態鏈接庫), 其實在很大意義上而講,DLL讓我更靈活的組織編寫我們的應用程序,作為軟件設計者,可一個根據它來達到很高的代碼重用效果。下面我來介紹一下在C#中如何創建和調用DLL。

二、準備工作

  我們需要對我們接下來要做的事情做個簡單的介紹,在本文我們將利用C#語言創建一個名為 MyDLL.DLL的動態鏈接庫,在這個動態鏈接庫文件中我們將提供兩個功能一個是對兩個參數交換他們的值,另一個功能是求兩個參數的最大公約數。然后創建一個應用程序使用這個DLL。運行并輸出結果。

三、創建DLL

讓我們創建以下三個C#代碼文件:

1、 MySwap.cs



}

using System;

namespace MyMethods

{

     public class SwapClass

     {

          public static bool Swap(ref long i,ref long j)

          {

               i = i+j;

               j = i-j;

               i = i-j;

               return true;

           }

       }

}

2、MyMaxCD.cs

using System;

namespace MyMethods

{

     public class MaxCDClass

     {

          public static long MaxCD(long i, long j)

          {

               long a,b,temp;

               if(i>j)

               {

                    a = i;

                    b = j;

               }

               else

               {

                    b = i;

                    a = j;

               }

               temp = a % b;

               while(temp!=0)

               {

                    a = b;

                    b = temp;

                    temp = a % b;

               }

               return b;

            }

       }

}

 需要注意的是:我們在制作這兩個文件的時候可以用Visual Studio.NET或者其他的文本編輯器,就算是記事本也可以。這兩個文件雖然不在同一個文件里面,但是他們是屬于同一個namespace(名稱空間)這對以后我們使用這兩個方法提供了方便。當然他們也可以屬于不同的名稱空間,這是完全可以的,但只是在我們應用他們的時候就需要引用兩個不同的名稱空間,所以作者建議還是寫在一個名稱空間下面比較好。

  接下來的任務是把這兩個cs文件變成我們需要的DLL文件。方法是這樣的:在安裝了Microsoft.NET Framework的操作系統上,我們可以在Windows所在目錄下找到Microsoft.NET目錄。在這個目錄下面提供了C#的編譯器,CSC.EXE運行:csc /target:library /out:MyDLL.DLL MySwap.cs MyMaxCD.cs,完成后可在本目錄下面找到我們剛才生成的MyDLL.DLL文件/target:library 編譯器選項通知編譯器輸出 DLL 文件而不是 EXE 文件。后跟文件名的 /out 編譯器選項用于指定 DLL 文件名。如果/out后面不跟文件名編譯器使用第一個文件 (MySwap.cs) 作為 DLL 文件名。生成的文件為MySwap.DLL文件。

  OK!我們創建動態鏈接庫文件的任務完成了,現在是我們享受勞動成果的時候了,下面我將介紹如何使用我們所創建的動態鏈接庫文件。   四、使用DLL   我們簡單寫一個小程序來測試一下我們剛才寫的兩個方法是否正確,好吧,跟我來:

MyClient.cs

using System;

using MyMethods; //這里我們引用剛才定義的名稱空間,如果剛才的兩個文件我們寫在兩個不同的名稱空間

class MyClient

{

     public static void Main(string[] args)

     {

         if (args.Length != 2)

         {

              Console.WriteLine("Usage: MyClient <num1> <num2>");

              return;

         }

          long num1 = long.Parse(args[0]);

          long num2 = long.Parse(args[1]);

          SwapClass.Swap(ref num1,ref num2);

   // 請注意,文件開頭的 using 指令使您得以在編譯時使用未限定的類名來引用 DLL 方法

          Console.WriteLine("The result of swap is num1 = {0} and num2 ={1}",num1, num2);

          long maxcd = MaxCDClass.MaxCD(num1,num2);

          Console.WriteLine("The MaxCD of {0} and {1} is {2}",num1, num2, maxcd);

     }

}

若要生成可執行文件 MyClient.exe,請使用以下命令行:

csc /out:MyClient.exe /reference:MyDLL.DLL MyClient.cs

/out 編譯器選項通知編譯器輸出 EXE 文件并且指定輸出文件名 (MyClient.exe)。/reference 編譯器選項指定該程序所引用的 DLL 文件。

五、執行

若要運行程序,請輸入 EXE 文件的名稱,文件名的后面跟兩個數字,例如:MyClient 123 456

六、輸出

The result of swap is num1 = 456 and num2 = 123

The MaxCD of 456 and 123 is 3

七、小結

動態鏈接具有下列優點:

 ?。薄⒐澥却婧蜏p少交換操作。很多進程可以同時使用一個 DLL,在內存中共享該 DLL 的一個副本。相反,對于每個用靜態鏈接庫生成的應用程序,Windows 必須在內存中加載庫代碼的一個副本。

  2、節省磁盤空間。許多應用程序可在磁盤上共享 DLL 的一個副本。相反,每個用靜態鏈接庫生成的應用程序均具有作為單獨的副本鏈接到其可執行圖像中的庫代碼。    ?。场⑸壍?DLL 更為容易。DLL 中的函數更改時,只要函數的參數和返回值沒有更改,就不需重新編譯或重新鏈接使用它們的應用程序。相反,靜態鏈接的對象代碼要求在函數更改時重新鏈接應用程序。

 ?。础⑻峁┦酆笾С?。例如,可修改顯示器驅動程序 DLL 以支持當初交付應用程序時不可用的顯示器。

 ?。?、支持多語言程序。只要程序遵循函數的調用約定,用不同編程語言編寫的程序就可以調用相同的 DLL 函數。程序與 DLL 函數在下列方面必須是兼容的:函數期望其參數被推送到堆棧上的順序,是函數還是應用程序負責清理堆棧,以及寄存器中是否傳遞了任何參數。

 ?。丁⑻峁┝藬U展 MFC 庫類的機制??梢詮默F有 MFC 類派生類,并將它們放到 MFC 擴展 DLL 中供 MFC 應用程序使用。

 ?。?、使國際版本的創建輕松完成。通過將資源放到 DLL 中,創建應用程序的國際版本變得容易得多??蓪⒂糜趹贸绦虻拿總€語言版本的字符串放到單獨的 DLL 資源文件中,并使不同的語言版本加載合適的資源。

  使用 DLL 的一個潛在缺點是應用程序不是獨立的;它取決于是否存在單獨的 DLL 模塊。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品免费视频xxxx| 日本高清视频一区| 日韩欧美一区二区三区久久| 欧美午夜激情视频| 国产成人高潮免费观看精品| 欧美日韩国产丝袜美女| 欧美成人激情视频免费观看| 欧美激情精品久久久久久免费印度| 国产精品99导航| 日韩美女在线观看一区| 久久影院在线观看| 欧美情侣性视频| 国产亚洲a∨片在线观看| 亚洲美女av在线播放| 亚洲乱码国产乱码精品精天堂| 欧洲亚洲免费在线| 精品久久久久久久大神国产| 欧美国产日韩免费| 亚洲综合色av| 欧美重口另类videos人妖| 色诱女教师一区二区三区| 在线观看精品自拍私拍| 久久精品影视伊人网| 中文字幕日韩视频| 亚洲美女在线视频| 2019中文字幕在线免费观看| 久久天天躁夜夜躁狠狠躁2022| 欧美精品做受xxx性少妇| www.日本久久久久com.| 国产精品国产福利国产秒拍| 91久久精品美女| 正在播放欧美一区| 亚洲欧美自拍一区| 亚洲最大在线视频| 亚洲精品二三区| 亚洲va久久久噜噜噜| 亚洲综合第一页| 91高清免费在线观看| 欧美风情在线观看| 日本伊人精品一区二区三区介绍| 国产精品99蜜臀久久不卡二区| 神马久久久久久| 亚洲天堂免费观看| 欧美激情第99页| 亚洲tv在线观看| 色哟哟亚洲精品一区二区| 91av在线免费观看视频| 91国产精品视频在线| 久久99久久久久久久噜噜| 国产精品久久久久久久久久久久久久| 精品久久久久久中文字幕| 亚洲va电影大全| 97色在线播放视频| 久久久久成人精品| 成人精品aaaa网站| 久久夜色撩人精品| 一区二区三区亚洲| 精品久久久久久中文字幕一区奶水| 在线观看国产精品日韩av| 日韩免费在线电影| 久久精品国产91精品亚洲| 亚洲www永久成人夜色| 欧美久久久精品| 久久91精品国产| 日韩精品极品视频免费观看| 国产精品美女主播在线观看纯欲| 伊人伊人伊人久久| 爽爽爽爽爽爽爽成人免费观看| 精品久久久久久久久久久久久| 亚洲国产精品久久久久秋霞不卡| 国产精品久久久久7777婷婷| 欧美亚洲第一页| 高清日韩电视剧大全免费播放在线观看| 久久午夜a级毛片| 亚洲欧洲一区二区三区久久| 亚洲激情 国产| 正在播放亚洲1区| 色噜噜久久综合伊人一本| 国语自产偷拍精品视频偷| 精品日韩中文字幕| 国产精品免费视频xxxx| 欧美性猛交xxxxx免费看| 国产精品久久久久久久久久免费| 有码中文亚洲精品| 亚洲白拍色综合图区| 欧美性视频在线| 久久不射热爱视频精品| 91av视频在线播放| 成人黄色影片在线| 亚洲色图综合久久| 日韩亚洲欧美成人| 国产精品午夜一区二区欲梦| 国产99久久精品一区二区永久免费| 91精品久久久久久久久青青| 欧美成人第一页| 92福利视频午夜1000合集在线观看| 国产精品女视频| 久久精品小视频| 国产成人精品视频在线观看| 亚洲四色影视在线观看| 欧美日韩高清在线观看| 丝袜亚洲欧美日韩综合| 欧美一级在线亚洲天堂| 日韩av在线导航| 韩国欧美亚洲国产| 久久久久久久久久久网站| 亚洲成成品网站| 欧美成人激情图片网| 国产午夜精品全部视频在线播放| 日韩精品在线观看网站| 97色在线观看| 日韩美女在线观看一区| 91欧美激情另类亚洲| 久久久日本电影| 综合网日日天干夜夜久久| 另类视频在线观看| 久久亚洲国产精品成人av秋霞| 亚洲欧美综合精品久久成人| 国产亚洲人成a一在线v站| 亚洲一级片在线看| 欧美日韩午夜激情| 国产亚洲精品va在线观看| 午夜精品久久17c| 亚洲国产成人精品女人久久久| 欧美成人午夜激情视频| 伊人久久精品视频| 日韩av免费看网站| 日韩欧美在线视频观看| 亚洲国产精品久久| 久久香蕉精品香蕉| 国产精品久久久久久久久久尿| 日韩中文字幕网站| 欧美亚洲国产精品| 欧美整片在线观看| 萌白酱国产一区二区| 中文字幕精品影院| 国产成人精品久久二区二区| 精品呦交小u女在线| 亚洲桃花岛网站| 国产日韩欧美一二三区| 欧美日韩精品在线视频| 日韩美女视频免费在线观看| 国产亚洲美女精品久久久| 日韩av电影免费观看高清| 日韩av日韩在线观看| 欧美性高跟鞋xxxxhd| 国产91精品在线播放| 国产丝袜一区二区三区| 欧美—级a级欧美特级ar全黄| 亚洲视频自拍偷拍| 北条麻妃一区二区在线观看| 中文日韩电影网站| 亚洲精品成人久久| 伊人久久久久久久久久久久久| 国产精品极品美女在线观看免费| 国产啪精品视频网站| 中文字幕日韩av| 红桃av永久久久| 国产午夜精品免费一区二区三区| 国产精品美女在线| 亚洲xxxx3d| 色中色综合影院手机版在线观看| 久久精品男人天堂| 羞羞色国产精品|