关于作者

用户名:神月
笔名:神月
地区:
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



私人收藏

奇迹游戏

好文共赏

访问统计:
文章个数:47
评论个数:55
留言条数:0




Powered by BlogDriver 2.1

神月

 

迷茫并活着,做时间的经历者、记录者

文章

女孩<3> 芳
进入初中的我,正可谓“少年不知愁滋味”,已不屑于只是在厕所有人时从外面的掏粪口往里丢石头以激起千层浪,已不屑于从口袋里拿出只死青蛙吓唬班上的女孩,年少的我们已经学会了如何消费,如何骂人,如何抽烟,相互勾肩搭背,边着边挤着眼睛大声吆喝着“风雨中,这点痛算什么,擦干泪,不要问,为什么……”,还要在人多的时候夸张地提一下裤子,以示很“拽”。

进入初中,年龄仍然比同学们小一岁,在变成大家的固定欺侮对象之前,我学会了“结拜”兄弟,开始懂得团体的力量,一下课就和兄弟们冲到对面的土坡上乱搞,又学会了在课堂上传纸条,无非是XXX和XXX有一腿,日复一日,没有一点儿新意。

初一期末考试,不幸得了个全班倒数第二,没办法,奉命留级,重修初一课程。留级的感觉真好,同学终于是同龄人了,再不用担心被人无端地欺侮了。

街面上突然同时出现了好几家大型游戏厅,和现在的网吧一样,当时被视为洪水猛兽的街机厅对我们这些年青人是那样的吸引,从此,放学后的无聊时间再也没觉得够用,周末一大早就和志同道合的兄弟们直奔游戏厅,常常是我们都到了,游戏厅还没有开门。母亲发现我迷上这东西以后,零用钱就再也没有给过,只好天天混着捡别人的便宜,经常是母亲站在我背后拍我的肩膀,我回头来一看,再回头看游戏屏时,自己的角色已经被大恐龙一巴常拍死了。

穷人的日子不好过啊,直到有一天,兄弟江拿着一张似曾见过的纸币在我眼前一晃:国库券!面值500元的国库券被我们以280元的价格卖给了校门外的小卖部,接下来的日子里,我学会了逃课,为玩游戏,把那辆飞鸽自行车丢掉,学会了抽烟,学会了打架……成绩再也没有好过,总在中下游徘徊,化学考过2分,英语考过0分,英语老师是个姓李的女老师,叫我到办公室问:看你还答得满满的,二十五道单选题,你就一道也蒙不上?真是奇才啊!

那时,有很多流行的歌曲在学校传唱,记得有一首李春波的成名作《小芳》这样唱道:“村里有个姑娘叫小芳,长得好看又善良,一双美丽的大眼睛,辫子粗又长……”

在初一下半学期的时候,班里一下来了两个留级的女孩,一个名字就叫芳,长得很秀气的样子,谈不上长得很好看,和歌词里很有些出入:并没有大眼睛,也没有粗又长的辫子,脸上有不少灰灰的雀斑,而且留了整整齐齐的日本头型—也就是前发齐眉,三面齐脖的短发;另一个叫小艳,留着齐脖短发,稍胖了一些,大概是我坐得近得原故,总觉得小艳比芳要可爱一些。

开学时,我会在窗边,因为没有来得及调座位,小艳一个人坐在我的前面,没几天便混熟了,记得经常在放学以后,小艳会从窗户外伸手在我的头上轻轻拍几下,然后淘气地笑着跑掉。

有美女新入,兄弟们当然按捺不住了,没过几天,比我高半头的坤,班上的金噪子,决意展开行动了,他的目标是芳。

每每下课后兄弟们围在一起点上一根烟,坤便开始发酸了:先是深深地吐上一口烟,用刚刚想到的形容词来轻描淡写一下芳的美丽,然后再含情脉脉地往那个方向瞅上两眼,这种眼神,本应是恋人才会有的,但少不更事的我,却在大家都没有经意的时候,学会了——偷偷地从一个不容易被发现的角度看一个女孩,原来是这样的让人心跳不已,我不自觉地爱上了这种感觉。

其实现在想一想,芳并不是让我欣赏的女孩,何况再不懂事,我也是知道朋友妻不可欺这个道理的,但等想要阻止时,却发现自己已经没有气力了。

于是,在大家的起哄声中,我越陷越深,却因为完全不懂得爱,不知道自己该如何表达,如何收场,初中的三年中,便一直这样暗暗地、朦胧地喜欢着这个女孩。这种“名不正,言不顺”的爱恋,让我不能象别人一样正视芳,就象一个吸食海洛因的瘾君子,明知已经滑向边缘,却不能停止,我的学习成绩一天比一天差,只会麻木地盯着黑板脑中反复地映着芳的影子。

象是毫无理由的“单相思”,对方毫无表示,甚至我们之间都没有随意的交谈,浅浅的同学之间的感情,而自己却执着地爱对方,追求对方。初中的日子的确没有什么好回忆的内容,天空是灰色的,整天生活在这种错误主观意识的单恋中,没有开始,没有结束,也有快乐和兴奋,但更多的还是痛苦和压抑,正因为这样,我的单恋才变得如此牵肠挂肚和铭心刻骨。

单恋的人,只尝到爱情的苦汁,却从来未尝到爱情的甜蜜。 单恋与失恋不同,单恋虽有钟情的目标,但双方从未有过感情的融合与交流,只是一厢情愿的苦苦相思。严格地说,它不能叫恋爱,只是恋爱的一种错觉。

我以糟糕的成绩初中毕业以后,个头突然开始长高,踏入高中之后,我失去了芳的消息,最近一次见到她,她好象已经认不出我来。看着她骑自行车经过我面前,我的心里笑了笑:我也曾经年少过!

2004年2月27日,坤和小艳结婚了,那一天,我想了很多事情。

- 作者: 神月 2004年09月28日, 星期二 01:31  回复(2) |  引用(0) 加入博采

VB.NET<10> 深入了解

今天开始,到 http://msdn.microsoft.com/library/chs/ 微软的官方MSDN库去学习。

http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vsintro7/html/vbwlkCreatingDistributedWebApplicationWalkthrough.asp

感觉很爽!在.NET下写程序真的是一种享受。


Modifiers属性
决定控件的继承范围。默认情况下,.NET 中的所有控件都为 Friend。在 Visual Basic 的旧版本中,所有控件都为 Public。现在,您可以选择 Private、Protected、Friend 或 Public。例如,在可视继承应用中,将控件的Modifiers设为Private,继承后的窗体就不能更改控件的形状及属性;设为Protected,就可以对控件的形状及属性进行覆盖性的重新设计。

结构化的异常处理
Private Sub TestFinally()
  Dim lngSize As Long
  Dim s As FileStream

  Try
    '在此处执行某个可能引发错误的操作
    s = File.Open(txtFileName.Text, FileMode.Open)
    lngSize = s.Length
    s.Close()
  Catch e As Exception
    '在此处处理Try 块中发生的异常
    MessageBox.Show(e.Message)
  Finally
    '无论发生什么情况都运行此处的清理代码
    s = Nothing
  End Try
End Sub

轻松获得应用程序的属性
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' 获取记事本的文件版本
Dim FileProperties As FileVersionInfo = FileVersionInfo.GetVersionInfo("C:WINNTtaskman.exe")
' 检索文件说明(名称)
TextBox1.Text = FileProperties.FileDescription
'检索文件版本
TextBox2.Text = FileProperties.FileVersion
'检索文件的内部名称
TextBox3.Text = FileProperties.InternalName
'检索文件的旧名称
TextBox4.Text = FileProperties.OriginalFilename
'检索产品名称
TextBox5.Text = FileProperties.ProductName
'检索产品版本
TextBox6.Text = FileProperties.ProductVersion
'检索语言
TextBox7.Text = FileProperties.Language
End Sub

- 作者: 神月 2004年09月4日, 星期六 03:01  回复(0) |  引用(0) 加入博采

WebBrowser 控件技术

IE浏览器内核都是基于ShDocVw.dll的,而这个dll是一个可编程的ActiveX,可以使用任何支持com的语言去开发自己的浏览器,当然,一个前提是基于IE内核。时下流行的MyIE就是一个例子。


引用:
Microsoft HTML Object Library

部件:
Microsoft Internet Controls

On Error Resume Next
    Dim vdoc As IHTMLDocument2
    Dim vTag

    Dim i As Integer
    If Not WebBrowser1.Busy Then '如果下载完成,就执行下面程序
        Set vdoc = WebBrowser1.Document
        For i = 0 To vdoc.All.length - 1 '检测所有标签
            If UCase(vdoc.All(i).tagName) = "INPUT" Or UCase(vdoc.All(i).tagName) = "TEXTAREA" Then
             '找到input标签
                Set vTag = vdoc.All(i)
                    If vTag.Type = "text" Or vTag.Type = "password" Then '看看是不是我们需要的
                        Select Case vTag.Name
                            Case "UserName"
                                vTag.Value = NameText.Text
                            Case "PassWord"
                                vTag.Value = PWDText.Text
'                            Case "subject" '写标题,不同的网页表单,vTage.name的值不同,要查看网页源码修改
'                                vTag.Value = "Hello,sunHai!"
                        End Select

                    ElseIf vTag.Type = "submit" And vTag.Value = "登录" Then '找到发表按钮。
                         vTag.Click
                    End If
            End If
        Next i

'        vdoc.Forms(0).submit  '也可以用这句来提交表单
    End If

'取得网页的HTML源码
Text1.Text = WebBrowser1.Document.body.outerHTML
Text1.Text = WebBrowser1.Document.documentElement.innerhtml

WebBrowser包含了一个NewWindow2的事件,在下列情况产生的时候触发:
1.用户按shift键点击超链接
2.在超链接出右键菜单选择在新窗口打开
3.在主菜单上选择新建窗口
4.超链接设置了target,但是找不到相对应匹配的时候
5.通过编程window.open打开
所以,可以通过在此事件中将Cancel设为True来阻止弹出窗口

Private Sub WebBrowser1_NewWindow2(ByRef ppDisp As Object, ByRef Cancel As Boolean)
Cancel = True
End Sub

- 作者: 神月 2004年09月4日, 星期六 01:47  回复(1) |  引用(0) 加入博采

新浪短信网页服务

在VS.NET环境中直接添加Web引用http://smsinter.sina.com.cn/ws/smswebservice0101.wsdl

该Web Service就只有一个方法string sendXml(carrier,userid,password,mobilenumber,content,msgtype)。各个参数全部为string类型。

carrier:运营商名称,这里面可以随便输,不过似乎没有任何显示,不知道里面有没有其它奥秘。
userid:您在新浪无线上注册的手机ID,即http://sms.sina.com.cn。
password:您在新浪无线上注册手机时所使用的密码。
mobilenumber:对方的手机号码;
content:发送短消息的内容;
msgtype:发送短消息的类型,我估计支持彩信,不过我目前仅使用文本短信方式,似乎随便输什么都可以,我使用的是“Text”。

示例如下:
Sina.SMSWS ws = new Sina.SMSWS();
string result = ws.sendXml("Sina",textBox1.Text,textBox2.Text,textBox3.Text,textBox4.Text,"new");


http://www.cnblogs.com/zc_net/archive/2004/03/23/3962.aspx

http://blog.joycode.com/joy/

- 作者: 神月 2004年09月4日, 星期六 02:04  回复(0) |  引用(0) 加入博采

VB.NET<9> 简单技巧

最近每天不知道自己在干什么,不行了,得想个办法改变一下。

玩了一整下午的Anchor属性,确实好玩。


'使用OpenFileDialog对话框控件
Dim FileName As String
With OpenFileDialog1
    .Filter = "图像文件|*.bmp;*.gif;*.jpg|所有文件|*.*"
    .Multiselect = False
    '.InitialDirectory = Application.StartupPath
    .RestoreDirectory = True '记录上次打开
    .ShowDialog()
    FileName = .FileName
    TextBox1.Text = FileName
    If FileName <> "" Then
        PictureBox1.Image() = Image.FromFile(FileName)
    End If
End With

'回车符
Label1.Text = "提示:" & ControlChars.CrLf & "内容"

'将窗体以模式显示,并返回原来的窗体
Me.Visible = False
Dim Frm2 As New Form2
Frm2.ShowDialog()
Frm2.Dispose()
Me.Visible = True
Me.Close

- 作者: 神月 2004年09月2日, 星期四 17:55  回复(0) |  引用(0) 加入博采

VB.NET<8> 命名空间

名称空间

VB.NET中的"名称空间"是一种对功能进行组织的很棒方法,其实它们就是建立在整个.NET 框架上的一批类,每种.NET编程语言都要使用这些名称空间。名称空间是一种命名方案,帮助我们组织应用程序可用的各种类。你可以使用一些被默认引入的名称空间的指令,而不需要键入其全部冗长的前缀。

在 Microsoft.VisualBasic 名称空间中,有许多是我们VB开发人员惯于使用的。要想知道我在说些什么,请到代码窗口,键入Microsoft 并跟随一个句号。这时你会面临两个选择:Win32和VisualBasic。如果你键入了VisualBasic并且再一次按下句号,就会看到我们这些编码人员所熟悉的全部函数列表了。

所以,如果你想使用我们在VB6时代就了解的StrReverse函数,就应该执行下列这串代码:

MessageBox.Show(Microsoft.VisualBasic.StrReverse("Karl Moore"))

首先,让我解释一下这种类的"组织"有许多优越性。作为一个开端,它是有组织的。而且,还可以避免命名的冲突,从而在所有的语言之间获得了一个共同的基础。

在默认状态, Microsoft.VisualBasic名称空间中所有的指令都是默认引入的,这就意味着你只需要使用它们的名称,而可以跳过 Microsoft.VisualBasic 这个前缀。

引入一个名称空间时可以在你的表单或组件中指定"Imports 什么.什么",也可以在工程文件属性中指定引入。"Imports"是一种免去你键入全部冗长的前缀的一种方法。事实上,它同你已经了解并喜爱的"With"语句非常相似。

并不只是有 Microsoft.VisualBasic 名称空间,还有System(系统)名称空间... 它们下面有无穷多个指令。

有时候你会想要使用一个不是默认引入的名称空间中的功能,这时候你就需要"引入"它或是用完整的"名称空间路径"来引用它。如果正在进行图形方面的工作,你也许会对 System.Drawing.Graphics 名称空间感兴趣。如果在操作数据库,也许你会想要仔细研读System.Data.ADO。也许想要保存旧的Visual Basic代码,那么就应该查看Microsoft.VisualBasic.Compatibility.VB6 名称空间。


- 作者: 神月 2004年08月27日, 星期五 01:25  回复(1) |  引用(0) 加入博采

VB.NET<7> 多线程应用
开发者一直要求微软为VB加入更多的多线程功能,对于VB.NET也是这样。VB6已经支持建立多线程的EXE、DLL和OCX。不过使用多线程这个词语,可能也不太确切。因此VB6仅支持运行多个单线程的单元。一个单元实际上是代码执行的空间,而单元的边界限制了代码访问任何单元以外的事物。

VB.NET就不同了,它支持建立自由线程(free-threaded)的应用。这意味着多个线程可以访问同样一套的共享数据。本文的以下部分将讨论一下多线程的一些基本点。

问题

虽然VB6支持多个单线程的单元,不过它并不支持一个自由线程的模型,即不允许多个线程使用同一套数据。在许多的情况下,你需要建立一个新的线程来进行后台的处理,这样可提高应用的可用性,否则,一个长的处理就可以令程序的响应变得很慢,例如你按下表格上的一个取消按钮,却很久都没有响应。

解决办法

由于VB.NET使用了CLR(Common Language Runtime),从而拥有了许多的新特性,其中的一个是可以创建自由线程的应用。

使用线程

在VB.NET中,运用线程是很简单的。我们将在后面涉及其中的细节,现在我们首先来创建一个简单的表格,它使用一个新的线程来运行一个后台处理。第一件要做的事情是创建运行在新线程上的后台任务。以下的代码执行一个相当长的运行处理--一个无限的循环:

Private Sub BackgroundProcess()
Dim i As Integer = 1

Do While True
ListBox1.Items.Add("Iterations: " + i)
i += 1
Loop
End Sub

这段代码无限地循环,并且在每次执行时为表格上的一个列表框加入一个项目。如果你对VB.NET不熟悉的话,你将会发现这段代码和VB6的有一些区别:

. 在声明变量Dim i As Integer = 1时赋值
. 使用+=操作符i += 1代替i = i + 1
. 没有使用Call关键字

一旦我们拥有了一个工作的处理,我们就需要将这段代码分配给一个线程处理,并且启动它。为此我们要使用线程对象(Thread object),它是.NET架构类中System.Threading命名空间的一部分。在实例化一个新的线程类时,我们将要在线程类构造器执行的代码块的一个引用传送给它。以下的代码创建一个新的线程对象,并且将BackgroundProcess的一个引用传送给它:

Dim t As Thread
t = New Thread(AddressOf Me.BackgroundProcess)
t.Start()

AddressOf操作符创建了一个到BackgroundProcess方法的委派对象。在VB.NET中,一个委派是一个类型安全、面向对象的函数指针。在实例化该线程后,你可以通过调用线程的Start()方法来开始执行代码。

控制线程

在线程启动后,你可以通过线程对象的一个方法来控制它的状态。你可以通过调用Thread.Sleep方法来暂停一个线程的执行,这个方法可以接收一个整型值,用来决定线程休眠的时间。拿前面的例子来说,如果你想让列表项目增加的速度变慢,可以在其中放入一个sleep方法的调用:

Private Sub BackgroundProcess()
Dim i As Integer = 1

Do While True
ListBox1.Items.Add("Iterations: " + i)
i += 1
Thread.CurrentThread.Sleep(2000)
Loop
End Sub

CurrentThread是一个public static的属性值,可让你得到当前运行线程的一个引用。

你还可以通过调用Thread.Sleep (System.Threading.Timeout.Infinite)来让线程进入休眠状态,有点特别的是,这个调用的休眠时间是不确定的。要中断这个休眠,你可以调用Thread.Interrupt方法。

与休眠和中断类似的是挂起和恢复。挂起可让你暂停一个线程,直到另一个线程调用Thread.Resume为止。休眠和挂起的区别是,后者并不立刻让线程进入一个等待的状态,线程并不会挂起,直到.NET runtime认为现在已经是一个安全的地方来挂起它了,而休眠则会立刻让线程进入一个等待的状态。

最后要介绍的是Thread.Abort,它会停止一个线程的执行。在我们的那个简单例子中,如果要加入一个按钮来停止处理,很简单,我们只要调用Thread.Abort方法就行了,如下所示:

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
t.Abort()
End Sub

这就是多线程的强大之处。用户界面的响应很好,因为它运行在一个单独的线程中,而后台的处理运行在另外一个线程中。在用户按下取消按钮时,便会马上得到响应,并且停止处理。

通过多线程程序传送数据

上面的例子只是一个相当简单的应用。在编程时,你还需要使用到多线程的许多复杂特性。其中的一个问题是如何将程序的数据由线程类的构造器传入或者传出,也就是说,对于放到另外一个线程中的过程,你既不能传参数给它,也不能由它返回值。这是由于你传入到线程构造器的过程是不能拥有任何的参数或者返回值的。为了解决这个问题,可以将你的过程封装到一个类中,这样方法的参数就可使用类中的字段。

这里我们举一个简单的例子,如果我们要计算一个数的平方,即:

Function Square(ByVal Value As Double) As Double
Return Value * Value
End Function

为了在一个新的线程中使用这个过程,我们将它封装到一个类中:

Public Class SquareClass
Public Value As Double
Public Square As Double

Public Sub CalcSquare()
Square = Value * Value
End Sub
End Class

使用这些代码来在一个新的线程上启动CalcSquare过程,如下所示:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim oSquare As New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30

t.Start()
End Sub

要注意到,在线程启动后,我们并没有检查类中的square值,因为即使你调用了线程的start方法,也不能确保其中的方法马上执行完。要从另一个线程中得到值,有几个方法,这里使用的方法是最简单的,即是在线程完成的时候触发一个事件。我们将在后面的线程同步中讨论另一个方法。以下的代码为SquareClass加入了事件声明。

Public Class SquareClass
Public Value As Double
Public Square As Double

Public Event ThreadComplete(ByVal Square As Double)

Public Sub CalcSquare()
Square = Value * Value
RaiseEvent ThreadComplete(Square)
End Sub
End Class

在调用代码中捕捉事件的方法和VB6差不多,你仍然要声明WithEvents变量,并且在一个过程中处理事件。有些不同的是,你声明处理事件的过程使用的是Handles关键字,而不是通过VB6中通常使用的Object_Event。

Dim WithEvents oSquare As SquareClass

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

oSquare = New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30
t.Start()
End Sub

Sub SquareEventHandler(ByVal Square As Double) _
Handles oSquare.ThreadComplete

MsgBox("The square is " & Square)

End Sub

对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。

同步线程

在线程的同步方面,VB.NET提供了几个方法。在上面的平方例子中,你要与执行计算的线程同步,以便等待它执行完并且得到结果。另一个例子是,如果你在其它线程中排序一个数组,那么在使用该数组前,你必须等待该处理完成。为了进行这些同步,VB.NET提供了SyncLock声明和Thread.Join方法。

SyncLock可得到一个对象引用的唯一锁,只要将该对象传送给SyncLock就行了。通过得到这个唯一锁,你可以确保多个线程不会访问共享的数据或者在多个线程上执行的代码。要得到一个锁,可使用一个较为便利的对象--与每个类关联的System.Type对象。System.Type对象可通过使用GetType方法得到:

Public Sub CalcSquare()
SyncLock GetType(SquareClass)
Square = Value * Value
End SyncLock
End Sub

另一个是Thread.Join方法,它可让你等待一个特定的时间,直到一个线程完成。如果该线程在你指定的时间前完成了,Thread.Join将返回True,否则它返回False。在平方的例子中,如果你不想使用触发事件的方法,你可以调用Thread.Join的方法来决定计算是否完成了。代码如下所示:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim oSquare As New SquareClass()

t = New Thread(AddressOf oSquare.CalcSquare)

oSquare.Value = 30
t.Start()

If t.Join(500) Then
MsgBox(oSquare.Square)
End If
End Sub

对于这种方法,要注意的是处理事件的过程,在这个例子中的是SquareEventHandler,将运行在产生该事件的线程中。它并不是运行在表格执行的线程中。

- 作者: 神月 2004年08月27日, 星期五 00:48  回复(0) |  引用(0) 加入博采

VB.NET<6> 部署和分发.NET应用程序

微软的.NET计划是一项激动人心的浩大工程,随着VS.NET Beta2版本的发布,.NET技术也逐渐趋于稳定和成型,越来越多的公司和技术爱好者投入到.NET的开发中来,而现在及早开始.NET的学习和相关开发正是好时机。但是,目前存在着的一个明显事实是,所有的基于.NET技术的应用程序或者产品都需要.NET的运行库支持,因为.NET在程序部署和分发方面有些类似,它需要.NET Framework SDK的支持(JAVA应用程序需要JDK的支持才可以运行),不幸的是,目前的Win9x系列以及WinNT/2000系列均没有内置.NET SDK(不难理解,因为.NET技术的推出的时间晚于上面提到的各种操作系统的发布时间),甚至连即将发布的WindowsXP都不会内置.NET SDK。

虽然,没有了.NET SDK的支持,就连一个简单的在屏幕上面打印“Hello,World!”的应用程序都无法运行,那我们也不可能要求用户必须手工安装将近120M的.NET SDK后才能运行我们自己开发的应用程序!有没有更为简便的发布.NET应用程序的方法呢?答案是肯定的,下面我们就提供两种可以正确部署和发布.NET应用程序的方法。


 一、用VS.NET来部署和分发.NET应用程序

无庸置疑的是,VS.NET是开发.NET应用程序的一个非常强大和快捷的集成开发环境(IDE),微软历来在配合自己的应用技术方面都能做到尽善尽美,当然,我想也只有微软才能真正做到和.NET技术的无缝衔接。

下面我们就详细看看如何利用VS.NET来部署和分发.NET应用程序。为了讲解的方便,我们例举一个非常简单的Windows应用程序:简单的在屏幕上面放置一个按钮Button。

我们开发.NET应用程序的测试环境是:Windows2000 Server中文版(SP2)+VS.NET Beta2中文版。

第一步:在原有的项目基础上,再新建立一个项目,并且选择其中的“安装和部署项目”

注意上图中红色标记的地方,尤其需要注意选择“添入解决方案”这个选项,因为只有这样才会将部署项目和我们自己的应用程序放置到同一个“解决方案”当中,这一点千万要注意了!

第二步:点击“确定”按钮之后,会出现安装向导

因为我们的.NET测试程序是一个Windows应用程序,所以我们在上图中选择“创建用于Windows应用程序的安装程序(S)”。点击“下一步(N)”,我们将会看到需要选择的画面

上图中的各个选择项目的含义相信大家可以从中文名称中直观的理解到,我们就不再多费口舌了。一路点击“下一步”直到最终安装向导的完成会需要5步,最终会在当前的解决方案中添加一个名称为“Setup1”的安装项目。

在这里我们稍微提一下在VS.NET中的“解决方案”这个概念,其实在VS.NET中的所谓“解决方案”就类似于以前VB中的“项目组”概念,也就是将多个项目集成到一起而已,只不过VS.NET中的“解决方案”这个概念的覆盖范围更广泛而已罢了,这个我们知道一下就可以了。

第三步:在完成上面的两个步骤之后,我们就会发现,VS.NET的安装向导已经将我们的应用程序中所用到的各种程序集、系统DLL文件、资源文件等等依赖文件找到了,并且我们还可以方便的继续添加额外的我们需要的其他相关文件,在这方面做的有些类似于InstallShield了,不过不需要编写安装Script脚本。

这样,我们选择VS.NET的菜单“生成(B)”—〉“生成解决方案”,即可立即生成我们的安装文件Setup1.msi,这个安装文件你可以在你的应用程序解决方案所在的目录中找到。

找到了这个安装文件你就会大吃一惊了,即使我们的应用程序只有简单的一句话,打包之后就会有17M之大!不过没有办法,VS.NET会生成一个简洁的.NET SDK放在我们刚才生成的那个安装文件当中。

剩下来的事情,就是直接在没有安装.NET环境的Windows9x/NT/2000/XP中运行我们的这个Setup1.msi文件就可以了!


二、手工部署和分发.NET应用程序

在上面的第一种方法中,我们可以感受到VS.NET来做.NET应用程序的方便和快捷,但是并不是所有的人都是使用VS.NET集成开发环境来开发.NET应用程序的,对于一些小的应用程序,根本不需要安装庞大的VS.NET开发环境也可以方便的开发,比如使用UtraEdit软件来编写小巧玲珑的.NET应用程序也是一个不错的选择。

在这里我们就说说如何不使用VS.NET来自己手工的部署和分发我们的.NET应用程序。首先分两类:

第一类:基于Web的.NET应用程序

对于这一类应用程序,可以说在部署和分发方面是最为简单的了,我们只需要将.NET运行环境安装到我们自己的服务器上面就可以了,用户端需要的仅仅是兼容IE4.0以上的任何浏览器就可以了。

第二类:基于Windows的.NET应用程序

对于这一类,应用程序,我们可以使用InstallShield安装软件来手工打包。首先,先在我们的.NET Frameword SDK光盘中找到目录dotNet,在这个目录里面我们可以发现一个大小大约15M的一个安装文件,这个就是我们的.Net 的运行时刻文件,类似于JAVA的JRE(JAVA运行时环境)。这个文件的体积也是比较大的,但是相对于.NET SDK文件的庞大的120M可以算是要好许多了。

至于InstallShield的详细使用方法我在这里也无法透彻讲解,不过使用起来是非常方便的,我只提出需要注意的地方:

1、在使用InstallShield中,可以稍微编写一段脚本来监测目标机器时候已经存在了.NET的运行环境,如果有了,就不必安装.NET运行时文件了。

2、所有我们自己的DLL文件不在需要注册,只需要简单的将他们拷贝到我们应用程序所在的目录即可!

我们在这里例举的是使用InstallShield来制作安装程序,当然还可以使用其它的任何第三方安装制作软件来部署和分发我们的.NET应用程序,比如Windows Installer等等。

好了,最终我们比较这两种部署和分发.NET应用程序的方法,我们可以看到,使用第二种方法能够带来的一个潜在好处是,我们可以将.NET运行时环境文件和自己的应用程序分离开来,从而在某些情况下可以大大减少部署安装应用程序的文件大小;而第一种方法就不可以了,他将始终将.NET运行时环境文件打包进入安装文件。但是第一种方法的优点也是显而易见的,就是比较智能化,需要人干预的地方很少,并且如果需要部署和分发的.NET应用程序是比较大型的软件的话,我们推荐使用第一种方法!

相信在微软正式发布.NET以及VS.NET之后,部署和分发.NET应用程序将会变得更加简单和快捷,但是最好的方式是希望微软在下一版本的操作系统中能够内置.NET运行时环境就好了,那样的话,我们就不必时刻“随身携带”体积不算小的.NET运行时环境文件了,让我们拭目以待吧。

- 作者: 神月 2004年08月27日, 星期五 00:43  回复(6) |  引用(0) 加入博采

XML - 网络世界的国际语言

网络正影响着世界的每一个角落,改变着人们的生活。正如人们交流需要共同的语言一样,在网络世界里,系统之间、机器之间、程序之间的交流也同样需要共同语言。如果有一种通用的语言,那么这种交流的将方便而高效,否则就要通过翻译了。在W3C的推动下,XML正以其自身的优势,逐渐成为网络世界的“国际语言”。

XML标准简介

XML的英文全名是:eXtensible Markup Language,翻译成中文是:可扩展置标语言。它是国际组织W3C为适应WWW的应用,将SGML标准进行简化形成的置标语言。它作为一种可用来制定具体应用语言的元语言,既具有强大的描述能力,又具有适合网络应用的简洁性。

XML作为一种置标语言是运用“置标法”描述结构化数据的形式语言。所谓“置标法”就是为了处理的目的,在数据中加入附加信息的方法,而这些附加的信息称为置标。

XML标准体系

XML作为一种元语言,提供的是描述具体应用语言的基本方法。针对具体的应用领域需要制定相应的应用标准。例如,具体的置标表示的语义,附加的语法约束等。另外,针对XML应用中的公用特征、方法或规则,W3C制定了一些XML的基础标准。

如图所示,是XML标准体系的框架。XML作为整个体系的核心,其他XML相关标准都是用它制定的或为其服务的。在图中,中间一层是XML基础标准,最下层是XML的应用标准。

XML基础标准

XML基础标准是为XML的进一步实用化制定的标准,规定了采用XML制定标准时的一些公用特征、方法或规则。XML Schema描述了更加严格地定义XML文档的方法,以便可以更自动化的处理XML文档。XML Namespace用于保证XML DTD中名字的一致性,以便不同的DTD中的名字在需要时可以合并到一个文档中。DOM定义了一组与平台和语言无关的接口,以便程序和脚本能够动态访问和修改XML文档内容、结构及样式。XQuery的目的是为从WEB文档中提取数据,提供一种灵活的查询机制。XPath描述如何识别、选择、匹配XML文件中的各个构成元件,包括元素、属性、文字内容等。XPointer和XLink标准,规定了有关定位、链接方面的内容。CSS被用来作为XML文档显示的样式标准。等等。

XML应用标准

XML已开始被广泛接受,大量的应用标准,特别是针对Internet的应用标准,纷纷采用XML进行制定。在这Internet时代,几乎所有的行业领域都与Internet有关。而这些行业一旦与Internet发生关系,都必然要有其行业标准。这些应用标准往往采用XML来制定。当前较为重要的应用标准主要包括:用于XML显示的标准:XHTML(采用XML对HTML的重新定义)、SVG(有关矢量图形的)、SMIL(有关多媒体同步显示的)、MathML(有关数学公式符号的);用于电子商务领域的标准:Micropayments(W3C制定的)、BizTalk(Microsoft发起的电子商务的schema库)、ebXML(联合国UN/CEFACT小组和OASIS共同发起的)、PIP(由诸多IT业的巨子组成的一个标准化组织RosettaNet的应用网络标准。),cXML、xCBL、tpaML等等;以及其他领域的。

XML标准已成为网络世界的ASCII标准。


XML规范

第一行<?xml version="1.0"?>是一个XML声明,表示文档遵循的是XML的1.0 版的规范。
第二行定义了文档里面的第一个元素(element),也称为根元素: <文章>。这个就类似HTML里的<HTML>开头标记。注意,这个名称是自己随便定义的。
再下面定义了四个子元素分别说明文章的标题,作者,邮箱和日期:

<?xml version="1.0" encoding="GB2312"?>
<文章>
<标题>XML轻松学习手册</标题>
<作者>ajie</作者>
<信箱>ajie@aolhoo.com</信箱>
<日期>20010115</日期>
</文章>

这就是XML的文档,任何掌握HTML的网友都可以直接写出这样简单的XML文档。
另外,学习XML还必须掌握一种页面脚本语言,常见的就是javascript和VB script。因为XML数据是使用script实现HTML中调用和交互的。我们看一个最简单的例子(例2):
1.将下面代码存为myfile.htm

<html>
<head>
<script language="JavaScript" for="window" event="onload">
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.load("myfile.xml");
nodes = xmlDoc.documentElement.childNodes;
title.innerText = nodesitem(0).text;
author.innerText = nodes.item(1).text;
email.innerText = nodes.item(2).text;
date.innerText = nodes.item(3).text;
</script>
<title>在HTML中调用XML数据</title>
</head>
<body bgcolor="#FFFFFF">
<b>标题: </b>
<span id="title"> </span><br>
<b>作者: </b>
<span id="author"></span><br>
<b>信箱: </b>
<span id="email"></span><br>
<b>日期:</b>
<span id="date"></span><br>
</body>
</html>

2.将下面代码存为myfile.xml

<?xml version="1.0" encoding="GB2312"?>
<myfile>
<title>XML轻松学习手册</title>
<author>ajie</author>
<email>ajie@aolhoo.com</email>
<date>20010115</date>
</myfile>

3.将它们放在同一个目录下,用IE5以上版本浏览器打开,可以看到效果。

XML的严格格式

吸取HTML松散格式带来的经验教训,XML一开始就坚持实行"良好的格式"。
我们先看HTML的一些语句,这些语句在HTML中随处可见:
1.<p>sample
2.<b><i>sample</b></i>
3.<td>sample</TD>
4.<font color=red>samplar</font>
在XML文档中,上述几种语句的语法都是错误的。因为:
1.所有的标记都必须要有一个相应的结束标记;
2.所有的XML标记都必须合理嵌套;
3.所有XML标记都区分大小写;
4.所有标记的属性必须用""括起来;
所以上列语句在XML中正确的写法是
1.<p>sample</p>
2.<b><i>sample</i></b>
3.<td>sample</td>
4.<font color="red">samplar</font>
  另外,XML标记必须遵循下面的命名规则:
1.名字中可以包含字母、数字以及其它字母;
2.名字不能以数字或"_" (下划线) 开头;
3.名字不能以字母 xml (或 XML 或 Xml ..) 开头;
4.名字中不能包含空格。

- 作者: 神月 2004年08月26日, 星期四 05:36  回复(2) |  引用(0) 加入博采

VB.NET<5> 访问数据方法
  VB.NET作为VB的升级语言,提供了比VB更加强大的功能。它是一种完全面向对象的编程语言。微软对其进行了很大的改进。ADO在Visual Basic.NET中不再直接支持。访问数据有了新的变化,比以前复杂多了。签于大家比较熟悉ADO,且ADO的确简单、方便、适用。固本人利用ADO编写的访问目前市面上最广泛使用的数据库。现在接合Visual Basic.NET强大的类开发功能,本人把ADO访问数据的方法编成组件,完全封装起来,以方便大家的使用。
  启动Visual Studio.NET。在新建项目中选择Visual Basic项目,在模板中选择类库,在名称中输入类库名称如DataAccess.确定后,则进入类库开发环境中,把Class1换名为ADOAccess。

  在项目菜单中加入引用,选择COM页,找到 Microsoft ActionX Data Object 20 Library 或更高版本确定。COM是Microsoft为了区分现在的.net,兼容以前的开发方式而设置的,凡是.net之前的组成件都可在COM页中可找到。(Microsoft ActionX Data Object 20 Library是Microsoft提供的ADO组件。它极大地方便了数据库的访问,是开发数据库有关软件的最实用的工具之一)

  在类名上面写上Imports ADODB.Connection Imports ADODB.Recordset ,Imports ADODB.CursorLocationEnum, Imports System.DBNull 4条引用语句,这里分别是引用ADO,ADO的宏定义,空值函数的来源。

  在类中定义一局部连接对象变量。 Private mCnnDB As New ADODB.Connection()
然后定义连接Access数据库的过程. Access 数据库是Microsoft开发的本地数据库,用adUseClient指定。它通过Microsoft.Jet.OLEDB数据访问方式访问数据库,Microsoft.Jet.OLEDB又有多种版本,其中4.0是最高版本,它能访问ACCESS 2000,所以这里的数据提供者指定为Microsoft.Jet.OLEDB.4.0。指定了本地数据库和提供者后,就可打开一个数据库了,用open方法实现。完整的代码如下:

'作用: 连接Access数据库
'参数: DBName 数据库名
Public Sub ConnAccess(ByVal DBName As String)
Dim strDB As String
mCnnDB.CursorLocation = adUseClient
mCnnDB.Provider = "Microsoft.Jet.OLEDB.4.0"
mCnnDB.Open(DBName, "Admin")
End Sub

  ODBC是一种广泛使用的连接多种数据库的方法,有万能钥匙之功效,但它需要通过ODBC先建立一个DNS,这里不作详细说明.有了DNS就可访问所连接的数据库。访问ODBC时先指明提供者,提供者只能为Microsoft 命名的MSDASQL,然后通过连接字符串指定数据源,用户名和密码,在下面的ConnectionString中指定,最后用open打开。由于ODBC分有用户名和无用户名两者,我们必须分别实现,借助类的函数名重载功能,我们编写两个同名的过程,完整的代码如下:

'作用: 连接ODBC数据库(不需指定用户和密码 )
'参数:dsnName为ODBC名
Public Sub ConnODBC(ByVal dsnName As String)
mCnnDB.Provider = "MSDASQL"
mCnnDB.ConnectionString = "Data Source='" & dsnName & "'"
mCnnDB.Open()
End Sub

'作用: 连接ODBC数据库(需指定用户和密码 )
'参数:dsnName ODBC名,UserID 用户名,UserPwd 用户密码
Public Sub ConnODBC(ByVal dsnName As String, ByVal UserID As String, ByVal UserPwd As String)
mCnnDB.Provider = "MSDASQL"
mCnnDB.ConnectionString = "Data Source='" & dsnName & "'User ID='" & UserID & "';" & "Password='" & UserPwd & "
mCnnDB.Open()
End Sub
  SQL Server数据库是Microsoft开发的一种广泛使用的后台数据库。访问SQL Server可以通过指明ODBC驱动程序为SQL Server来实现,即在连接字符串中要有driver={SQL Server},由于它是后台数据库,所以必须指明SQL Server所在的计算机名,通常把它称为服务器,下面的ServerName就说明这点,然后指明是连接哪个数据库。其它的类似上面的ODBC。SQL Server的用户分为WIN NT 和授权用户,WIN NT用户是不需要指定用户名和密码的超级用户,否则要指明用户名和密码,这责定于SQL Server数据库管理员,在此不作详细说明,完整的代码如下:

'作用: 连接SQL Server数据库
'参数:ServerName 服务器名,DBName 数据库名
Public Sub ConnSQLServer(ByVal ServerName As String, ByVal DBName As String)
With mCnnDB
.ConnectionString = "uid=;pwd= ;driver={SQL Server};" & "server=" & ServerName & ";database=" & DBName
.Open()
End With
End Sub
'作用: 连接SQL Server数据库
'参数:ServerName 服务器名,DBName 数据库名,UserID 用户名,UserPwd 用户密码
Public Sub ConnSQLServer(ByVal ServerName As String, ByVal DBName As String,ByVal UserID As String, ByVal UserPwd As String)
With mCnnDB
.ConnectionString = "uid=’” & UserID & “’;pwd=’” & UserPwd & ”’;driver={SQL Server};" & "server=" & ServerName & ";database=" & DBName
.Open()
End With
End Sub

  Oracle数据库是目前最有影响的一种广泛使用的后台数据库。访问Oracle先指明其提供者MSDAORA。Oracle与Sql Server不同的是它不是通过数据库来管理的,所以它不需指明数据库,但它连接时必须指明用户,即使是超级用户也如此,这是它的安全性能高于Sql Server的理现之一,所以我们只须编写一个过程。其它类似。完整的代码如下:

'作用: 连接Oracle数据库
'参数:ServerName 服务器名,DBName 数据库名,UserID 用户名,UserPwd 用户密码
Public Sub ConnOracle(ByVal ServerName As String, ByVal UserID As String, ByVal UserPwd As String)
With mCnnDB
.Provider = "MSDAORA"
.ConnectionString = "User ID='" & UserID & "';" & "Password='" & UserPwd & "';" & "Data Source='" & ServerName & "'"
.Open()
End With
End Sub

  有了上面的连接数据库的方法,我们就直接可读写数据了。下面利用ADO扩充读写数据的函数。

  ADO在访问表时要指明其光标类型和锁类型,且指定不同其权限就不同,权限分为读写二种,这里我们编写的是有读写权限的通用的函数,所以我们指定光标CursorType为adOpenKeyset,锁为开锁adLockOptimistic,.net需指明其来源,这是为什么开始要有 “Imports ADODB.CursorLocationEnum”语句的原因。有了这些,就可通过执行查询语句来打开一个表。打开表后,我们判断表是否为空表,不是则移动记录至尾后再现移至记录头(这是为了可以访问其中每条记录,特别是用RecordCount求记录数时不至有时返回-1的关键),最后返回一个记录集,完整的代码如下:

'作用:连接表
'参数:TableName表名
'返回:记录集
Public Function OpenTable(ByVal TableName) As ADODB.Recordset
Dim strSql As String
Dim rec As ADODB.Recordset
rec = New ADODB.Recordset()
rec.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
rec.LockType = ADODB.LockTypeEnum.adLockOptimistic
strSql = "SELECT * FROM " & TableName
rec.Open(strSql, mCnnDB) '打开记录集
If Not rec.EOF Then
rec.MoveLast()
rec.MoveFirst()
End If
OpenTable = rec
End Function

  下面是扩充上面函数的功能,可以跟据条件访问单个表。

Public Overloads Function OpenTable(ByVal TableName As String, ByVal strWhere As String) As ADODB.Recordset
Dim strSql As String
Dim rec As ADODB.Recordset
rec = New ADODB.Recordset()
rec.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
rec.LockType = ADODB.LockTypeEnum.adLockOptimistic
strSql = "SELECT * FROM " & TableName & " where " & strWhere
rec.Open(strSql, mCnnDB) '打开记录集
If Not rec.EOF Then
rec.MoveLast()
rec.MoveFirst()
End If
Return rec
End Function

  我们继续扩充访问表的功能。有时要打开多个表,读写其中的数据,我们可以通过建立查询视图实现,其它类似上面的OpenTable,完整的代码如下:

'作用:连接多表
'参数:strSQL
'返回:记录集
Public Function ExecuteSQL(ByVal strSql As String) As ADODB.Recordset
Dim rec As New ADODB.Recordset()
rec.CursorType = ADODB.CursorTypeEnum.adOpenKeyset
rec.LockType = ADODB.LockTypeEnum.adLockOptimistic
rec.Open(strSql, mCnnDB) '打开记录集
ExecuteSQL = rec
End Function
  下面编写了一个用记录集填充AxMSFlexGrid网格的过程。其中函数RecordCount是我自己编写的求记录集中记录数据的函数。这里不能直接用ADO的RecordCount求得。如果记录集是空,则退出过程。否则求出记录集的记录数和字段数据用来确定AxMSFlexGrid网格的行列数据,然后读出记录集的数据直接填充到AxMSFlexGrid网格。要说明的是读出记录集的数据时要先判断是否为空值,由函数IsDBNull实现(函数IsDBNull来源于System.DBNull).最后记录集应该返回到记录首位,否则影响了原有的记录集,完整的代码如下:

'作用:用记录集的数据填充网格
'参数:MSGrid 网格对象,rec 记录集对象
Public Sub FillMsGrid(ByVal MSGrid As AxMSFlexGridLib.AxMSFlexGrid, ByVal rec As ADODB.Recordset)
Dim i, j, RecordNum As Integer
If rec.EOF Then Exit Sub
RecordNum = RecordCount(rec)
MSGrid.Rows = RecordNum + 1
MSGrid.Cols = rec.Fields.Count + 1
For i = 0 To RecordNum - 1
For j = 0 To rec.Fields.Count - 1
If IsDBNull(rec(j).value) Then
MSGrid.set_TextMatrix(i + 1, j + 1, "")
Else
MSGrid.set_TextMatrix(i + 1, j + 1, rec(j).value)
End If
Next
MSGrid.set_TextMatrix(i + 1, 0, i)
rec.MoveNext()
Next
rec.MoveFrist()
End Sub
'作用:取记录集的记录数
'参数:rec 记录集对象
'返回:记录集的记录数

Public Function RecordCount(ByVal rec As ADODB.Recordset) As Integer
Dim i As Integer
If rec.EOF Then
RecordCount = 0
Exit Function
End If
With rec
.MoveFirst()
Do While Not .EOF
i += 1
.MoveNext()
Loop
.MoveFirst()
End With
RecordCount = i
End Function

  以上代码编好后放在所定义的类中.下面的省略号代表上面的函数和过程。可直接生成为DLL组件。方法是在.net编辑环境下选择生成菜单中按生成就生成了DLL文件。然后,你可以直接调用该组件了。

Imports ADODB.Connection
Imports ADODB.Recordset
Imports ADODB.CursorLocationEnum
Imports System.DBNull ‘函数IsDBNull的来源
Class ADOAccess
Private mCnnDB As New ADODB.Connection()

End Class

  调用上面生成的组件方法如下:在Visual Basic.NET中建立一项目,在窗口Form1中加入一AxMSFlexGrid网格命名为MsGrid1,然后引用刚建立的Dll。方法是选择项目菜单的添加引用,选择项目页,按浏览找到其DLL文件确定后引用完成。在Form1中定义一ADOAccess对象,在Load事件中编写调用代码,分别测试其功能,代码如下:

Public Class Form1
Inherits System.Windows.Forms.Form
Dim DB As New ADOAccess()
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim rec As New ADODB.Recordset()
'DB.ConnAccess("e: est.mdb")
'DB.ConnSQLServer("wj-1058", "test")
'DB.ConnODBC("testODBC")
'DB.ConnOracle("wj-1059", "system", "manager")
'rec = DB.OpenTable("DEMO.customer")
rec = DB.OpenTable("doc_file")
DB.FillMsGrid(MSGrid1, rec)
End Sub

  说明:

  1.你的机上要有Access数据库文件(e: est.mdb),MS Server数据库中有数据库test,doc_file 为其test中的表,Oracle数据库中有表DEMO.customer。
 
  2. wj-1058为MS Server服务器名,wj-1059为Oracle服务器名,"system", "manager"分别为用户名及口令。

  3. 一次仅连接一种数据库。以上程序在Visual Studio.NET中调试通过。

  总结:

  上面方法介绍了刚面世不久的Visual Basic.NET中有关数据库的开发,ADO在Visual Basic.NET中的应用,连接几种最实用的数据库,且介绍了编写组件的方法。利用该知识极大地方便了软件开发者访问数据的能力,提高了开发效率。

- 作者: 神月 2004年08月26日, 星期四 05:26  回复(1) |  引用(0) 加入博采