數(shù)學上不是有斜二測畫法,算好坐標即可畫出
成都創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站建設、成都做網(wǎng)站與策劃設計,貢嘎網(wǎng)站建設哪家好?成都創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設十多年,網(wǎng)設計領域的專業(yè)建站公司;建站業(yè)務涵蓋:貢嘎等地區(qū)。貢嘎做網(wǎng)站價格咨詢:028-86922220
或者用AnyCAD的.Net圖形控件
也可以調(diào)用matlab 實現(xiàn)
VB.NET和VB6.0有什么區(qū)別
Visual Basic .NET是Microsoft Visual Studio .NET套件中主要組成部分之一。.NET版本的Visual Basic增加了更多特性,而且演化為完全面向?qū)ο螅ň拖馛++)的編程語言。本文將介紹VB.NET的新特性,并比較VB6.0/VB.NET之間的區(qū)別,闡述如何利用VB.NET編寫簡單的應用程序。
1.1 什么是 VB.NET? Microsoft推出全新的編程和操作系統(tǒng)Framework——.NET,支持多種語言利用公共.NET庫開發(fā)應用程序,這些應用程序在.NET Framework上運行。使用Visual Basic在.NET Framework上編程,這就是VB.NET。
首先,讓我演示在VB.NET中寫最簡單的控制臺程序:Hello World。
1.2 Hello, World!“Hello World!”是初學者學習Windows編程的代表性程序。我們的第一個程序就叫做“Hello VB.NET World!”。該程序在控制臺輸出一句話:“Hello VB.NET World!”,代碼如下所示:
代碼 1.1: Hello VB.NET World例子Imports System
Module Module1
Sub Main()
System.Console.WriteLine("Hello VB.NET World!")
End Sub
End Module
1.3 VB.NET 編輯器和編譯器你可以在記事本或VS.NET IDE等任意文本編輯器中撰寫上述代碼,然后保存為HelloWorld.vb。 代碼編寫完成之后,要么在命令行、要么在VS.NET IDE中編譯它。在Microsoft .NET Framework SDK中已經(jīng)包括VB.NET編譯器vbc.exe[][1],從IDE或是命令行都可以調(diào)用。要從命令行編譯HelloWorld.vb,請在命令行窗口輸入
vbc HelloWorld.vb /out:HelloWorld.exe /t:exe
編譯結(jié)束后,HelloWorld.exe被創(chuàng)建到當前目錄下。在資源管理其中雙擊圖標或在命令行執(zhí)行,程序正確地運行了。祝賀你進入VB.NET開發(fā)者的行列。
Imports 語句
如你所知,大部分的.NET類型都在名字空間(namespace)中定義。Namespace是定義和管理類別的范疇。察看.NET Framework Class Library,可以看到數(shù)以百計的namespace。例如,System namespace就包括了Console、Object等類型定義。如果想使用Console類,需要用Imports指令導入System namespace。如下所示:
Imports System甚至可以明確地調(diào)用namespace而無需用Import導入。下面的例子展示了不用Import的“Hello World!”程序:
代碼1.2: Hello VB.NET World例子Module Module1
Sub Main()
System.Console.WriteLine("Hello VB.NET World!")
End SubEnd Module1.4 解析 "Hello VB.NET World!"程序第一行是:
Imports System; System namespace定義了Console類,該類用于讀寫控制臺(命令行窗口)。然后你定義了一個module:Module Module1
…End Module所有的VB程序都包括一個Main()方法,即應用程序入口點。在例子程序中,我們調(diào)用Console.WriteLine()向控制臺寫入“Hello VB.NET World!”:
Sub Main()
Console.WriteLine(“Hello VB.NET World!”) End SubWriteLine()方法歸屬于Console類,它負責向控制臺寫一個帶有行結(jié)束符的字符串。如前所述,Console類定義于System namespace,你通過直接引用來控制類成員。
Console類負責讀寫系統(tǒng)控制臺。讀控制臺輸入用Read和ReadLine方法,向控制臺輸出用WriteLine方法。
表1.1 Console類定義的方法
方法 用途 例子
Read 讀入單個字符 int i = Console.Read();
ReadLine 讀入一行 string str = Console.ReadLine();
Write 寫一行 Console.Write("Write: 1");
WriteLine 寫一行,并帶上行結(jié)束符
Console.WriteLine("Test Output Data with Line");
1.5 VB.NET有什么新特點? VB.NET比 VB6.0更加穩(wěn)定,而且完全面向?qū)ο?。也許你還記得,VB6.0不支持繼承、重載和接口,所以不是真正面向?qū)ο蟮?。而VB.NET則支持這些面向?qū)ο筇匦?。VB6.0有兩個薄弱環(huán)節(jié)——多線程和異常處理。在VB.NET中,開發(fā)多線程應用和使用C++/C#別無二致,結(jié)構(gòu)化異常處理也得到支持。稍后我們會詳細解釋這些特性。
下面是VB.NET的特性列表——
·面向?qū)ο蟮木幊陶Z言。支持繼承、重載、接口、共享成員和構(gòu)造器?!ぶС炙械腃LS特性,如存取控制.NET類、與其它.NET語言交互、元數(shù)據(jù)、公共數(shù)據(jù)類型、委托等等?!ざ嗑€程支持?!そY(jié)構(gòu)化異常處理。 1.6 名字空間與集合 前面討論了我們的第一個VB.NET程序。該程序中首先引人注意的是名字空間(namespace)。在.NET參考文檔中,你會發(fā)現(xiàn)每個類都歸屬于某個namespace。那么,namespace到底是什么?
一個namespace是類和組件的邏輯組合,其目的在于將.NET class按類別定義。微軟借用了C++ class packaging概念:namespace來描述這種組合。.NET Framework中的組件被稱為集合(assembly)。全部.NET代碼在數(shù)百個庫文件(DLL)中定義。Namespace把assembly中定義的類組織起來。一個namespace可以包括多個assembly,一個assembly也可以在多個namespace中定義。 namespace樹的根節(jié)點是System namespace。在.NET Library中,每個class都在一組相似的類別中定義。例如,System.Data namespace只包括數(shù)據(jù)相關(guān)類。同樣,System.Multithreading只包括多線程類。
在使用.NET支持的語言(如C#、VB.NET、C++.NET等)創(chuàng)建新應用程序時,你會注意到每個應用程序都被定義為一個namespace,而所有的class都歸屬于這個namespace。通過引用這個namespace,其它應用程序就能存取這些class。 在.NET中,代碼被編譯為中間語言(Intermediate Language,IL),assembly中存儲了IL代碼、元數(shù)據(jù)和其它資源文件。同一個assembly可以附屬于一個或多個Exe/DLL。所有的.NET庫都存儲在assembly中。
1.7 VB.NET: 完全面向?qū)ο蟮木幊陶Z言抽象、封裝、多態(tài)、繼承是面向?qū)ο笳Z言的四個基本屬性。VB6.0不支持繼承,而VB.NET則不然。所以,和C++一樣,VB.NET也是完全面向?qū)ο蟮木幊陶Z言。
Class 和 ModuleVB.NET用Class...End Class語句對創(chuàng)建class。每個VB.NET至少包括一個Module(模塊)。Module在Module…End Module語句對中實現(xiàn)。應用程序的主要模塊是Main方法,亦即應用程序入口點。
和VB6.0相似的地方是,都可以使用Function/Sub關(guān)鍵字定義方法。下面的例子顯示了如何創(chuàng)建class、添加方法,并從主程序調(diào)用方法: Imports System
Module Module1
Sub Main()
Dim cls As TestClass = New TestClass
Console.WriteLine(cls.MyMethod)
End Sub
Class TestClass
Function MyMethod() As String
Return "Test Method"
End Function
End Class
End ModuleProperty屬性(Property)是類變量的公共描述。Property…End Property語句用以創(chuàng)建property。屬性的Get/Set方法分別用于取得和設置屬性值。下面的例子中,Data是TestClass的屬性。
Imports System
Imports System.Console
Module Module1
Sub Main()
Dim cls As TestClass = New TestClass
WriteLine(cls.MyMethod)
WriteLine(cls.Data)
cls.Data = "New Data"
WriteLine(cls.Data)
End Sub
End Module
Class TestClass
Private strData As String = "Some Data"
Function MyMethod() As String
Return "Test Method!"
End Function
' Adding Data property to the class
Public Property Data() As String
Get
Return strData
End Get
Set(ByVal Value As String)
strData = Value
End Set
End Property
重載VB.NET通過overload關(guān)鍵字支持方法重載。使用這個關(guān)鍵字,你可以定義同名但不同參數(shù)的方法。
類成員訪問域
除了原有的Private和Public,VB.NET引入了幾個新關(guān)鍵字。全部訪問域關(guān)鍵字列表如下:
關(guān)鍵字 作用域
Private 限于class內(nèi)部
Public 可以從class外訪問
Friend 限于class所屬的應用程序內(nèi)
Protected 只能被class和其派生類訪問
Protected Friend 能被class、應用程序和派生類訪問
繼承繼承是面向?qū)ο缶幊陶Z言中最常用的技術(shù)。繼承讓你能夠重用類代碼和功能。
VB.NET支持繼承,而VB6.0則不支持。繼承的好處在于你能使用任何人編寫的類,從這些類派生自己的類,然后在自己的類中調(diào)用父類功能。在下面的例子中,Class B派生自Class A,我們將從Class B中調(diào)用Class A的方法MethodA。
Imports System
Imports System.Console
Module Module1
Sub Main()
Dim bObj As B = New B
WriteLine(bObj.MethodA())
End Sub
End Module
' Class A defined
Public Class A
Function MethodA() As String
Return "Method A is called."
End Function
End Class
'Class B, inherited from Class A. All members (Public and Protected)
' can be access via B now.
Public Class B
Inherits A
Function MethodB() As String
Return "Method B is called."
End Function
End Class
可以從一個class中派生多個自定義class,也可以從多個class派生一個自定義class。
共享的成員類的共享成員被類的所有實體共享。共享成員可能是屬性、方法或字段/值域。在你不想讓用戶全面控制自己的類時,共享成員相當有用。例如,你可以開發(fā)一個類庫,讓用戶通過共享成員使用其中的部分功能。
可以通過class本身引用共享成員,而無需通過類的實體。例如:Module Module1
Sub Main()
WriteLine(A.MethodA())
End Sub
End Module
' Class A defined
Public Class A
Shared Function MethodA() As String
Return "Method A is called."
End Function
End Class
多線程VB語言的一大弱點就是缺乏編寫自由線程(free-threaded)程序的能力。在.NET Framework中,所有語言共享CRL(Common Runtime Library,公共運行庫),也就是說,你可以用VB.NET、C#或其它.NET語言編寫同樣的程序。
System.Threading namespace定義了線程類。我們只需要引入System.Threading namespace,即可使用線程類。
System.Threading.Thread類提供線程對象,可以使用Thread類創(chuàng)建或破壞線程。
創(chuàng)建線程使用Thread類的實體創(chuàng)建一個新線程,然后用Thread.Start方法開始執(zhí)行線程。線程構(gòu)造器接受一個參數(shù),該參數(shù)指明你要在線程中執(zhí)行的procedure。在下例中,我想在oThread1(Thread類的一個實體)的第二線程中執(zhí)行SecondThread過程:
oThread1 = New Thread(AddressOf SecondThread)
SecondThread procedure looks like below:
Public Sub SecondThread()
Dim i As Integer
For i = 1 To 10
Console.WriteLine(i.ToString())
Next
End Sub
然后,調(diào)用Thread.Start()開始線程:
oThread1.Start()
下面的代碼創(chuàng)建兩個第二線程:
Imports System
Imports System.Threading
Module Module1
Public oThread1 As Thread
Public oThread2 As Thread
Sub Main()
oThread1 = New Thread(AddressOf SecondThread)
oThread2 = New Thread(AddressOf ThirdThread)
oThread1.Start()
oThread2.Start()
End Sub
Public Sub SecondThread()
Dim i As Integer
For i = 1 To 10
Console.WriteLine(i.ToString())
Next
End Sub
Public Sub ThirdThread()
Dim i As Integer
For i = 1 To 10
Console.WriteLine("A" + i.ToString())
Next
End Sub
End Module
破壞線程 調(diào)用Abort方法來破壞(中止)一個線程。在調(diào)用Abort之前,確保用IsAlive判斷線程處于活動狀態(tài)。
If oThread1.IsAlive Then
oThread1.Abort()
End If
暫停線程可以使用Sleep方法來暫停線程執(zhí)行。Sleep方法接受一個以毫秒為單位的參數(shù),指明線程應當暫停多長時間。
下面的例子讓線程暫停1秒鐘:
oThread2.Sleep(1000)你也可以使用Suspend和Resume方法來掛起和繼續(xù)線程執(zhí)行。
設定線程優(yōu)先級Thread類的Priority屬性用于設定線程優(yōu)先級。該屬性可以設置為Normal,AboveNormal,BelowNormal,Highest和Lowest。如:
oThread2.Priority = ThreadPriority.Highest線程與Apartment使用ApartmentState屬性設置線程的apartment類型,該屬性值可以為STA,MTA或是Unknown[][2]:
oThread.ApartmentState = ApartmentState.MTAMTS意味著可以使用多線程模式,而STA則只能是單線程執(zhí)行。
Public Enum ApartmentState
{
STA = 0,
MTA = 1,
Unknown = 2,
}
1.8 結(jié)構(gòu)化異常處理異常處理也被稱之為錯誤處理。作為VB程序員,你一定對On Error Goto和On Error Resume Next這些VB6.0錯誤處理語句耳熟能詳。這種類型的錯誤處理被稱為非結(jié)構(gòu)化異常處理(Unstructured Exception Handling)。而在VB.NET中,Microsoft推出了結(jié)構(gòu)化異常處理機制。VB.NET支持類似C++的TryCatch..Finally控制。Try..Catch..Finally結(jié)構(gòu)如下: Try
' 可能導致異常的代碼
Catch
' 當異常發(fā)生時處理異常的代碼
Finally
' 清理現(xiàn)場
End Try
Try語句塊用以拋出異常。如果異常發(fā)生,在Catch語句塊中處理。Finally語句塊是可選的,在需要釋放資源時特別有用。
1.9 VB6.0與VB.NET的不同之處除了上面談到的語言進化,還有一些語法上的變化。所有這些語言和語法的變化在MSDN中均可查到,本文只作簡單介紹。
數(shù)據(jù)類型(Data Type)的改變VB.NET中有些數(shù)據(jù)類型得到改進。下面是變化對照表。
數(shù)據(jù)類型 VB6.0 VB.NET
Integer 16 bit size 32 bit size
Long 32 bit size 64 bit size
Currency 用于存儲大浮點數(shù) 被decimal替代,支持更高精度
Variant 可以存儲任意類型數(shù)據(jù) 被Object類型替代,也可以存儲任意類型數(shù)據(jù),但結(jié)果更好
Date Date類型被存儲為double 引入DateTime類型,用于存儲不同格式的日期
在VB.NET中,Short數(shù)據(jù)類型是16 bit的。Short,Integer和Long都等同于CLR的System.Int16、System.Int32和System.Int64類型。 變量聲明的變化在VB6.0中,變量聲明有許多限制。其中之一就是不能同行聲明多個變量。如果一定要在一行中聲明多個變量,就一定得指明每個變量的類型,否則將被默認為Variant類型。
Dim a1, a2 As Integer Dim a3 As Integer, a4 As Integer 第一行中的a1是Variant類型,a2是Integer類型。第二行中兩個變量都是Integer類型。VB.NET支持同行聲明多個變量,舉例如下:
Dim a1, a2, a3 As Integer 變量初始化是另一個問題。在VB6.0中不能同時聲明和初始化變量,而VB.NET則支持這個特性。
Dim name As String = "Mahesh"System.Console.Write(name) 聲明常量也可以照此辦理:Const DT_COUNT As Integer = 23 New關(guān)鍵字。在VB.NET中,New關(guān)鍵字用于創(chuàng)建對象。由于數(shù)據(jù)類型是對象,所以New關(guān)鍵字用以創(chuàng)建一個數(shù)據(jù)類型對象。
Dim i As Integer = New Integer()i = 10System.Console.WriteLine(i.ToString()) 代碼塊級別支持。像C++一樣,VB.NET支持代碼塊級別的作用域檢查。在語句塊中聲明的變量只在塊內(nèi)有效。
For i = 1 To 10Dim p As LongSystem.Console.WriteLine(i.ToString())NextSystem.Console.WriteLine(p.ToString()) 這段代碼在VB.NET中會得到一個編譯錯誤,因為p在For..Next語句塊之外不可訪問。在VB6.0中這段代碼可以通過。
改進了的類型安全
在VB6.0中,當你聲明一個對外部過程的引用時,可以指定任意類型的參數(shù)為As Any。Any關(guān)鍵字禁止了類型檢查,允許任意數(shù)據(jù)類型傳入和返回。
VB.NET不支持Any關(guān)鍵字。你必須指定每個參數(shù)和返回值的數(shù)據(jù)類型。數(shù)組VB.NET對數(shù)組作了明顯的改動。
數(shù)組范圍。在VB.NET中,你需要格外留意數(shù)組范圍問題。VB6.0默認數(shù)組下界為0,故數(shù)組中的元素數(shù)量等與數(shù)組上界值加一。下面的數(shù)組界限從A(0)到A(10),共有11個元素:
Dim A(10) As Single可以使用Option Base改變下界值為1。在VB.NET中,數(shù)組和C++一樣,下界值為0,不支持Option Base。注意:MSDN文檔指出數(shù)組只能包括與其尺寸相等的元素數(shù)量,例如:Dim A(10) As Integer 只能包括10個元素(從A(0)到A(9)),但在編譯下面這段代碼時我發(fā)現(xiàn)它運行良好,看起來數(shù)組中容納了11個元素。
Dim A(10) As Integer A(0) = 12 A(2) = 24 A(10) = 23 System.Console.WriteLine(A(0).ToString()) System.Console.WriteLine(A(10).ToString())System.Console.WriteLine(UBound(A).ToString()) System.Console.WriteLine(LBound(A).ToString()) Lbound和Ubound分別返回 0與10。ReDim和Fixed Array。你可以在VB6.0中指定固定長度的數(shù)組。
Dim ArrWeekDays(0 To 6) As Integer
這里的ArrWeekDays數(shù)組是固定長度的,不能用ReDim語句改變長度。VB.NET不支持固定長度數(shù)組,所以ReDim總是有效。
可以用下面兩種方式聲明數(shù)組: Dim ArrWeekDays(6) As IntegerDim ArrWeekDays() As Integer = {1, 2, 3, 4, 5, 6} ReDim語句。在VB6.0中,ReDim用于初始化動態(tài)數(shù)組。在VB.NET中你不能把它當作聲明用。ReDim只能用于改變數(shù)組長度,不過不能改變數(shù)組維度。
Variant對陣ObjectVB6.0中的Variant數(shù)據(jù)類型能存儲任意類型變量,VB.NET中Object具備相同能力。
算術(shù)操作符VB.NET支持類似C++的快捷方式。下面的表格顯示了常規(guī)操作與快捷操作的不同之處??旖莘绞揭部捎糜?、/、|、等操作符。
操作符 常規(guī)語法 快捷方式加法 A = A+5 A +=5 減法 A = A – 5 A -+ 5固定長度字符串
在VB6.0中,可以在聲明字符串時指定其長度。VB.NET不支持固定長度字符串。
布爾操作符VB6.0中的And、Or或是Xor語句是按位操作符。而在VB.NET中,它們是布爾操作符。執(zhí)行這些操作將返回true或false。VB.NET引入新操作符來完成按位操作。
操作符 描述 BitAnd 按位AndBitOr 按位OrBitXor 按位XorBitNot 按位Not結(jié)構(gòu)與自定義類型在VB6.0中,你使用Type…End Type語句塊創(chuàng)建結(jié)構(gòu)或自定義類型。例如:
Type StdRec
StdId As Integer
StdName As String End Type
VB.NET引入新的語法:Structure。Type…End Type不再被支持。Structure…End Structure與C++用法相同??梢灾付ńY(jié)構(gòu)中每個元素的可訪問域,如Public、Protected、Friend、Protected Friend、Private等。例如:
Structure StdRec
Public StdId As Integer Public StdName As String
Private StdInternal As String End StructureVB.NET中的Structures就像類一樣,也可以擁有方法和屬性。New和Nothing關(guān)鍵字VB6.0中,AS New和Nothing關(guān)鍵字用于聲明一個對象并初始化它。 VB.NET不支持隱式創(chuàng)建對象。如前所言,甚至連數(shù)據(jù)類型都是對象。你可以采用以下兩種方法創(chuàng)建數(shù)據(jù)類型或?qū)ο螅?Dim i As Integer Dim i As Integer = New Integer() // Do something if i = Nothing Then End If 不支持Set語句VB6.0使用Set語句指派對象。例如:Set myObj = new MyObjectSet a = b在VB.NET中,不需要使用Set指派對象。例如:myObj = new MyObj()a = b過程(procedure)語法的變化在VB.NET中過程語法有了很多變化。例如類似C++的過程調(diào)用方式、ByVal(傳值)為默認類型、Optional關(guān)鍵字、return語句等等。類似C++的過程調(diào)用方式 VB6.0允許不用加圓括號調(diào)用過程(sub)。不過,用Call語句調(diào)用函數(shù)或sub時,一定要使用圓括號。例如:Dim I as IntegerCall EvaluateData(2, i) EvaluateData 2, i 在VB.NET中,所有的方法調(diào)用都需要圓括號,而Call語句則是可選的。 ByVal是默認參數(shù)類型在VB6.0中,在調(diào)用函數(shù)或sub時ByRef(傳址)是默認類型。那意味著所有改變將反映到傳入的變量。VB.NET改變了這種方式?,F(xiàn)在,默認的參數(shù)類型是ByVal(傳值)。 Optional關(guān)鍵字VB6.0使用Optional關(guān)鍵字可用來讓用戶決定傳入一個默認值,之后在調(diào)用IsMissing函數(shù)判斷參數(shù)是否有效。 而在VB.NET中,每個可選參數(shù)必須聲明其默認值,無需調(diào)用IsMissing函數(shù)。例如:Sub MyMethod(Optional ByVal i As Integer = 3)
Return語句VB.NET的Return語句與C++相似。使用Return語句把控制權(quán)從過程返還給調(diào)用者。在VB6.0中,Return語句與GoSub語句一起使用。VB.NET不再支持GoSub語句。流程控制的改變下面是VB.NET對流程控制語句的修改:1. GoSub不再受到支持。2. Call、Function和Sub語句均可用于調(diào)用過程。3. On ... GoSub和On ... GoTo語句不再受支持??梢允褂肧elect Case語句來替代。4. While ... Wend語句現(xiàn)在改為While…End While語句。不再支持Wend關(guān)鍵字。小結(jié) Visual Basic .NET是.NET版本的Visual Basic,已經(jīng)從根本發(fā)生了變化!通過本文你了解到VB6.0和VB.NET的區(qū)別是很大的,可以說根本就是兩種不同的語言,因為它們的內(nèi)核發(fā)生了變化,VB6.0是基于COM而vb點虐 是基于點虐 框架的,因為這個變化,所以在構(gòu)造類時也發(fā)生了根本性的變化。
請參考:
當我把一些舊的VB6項目轉(zhuǎn)變成VS2008時會出現(xiàn), “Declare”語句中不支持“As Any”的錯誤說明, 例如在National Instrument中有一個VBib-32.vb中有大量的這樣一類的語句:
Declare Function ibcmda32 Lib "Gpib-32.dll" Alias "ibcmda" (ByVal ud AsInteger, ByRef sstr As Any, ByVal cnt As Integer) As Integer
如何辦?
有兩種辦法:
一, 使用具體的參數(shù)
例如字符串, 就用string, 那么上面的ByRef as Any, 就寫成ByRef as string, 或者
二, 使用特殊說明MarshalAsAttribute
System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.AsAny)
把這段語句放在相應之處, 然后把Any改成Object, 于是最上面的說明語句寫成
Declare Function ibcmda32 Lib "Gpib-32.dll" Alias "ibcmda" (ByVal ud AsInteger, System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.AsAny) ByRef sstr As Object, ByVal cnt As Integer) As Integer
對于ByVal也是一樣
Public Declare Function GetPrivateProfileString Lib "kernel32" Alias"GetPrivateProfileStringA" (ByVal lpApplicationName As String, System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.AsAny) ByVal lpKeyName As Object, ByVal lpDefault As String,ByVal lpReturnedString As String, ByVal nSize As Integer, ByVal lpFileName AsString) As Integer
MSDN官方說明, 可以簡寫成:
Declare Sub SetData Lib "..\LIB\UnmgdLib.dll" ( ByVal x As Short, MarshalAsAttribute(UnmanagedType.AsAny)ByVal o As Object)
這種方法本人實際使用, 可行.
VB真想不到之六:有用的技術(shù)和沒用的指針
作者: AdamBear 來源:CSDN
關(guān)鍵字:VB、SafeArray、數(shù)值類型指針
難度:中級
參考文章:
1、2000年7月VBPJ Black Belt專欄文章《Modify a Varialbe's Pointer》
作者:Bill McCarthy
引言:
這真的是指針專題的最后一篇了(當然,以后肯定還會提到指針)。主要是來談談Bill McCarthy的文章《Modify a Varialbe's Pointer》的精華。關(guān)于這篇文章的東西,在我的《VB指針葵花寶典之SafeArray》里曾談到過,但那篇文章實際上沒有寫出SafeArray的精華,用SafeArray最妙的地方在于可以將一個變量建在指定的內(nèi)存處,就象上一篇文章給出的那個字串類一樣。
正文:
Bill McCarthy在那篇《Modify a Varialbe's Pointer》里用SafeArray實現(xiàn)多進程的數(shù)組共享內(nèi)存,他考慮了數(shù)組變量的類型,因此可以兼容大部分數(shù)值類型的數(shù)組,是一個非常不錯的東西。我這里不講它實現(xiàn)的具體方法,只是想和大家一起看看SafeArray還能做什么。
修改SafeArray結(jié)構(gòu)的pvData指針卻是一個非常有用的技術(shù),通過修改pvData,就能夠通過數(shù)組直接訪問指定的內(nèi)存。
和上一篇文章包裝字串指針類一樣,通過修改pvData,我們也可以包裝一些普通數(shù)值類型變量的指針類。
我在指針的第一篇文章里說過,要想實現(xiàn)C語言里'*'這個取指針所指變量值功能,必須要用CopyMemory。實際上,我說錯了,我們完全可以實現(xiàn)和C里一樣的指針,如下:
//C語言
Long L;
Long* pL = L;
*pL = 12;
printf("L = %d *pL = %d", l, *pl);
'VB里
Dim pL As New pLong, L As Long
pL.Attach L
'也可以 pL.Ptr = VarPtr(L)
pL = 12
Debug.Print "L ="; L; " *pL ="; pL
結(jié)果都能夠通過修改pL指針,達到修改變量L的目的。
上面VB代碼里的pLong就是一個包裝好的Long型變量的指針類,下面看看如何來實現(xiàn)它:
Option Explicit
'********************************************************
'pLong.cls
'包裝一個Long型指針的類
'作者: 熊超 ID: AdamBear 2002年3月18日
'
' 你可以自由使用本類模塊,不過請保留本聲明
'********************************************************
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private m_Arr(0) As Long
'缺省屬性
Public Property Get Data() As Long
Data = m_Arr(0)
End Property
Public Property Let Data(ByVal Value As Long)
m_Arr(0) = Value
End Property
Public Sub Attach(Target As Long)
Ptr = VarPtr(Target)
End Sub
Public Property Let Ptr(ByVal Target As Long)
Dim pSA As Long
'得到SafeArray結(jié)構(gòu)指針pSA
CopyMemory pSA, ByVal VarPtrArray(m_Arr), 4
'這個指針偏移12個字節(jié)后就是pvData指針
CopyMemory ByVal (pSA + 12), Target, 4
End Property
Public Property Get Ptr() As Long
Ptr = m_SA.pvData
End Property
Private Sub Class_Terminate()
CopyMemory ByVal VarPtrArray(m_Arr), 0, 4
End Sub
要將它改成Byte的指針類,只需要將上面的代碼中m_Arr數(shù)組的類型,Data屬性和Attach方法中的參數(shù)類型改為Byte型即可。
當我們這樣做出pLong、pByte、pInteger后,我們就能夠玩點和C里一樣的花樣了。
Sub Main()
Dim pB As New pByte, B As Byte
Dim pI As New pInteger, I As Integer
Dim pL As New pLong, L As Long
'用Attach方法將經(jīng)過類型檢查,直接用Ptr屬性則可以繞過類型檢查
pB.Attach B
pI.Attach I
pL.Attach L
'試試指針
B = 1
Debug.Print "B ="; B; " *pB ="; pB
pB = 1
Debug.Print "B ="; B; " *pB ="; pB
I = 1000
Debug.Print "I ="; I; " *pI ="; pI
pI = 2000
Debug.Print "I ="; I; " *pI ="; pI
L = 40000
Debug.Print "L ="; L; " *pL ="; pL
pL = 60000
Debug.Print "L ="; L; " *pL ="; pL
'試試C里的類型轉(zhuǎn)換
'用Integer指針訪問Long型變量
pI.Ptr = VarPtr(L)
Debug.Print "*pI ="; pI
End Sub
搞出這幾種普通數(shù)值類型的指針類有什么用?基本上沒有什么大用。不過是證明一種方法的可行性,和演示技術(shù)。這種技術(shù)還有什么用,需要的時候還會再談。
后記:
本文的東西,可見CSDN共享軟件上的《內(nèi)存共享和指針》,
指針的專題就到這兒了,下一篇準備開始著手寫VB和COM的一個系列文章,其間我準備翻譯一下《VB Design Patterns》,這是一本不錯的書。
9:43 添加評論 固定鏈接 引用通告 (0) 記錄它 VisualBASIC
固定鏈接
添加評論VB真想不到系列五
VB真想不到之五:高效字串指針類
作者:AdamBear 來源:CSDN
關(guān)鍵字:VB、HCAK、字串指針、BSTR、效率、內(nèi)存共享
難度:中級或高級
參考文章:
1、2000年7月VBPJ Black Belt專欄文章《Modify a Varialbe's Pointer》
作者:Bill McCarthy
2、1998年4月VBPJ Black Belt專欄文章《Play VB's Strings》
作者:Francesco Balena
引言:
本想以內(nèi)存共享做為VB指針專題的最后一篇,寫著寫著發(fā)現(xiàn)字串的問題應該單獨談談。在內(nèi)存共享的問題上,我尤其關(guān)心的是字串的共享,因為在我一個多月前發(fā)布的源碼里用的是《HardCore VB》里Bruce Mckinney提供的CShareStr類,它實現(xiàn)了字串的內(nèi)存共享。但是Bruce也沒有突破局限,對字串的處理依然是CopyMemory的乾坤大挪移,尤其是還要進行討厭的ANSI/DBCS和Unicode的轉(zhuǎn)換。我在readme里說過它效率極低,應該采用Variant或Byte數(shù)組來實現(xiàn),才能避免轉(zhuǎn)換。后來又想到可以用StrPtr來做,并在VC里用DLL共享節(jié)實現(xiàn)了可以不進行轉(zhuǎn)換的字串內(nèi)存共享。不過在VC里我仍然需要用SysAllocString來建立VB能使用的BSTR。這都不是我想要的,我想要的東西要象VC里的CString的一樣,只要字串夠大,對其賦值就不用重新分配內(nèi)存,還要象VC里CComBSTR類一樣可以Attach到一個特定BSTR。
知道該怎么做,是在看了VBPJ上Bill McCarthy和Francesco Balena的兩篇文章之后。Bill用修改SafeArray描述結(jié)構(gòu)實現(xiàn)了數(shù)組的內(nèi)存共享,而Francesco則對字串指針進行深入的探討。但是Bill和Francesco的東西都沒有實現(xiàn)我想要的字串類。
方法知道了,實現(xiàn)并不難,所以我決定自己來包裝一個這樣的東西。
正文:
使用VB里的字串類型String有兩大不足:第一、它的分配是由VB運行時控制,我們不能將其分配在指定內(nèi)存處;第二,任何一次對字串的賦值操作都要進行內(nèi)存重新分配。要實現(xiàn)高效、靈活的字串處理,我們必須克服這兩大不足。
對于第一個問題,通過修改String變量里放著的BSTR描述符指針可以實現(xiàn);對于第二個問題,可以用Mid語句(注意是語句而不是函數(shù))來賦值。不詳細講了,直接看下面的這個類:
Option Explicit
'********************************************************
'clsBSTR.cls
'作者: 熊超 ID: AdamBear 2002年3月18日
'
' 你可以自由使用本類模塊,不過請保留本聲明
'********************************************************
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'不要直接對sString賦值(可以用MID語句),將其設為公有僅為提高效率。
Public sString As String 'BSTR描述符指針
Private pStr As Long 'BSTR地址
Private nMaxLen As Long 'BSTR最大字節(jié)數(shù)
'讓本字串指向特定地址
Public Sub Attach(Addr As Long, Optional nLen As Long)
pStr = Addr
'修改BSTR描述符指針,使其指向Addr
CopyMemory ByVal VarPtr(sString), Addr, 4
If IsMissing(nLen) Then Exit Sub
'設定最大字串字節(jié)數(shù)
nMaxLen = nLen
End Sub
'還原本字串原BSTR描述符
Public Sub Detach()
CopyMemory ByVal VarPtr(sString), 0, 4
End Sub
'讓本字串指向源字串
Public Sub AttachStr(sStr As String)
Attach StrPtr(sStr), LenB(sStr)
End Sub
'data為缺省屬性
Public Property Let data(sVal As String)
Dim c As Long
c = LenB(sVal)
'超過最大字串數(shù),拋出錯誤。
If c nMaxLen Then Err.Raise vbObjectError + 3000, _
"CString::Let Data", "溢出"
'寫字串長度
CopyMemory ByVal (pStr - 4), c, 4
'寫字串
Mid(sString, 1) = sVal
End Property
'可以通過公有變量sString來讀字串,效率更高
Public Property Get data() As String
data = sString
End Property
Private Sub Class_Terminate()
Call Detach
End Sub
用法如下,假設我們已通過VitualAlloc,HeapAlloc,MapViewOfFile這樣的內(nèi)存管理API得到了一個4k個字節(jié)的可讀寫的內(nèi)存地址baseAddr:
Dim sShare As New clsBSTR
'留下前4個字節(jié)用于BSTR保存字串字節(jié)數(shù)
sShare.Attach(baseAddr+4, 4096-4)
'下面的字串"Test"會直接寫到baseAddr+4字節(jié)處
sShare = "Test"
Dim y As String
'讀字串時可以用sString屬性或缺省屬性
y = sShare.sString
'用AttachStr方法Attach到一個字串。
'必須要先Detach
sShare.Detach
sShare.AttachStr(y)
sShare = "Hahaha"
Debug.Print y
'一旦AttachStr到字串y后,對sShare的修改就相當于對y的修改。
'并且以后對y的修改也只能用Mid語句
Mid(y, 1) = "xxxxx"
'不能直接賦值,這樣VB會將原來y所指(也是sShare所指)內(nèi)存釋放,
' 重新分配y。這樣在訪問sShare時會出錯。
'y = "Test"
我也不在這里講這個類的詳細原理,可以參考我前面說的兩篇文章。
使用這個類有幾個需要注意的地方。
1、讀字串時可以用sString屬性來讀,更快。
讀sShare有兩種方法,一種是用缺省屬性Data來讀,一種是直接用sString屬性來讀。用sString屬性不重新分配內(nèi)存,要快得多。
2、不要直接給sString賦值,應使用缺省的data屬性來賦值。
之所以把sString屬性暴露出來,是為了效率和方便。我們可以用Mid語句對其進行修改,但不要直接用"="來賦值。
3、注意Attach的第二個參數(shù),表示字串的最大字節(jié)數(shù),不要讓它超過已經(jīng)分配的內(nèi)存。
4、用AttachStr將本字串對象Attach到某個字串(比如上面的y)上后,不能再對這個字串y重新賦值,也不能將其傳遞到會對其重新賦值的過程。
哇,這么多需要注意的問題,用起來豈不是更不方便。的確,用它的之前要考慮是不是必須的。因為建立這個類也一樣有開銷。所以還有一個需要注意的問題:
5、它主要的應用還是在于將字串安放在指定內(nèi)存處。雖然它也可以讓同一個進程內(nèi)幾個的字串達到共享的目的,但是如果只是兩三個很小的字串這樣時做反而慢了。
后計:
數(shù)組指針和字串指針我們已經(jīng)談過了,對于普通的數(shù)值類型變量的指針沒有什么Hack的必要,但是它關(guān)系到一個有用的技術(shù),下篇文章再談。
本文和下篇文章的代碼,以及用這個類來實現(xiàn)的共享內(nèi)存的代碼,我會發(fā)布到CSDN共享軟件上,名字是《內(nèi)存共享和指針》。
9:38 添加評論 固定鏈接 引用通告 (0) 記錄它 VisualBASIC
固定鏈接
添加評論VB真想不到系列四
VB真是想不到系列之四:VB指針葵花寶典之SafeArray
作者:AdamBear 來源:CSDN