分享
 
 
 

编程爱好者电子杂志2001年第一期

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

编程爱好者电子杂志 2001年第一期

出版日期: 2001年5月27日

编程爱好者网站: http://www.pfan.net

杂志网站】【编辑信箱】【提问信箱】 【过刊查询】【杂志订退

本 期 内 容

1.VFP中焦点行的动态显示

2.Java 应用程序中的按值传递语义

3.用VB实现屏幕阴暗操作

4.用Delphi 控制窗体的大小

5.VB与VC混合编程中处理消息的方法

6.用VB设计VCD播放器

7.用VB为软件增加注册功能

VFP中焦点行的动态显示

李明亮

在用VFP设计一个应用系统时,信息的浏览是其中一个相当重要的功能。人们一般用Grid对象来显示数据信息,但该对象在使用功能上却存在一些不足。

提出问题

当使用者在记录之间移动焦点时,只有获得焦点的记录的某一个字段以不同于Grid背景的颜色显示。为使整条记录均用同一种颜色突出显示(本文示例为蓝色背景),即当数据记录移动时,用颜色动态变化显示相对光标所在记录的位置,可以在Grid对象的afterRowColChange事件过程中加入如下内容:

this.setall(“dynamicbackcolor”,“iif(this.activerow=recno(),rgb(0,0,255),rgb(255,255,255))”,“column”)。

笔者在使用中发现:如果设置了Set delete on环境参数,则当逻辑删除记录后,动态背景的颜色显示就会出现混乱。

分析问题

这种情况一般有两种解决方法:

●执行pack命令,再重新创建和设置Grid的各项属性;

●先将没有删除标志的记录复制到一个临时表中,用zap命令删除源表中所有记录,再将没有删除标志的记录从临时表追加到源表中。

这两种方法实质上都是把已逻辑删除的记录从数据表中真正删除,缺点是两种方式都要求该表必须以独占方式打开。

如果表是以共享方式使用,那么又该如何处理呢?其实,动态背景颜色不能正确显示的原因是由于逻辑删除记录,该操作造成光标所在的行activerow()不等于数据的记录号recno(),从而导致了动态背景颜色的显示出现混乱。笔者通过两个表的关联成功地解决了这一难题。

解决问题

我们以一个实际的例子来说明如何解决这一问题。设有一个表cenji.dbf,表的字段分别为:学号、姓名、姓别、成绩。新建一个表单,并创建一个Grid对象,设置Grid对象的recordsource属性为cenji,在Grid对象的afterRowColChange事件过程中添加如下代码:

LPARAMETERS nColIndex

if this.activerow = recno()

this.setall(“dynamicbackcolor”, “iif

(this.activerow=recno(), rgb(0,0,255),rgb(255,255,255))”,“column”)

else

select 学号from cenji where .not. deleted() into cursor temp_table

select temp_table

index on 学号 tag xh

set relation to 学号 into temp_table in cenji

sele cenji

this.setall(“dynamicbackcolor”,“iif(this.

activerow=recno(‘temp_table'), rgb(0,0,255),rgb(255,255,255))”,“column”)

endif

thisform.refresh

在上述代码中,当逻辑删除记录造成光标所在的行activerow()不等于数据的记录号recno()时,只需对数据建立一个关联子表,当记录指针在父表cenji中移动时,子表temp_table的记录指针移到学号相同的记录上。子表的记录号是不包括逻辑删除记录的,保证了光标所在行的子表记录号recno(‘temp_table')等于光标所在的行activerow(),从而使该行动态背景颜色能正确显示。本文为了说明方便, 在afterRowColChange事件过程中建立子表,实际上最好在Delete等命令之后建立。

另外,当activerow属性与recno()函数配合使用动态显示背景颜色时,一般会提示用户“请不要在所显示的记录中设定主索引”,否则不能正确动态显示。实际上,按照如上方法,同样可以解决这一问题。

设表cenji.dbf中,按成绩字段建立一个主索引,在Grid对象的afterRowColChange事件过程中写下如下代码:

LPARAMETERS nColIndex

select 学号 from cenji into cursor temp_table order by 成绩 desc

select temp_table

index on 学号 tag xh

set relation to 学号 into temp_table in cenji

this.setall(“dynamicbackcolor”,“iif

(this.activerow=recno(‘temp_table’), rgb(0,0,255),rgb(255,255,255))”,“column”)

thisform.refresh

同样,不一定要在Grid对象的afterRowColChange事件过程中建立关联子表temp_table。

本文代码在中文版Windows 98和Visual Foxpro 6.0中运行通过。

回到目录

Java 应用程序中的按值传递语义

节选理解参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递。写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用传递参数,以避免因依赖"按引用传递"这一行为而导致的常见编程错误。

对此节选的某些反馈意见认为,我把这一问题搞糊涂了,或者将它完全搞错了。许多不同意我的读者用 C++ 语言作为例子。因此,在此栏目中我将使用 C++ 和 Java 应用程序进一步阐明一些事实。

要点

读完所有的评论以后,问题终于明白了,至少在一个主要问题上产生了混淆。某些评论认为我的节选是错的,因为对象是按引用传递的。对象确实是按引用传递的;节选与这没有冲突。节选中说所有参数都是按值 -- 另一个参数 -- 传递的。下面的说法是正确的:在 Java 应用程序中永远不会传递对象,而只传递对象引用。因此是按引用传递对象。但重要的是要区分参数是如何传递的,这才是该节选的意图。Java 应用程序按引用传递对象这一事实并不意味着 Java 应用程序按引用传递参数。参数可以是对象引用,而 Java 应用程序是按值传递对象引用的。

C++ 和 Java 应用程序中的参数传递

Java 应用程序中的变量可以为以下两种类型之一:引用类型或基本类型。当作为参数传递给一个方法时,处理这两种类型的方式是相同的。两种类型都是按值传递的;没有一种按引用传递。这是一个重要特性,正如随后的代码示例所示的那样。

在继续讨论之前,定义按值传递和按引用传递这两个术语是重要的。按值传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。按引用传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的内存地址,而不是值的副本。因此,如果函数修改了该参数,调用代码中的原始值也随之改变。

关于 Java 应用程序中参数传递的某些混淆源于这样一个事实:许多程序员都是从 C++ 编程转向 Java 编程的。C++ 既包含非引用类型,又包含引用类型,并分别按值和按引用传递它们。Java 编程语言有基本类型和对象引用;因此,认为 Java 应用程序像 C++ 那样对基本类型使用按值传递,而对引用使用按引用传递是符合逻辑的。毕竟您会这么想,如果正在传递一个引用,则它一定是按引用传递的。很容易就会相信这一点,实际上有一段时间我也相信是这样,但这不正确。

在 C++ 和 Java 应用程序中,当传递给函数的参数不是引用时,传递的都是该值的一个副本(按值传递)。区别在于引用。在 C++ 中当传递给函数的参数是引用时,您传递的就是这个引用,或者内存地址(按引用传递)。在 Java 应用程序中,当对象引用是传递给方法的一个参数时,您传递的是该引用的一个副本(按值传递),而不是引用本身。请注意,调用方法的对象引用和副本都指向同一个对象。这是一个重要区别。Java 应用程序在传递不同类型的参数时,其作法与 C++ 并无不同。Java 应用程序按值传递所有参数,这样就制作所有参数的副本,而不管它们的类型。

示例

我们将使用前面的定义和讨论分析一些示例。首先考虑一段 C++ 代码。C++ 语言同时使用按值传递和按引用传递的参数传递机制:

清单 1:C++ 示例 #include

#include

void modify(int a, int *P, int &r);

int main (int argc, char** argv)

{

int val, ref;

int *pint;

val = 10;

ref = 50;

pint = (int*)malloc(sizeof(int));

*pint = 15;

printf("val is %d\n", val);

printf("pint is %d\n", pint);

printf("*pint is %d\n", *pint);

printf("ref is %d\n\n", ref);

printf("calling modify\n");

//按值传递 val 和 pint,按引用传递 ref。

modify(val, pint, ref);

printf("returned from modify\n\n");

printf("val is %d\n", val);

printf("pint is %d\n", pint);

printf("*pint is %d\n", *pint);

printf("ref is %d\n", ref);

return 0;

}

void modify(int a, int *p, int &r)

{

printf("in modify...\n");

a = 0;

*p = 7;

p = 0;

r = 0;

printf("a is %d\n", a);

printf("p is %d\n", p);

printf("r is %d\n", r);

}

这段代码的输出为:

清单 2:C++ 代码的输出 val is 10

pint is 4262128

*pint is 15

ref is 50

calling modify

in modify...

a is 0

p is 0

r is 0

returned from modify

val is 10

pint is 4262128

*pint is 7

ref is 0

这段代码声明了三个变量:两个整型变量和一个指针变量。设置了每个变量的初始值并将其打印出来。同时打印出了指针值及其所指向的值。然后将所有三个变量作为参数传递给 modify 函数。前两个参数是按值传递的,最后一个参数是按引用传递的。modify 函数的函数原型表明最后一个参数要作为引用传递。回想一下,C++ 按值传递所有参数,引用除外,后者是按引用传递的。

modify 函数更改了所有三个参数的值:

将第一个参数设置为 0。

将第二个参数所指向的值设置为 7,然后将第二个参数设置为 0。

将第三个参数设置为 0。

将新值打印出来,然后函数返回。当执行返回到 main 时,再次打印出这三个参数的值以及指针所指向的值。作为第一个和第二个参数传递的变量不受 modify 函数的影响,因为它们是按值传递的。但指针所指向的值改变了。请注意,与前两个参数不同,作为最后一个参数传递的变量被 modify 函数改变了,因为它是按引用传递的。

现在考虑用 Java 语言编写的类似代码:

清单 3:Java 应用程序 class Test

{

public static void main(String args[])

{

int val;

StringBuffer sb1, sb2;

val = 10;

sb1 = new StringBuffer("apples");

sb2 = new StringBuffer("pears");

System.out.println("val is " + val);

System.out.println("sb1 is " + sb1);

System.out.println("sb2 is " + sb2);

System.out.println("");

System.out.println("calling modify");

//按值传递所有参数

modify(val, sb1, sb2);

System.out.println("returned from modify");

System.out.println("");

System.out.println("val is " + val);

System.out.println("sb1 is " + sb1);

System.out.println("sb2 is " + sb2);

}

public static void modify(int a, StringBuffer r1,

StringBuffer r2)

{

System.out.println("in modify...");

a = 0;

r1 = null; //1

r2.append(" taste good");

System.out.println("a is " + a);

System.out.println("r1 is " + r1);

System.out.println("r2 is " + r2);

}

}

这段代码的输出为:

清单 4:Java 应用程序的输出 val is 10

sb1 is apples

sb2 is pears

calling modify

in modify...

a is 0

r1 is null

r2 is pears taste good

returned from modify

val is 10

sb1 is apples

sb2 is pears taste good

这段代码声明了三个变量:一个整型变量和两个对象引用。设置了每个变量的初始值并将它们打印出来。然后将所有三个变量作为参数传递给 modify 方法。

modify 方法更改了所有三个参数的值:

将第一个参数(整数)设置为 0。

将第一个对象引用 r1 设置为 null。

保留第二个引用 r2 的值,但通过调用 append 方法更改它所引用的对象(这与前面的 C++ 示例中对指针 p 的处理类似)。

当执行返回到 main 时,再次打印出这三个参数的值。正如预期的那样,整型的 val 没有改变。对象引用 sb1 也没有改变。如果 sb1 是按引用传递的,正如许多人声称的那样,它将为 null。但是,因为 Java 编程语言按值传递所有参数,所以是将 sb1 的引用的一个副本传递给了 modify 方法。当 modify 方法在 //1 位置将 r1 设置为 null 时,它只是对 sb1 的引用的一个副本进行了该操作,而不是像 C++ 中那样对原始值进行操作。

另外请注意,第二个对象引用 sb2 打印出的是在 modify 方法中设置的新字符串。即使 modify 中的变量 r2 只是引用 sb2 的一个副本,但它们指向同一个对象。因此,对复制的引用所调用的方法更改的是同一个对象。

编写一个交换方法

假定我们知道参数是如何传递的,在 C++ 中编写一个交换函数可以用不同的方式完成。使用指针的交换函数类似以下代码,其中指针是按值传递的:

清单 5:使用指针的交换函数 #include

#include

void swap(int *a, int *b);

int main (int argc, char** argv)

{

int val1, val2;

val1 = 10;

val2 = 50;

swap(&val1, &val2);

return 0;

}

void swap(int *a, int *b)

{

int temp = *b;

*b = *a;

*a = temp;

}

使用引用的交换函数类似以下代码,其中引用是按引用传递的:

清单 6:使用引用的交换函数 #include

#include

void swap(int &a, int &b);

int main (int argc, char** argv)

{

int val1, val2;

val1 = 10;

val2 = 50;

swap(val1, val2);

return 0;

}

void swap(int &a, int &b)

{

int temp = b;

b = a;

a = temp;

}

两个 C++ 代码示例都像所希望的那样交换了值。如果 Java 应用程序使用"按引用传递",则下面的交换方法应像 C++ 示例一样正常工作:

清单 7:Java 交换函数是否像 C++ 中那样按引用传递参数 class Swap

{

public static void main(String args[])

{

Integer a, b;

a = new Integer(10);

b = new Integer(50);

System.out.println("before swap...");

System.out.println("a is " + a);

System.out.println("b is " + b);

swap(a, b);

System.out.println("after swap...");

System.out.println("a is " + a);

System.out.println("b is " + b);

}

public static void swap(Integer a, Integer b)

{

Integer temp = a;

a = b;

b = temp;

}

}

因为 Java 应用程序按值传递所有参数,所以这段代码不会正常工作,其生成的输入如下所示:

清单 8:清单 7 的输出 before swap...

a is 10

b is 50

after swap...

a is 10

b is 50

那么,在 Java 应用程序中如何编写一个方法来交换两个基本类型的值或两个对象引用的值呢?因为 Java 应用程序按值传递所有的参数,所以您不能这样做。要交换值,您必须用在方法调用外部用内联来完成。

结论

我在书中包括该信息的意图并不是作琐细的分析或试图使问题复杂化,而是想警告程序员:在 Java 应用程序中假定"按引用传递"语义是危险的。如果您在 Java 应用程序中假定"按引用传递"语义,您就可能写出类似上面的交换方法,然后疑惑它为什么不正常工作。

我必须承认,在我第一次认识到 Java 应用程序按值传递所有参数时,我也曾表示怀疑。我曾一直假定因为 Java 应用程序有两种类型,所以他们按值传递基本类型而按引用传递引用,就像 C++ 那样。在转向 Java 编程之前我已用 C++ 编程好几年了,感觉任何其他事情似乎都不直观。但是,一旦我理解了发生的事情,我就相信 Java 语言按值传递所有参数的方法更加直观。The Java Programming Language,Second Edition 的作者,Ken Arnold 和 James Gosling 在 2.6.1 节中说得最好:"在 Java 中只有一种参数传递模式 -- 按值传递 -- 这有助于使事情保持简单。"

资源

要查找生成有效 Java 代码的实用方法,请参阅 Peter Haggar 的 Practical Java Programming Language Guide。

要了解如何有效地利用 Java 的构造、库和语言详细资料,请参阅 Ken Arnold 和 James Gosling 的 Java Programming Language,Second Edition。

请阅读 developerWorks 上发布的 Practical Java 的其他节选。

回到目录

用VB实现屏幕阴暗操作

作者:燕义怀 出处:中国电脑教育报

使用过Windows 9x的用户都应该知道,在关闭Windows系统时,整个屏幕会暗下来,那么,如何在自己开发的应用程序中也实现这一效果呢?我们通过调用一组API函数就可以实现,如果你有兴趣,就跟我来吧!这一组函数是:

GetDC :用来获取屏幕的设备号;

ReleaseDC :释放指定的设备;

CreatePatternBrush :创建图形刷子;

PatBlt: 利用创建的图形刷子填充指定设备;

DeleteObject :删除创建的对象(与CreatePatternBrush创建的刷子对象呼应);

CreateBitmap :创建BMP对象;

SelectObject :选择当前操作对象;

InvalidateRect :使操作无效,即恢复变暗前的状态。

基本思路

首先创建一个位图对象,然后,利用此位图对象创建一个图案刷子,选择指定设备为当前设备,利用已经创建的图案刷子填充当前设备,删除创建的刷子对象即可使当前设备变暗。调用InvalidateRect函数就可使指定设备恢复到变暗前的状态。

步 骤

1、创建一个Form1窗体,设置2个Command按钮,将Command1和Command2的Caption属性分别设置为:“变暗”和“恢复”。

2、在窗体代码模块中声明API函数和相应的类型,代码如下:

Private Type RECT

Left As Long

Top As Long

Right As Long

Bottom As Long

End Type

Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long

Private Declare Function CreatePatternBrush Lib "gdi32" (ByVal hBitmap As Long) As Long

Private Declare Function PatBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal dwRop As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long

Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

Private Declare Function InvalidateRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT, ByVal bErase As Long) As Long

3、编写代码实现程序功能,由于版面所限,具体代码将放到CCE网站(http://www.cce.com.cn)。

以上就是屏幕变暗的方法。如果要使窗体、图片框等对象变暗,只要使窗体或图片框等对象获取句柄即可,修改Command1_Click过程和Command2_Click过程中的以下语句即可实现窗体变暗。

hdc5=Form1.Hdc;

Width5=Form1.width;

height5=Form1.height;

ReleaseDC(Form1.hwnd,hdct)

aa=InvalidateRect (Form1.hwnd,bottom,1)。

以上程序在VB6.中文版,Windwos 98 环境中运行通过。有兴趣的朋友可以去试一试,看到这种效果是不是觉得很惊奇呢!

回到目录

用Delphi 控制窗体的大小

出处:中国电脑教育报

在我们使用的软件中,有些窗口在极大化时只占屏幕的一小部分,那么它是如何实现的呢!请看下面的例子:

1、在FORM私有声明部分加上如下一行程序:

procedure WMGetMaxInfo( var Message:TWMGetMinMaxInfo);message WM_GETMinMAXINFO;

2、在声明部分加上如下几行程序:

procedure TForm1.WMMinMaxInfo( var Message :TWMGetMinMaxInfo );

begin

with Message.MinMaxInfo do

begin

ptMaxSize.X := 400; //最大化时宽度

ptMaxSize.Y := 400; //最大化时高度

ptMaxPosition.X := 50; //最大化时左上角横坐标

ptMaxPosition.Y := 50; //最大化时左上角纵坐标

end;

Message.Result := 0; //告诉Windows你改变了最大化和最小化信息。

inherited;

end;

回到目录

VB与VC混合编程中处理消息的方法

现在越来越多的人采用VB与VC的混合编程:用VB快速开发出漂亮的界面以及外围处理程序,再用VC编写底层的各种操作,例如内存的操作、IO端口的操作等,VC中还可以嵌入汇编语言进行更底层的操作。

一般的做法是将VC程序编译成DLL,在VB中用Declare语句声明DLL中的函数,例如:

Declare Function SendCommand Lib ″c:\program files\devstudio\wjfprojects\Hr0506dllMnsr\debug\Hr0506dllMnsr.dll″(CmdNum As Integer) As Boolean

声明以后,函数SendCommand 就可以当作VB自己的函数使用了。

但是,怎样将VC中的各种消息(例如各种底层的状态)及时通知VB并且VB能够及时处理呢?这是VB的一个缺陷:不能方便地处理自定义的Windows消息。例如在VC中自定义了两条消息:MW_TAPI_DATACOME,MW_TAPI_BUSY,在C语言中,用PostMessage(hWnd,MW_TAPI_CONNECTED,0,0);语句可以很方便地将MW_TAPI_CONNECTED消息传递给窗体(窗体句柄为hWnd),在主回调函数中就可以处理了。但是要把这条消息传递给VB,并让VB处理这条消息,并不太容易。虽然在VB5.0以上的版本中,可以定义自己的事件(EVENT),但比较麻烦。这里介绍一种简单的方法,让VB巧妙地处理自定义的消息:

1.首先将VB窗体中TextBox控件Text1的句柄传递给DLL(注意:VB中的TextBox控件有hWnd属性)。

VB中: ′声明DLL中的函数

Declare Function SendhWnd Lib ″c:\program files\devstudio\wjfprojects\Hr0506dllMnsr\debug\ Hr0506dllMnsr.dll″ ((ByVal hWnd As Long) As Boolean

′传递text1的句柄

SendhWnd(text1.hWnd)

VC中://句柄接收函数

declspec(dllexport) BOOL GethWnd(HWND hWnd1)

{ hWnd=hWnd1;

if (hWnd==NULL)

{ return FALSE; }

return TRUE;}

2.在VC中用API函数SetWindowText取代PostMessage直接发送消息给VB中的Text1控件:

SetWindowText(hWnd,″ MW_TAPI_DATACOME ″);

3.在Text1_Change事件中处理消息:

Private Sub Text1_Change()

Select case Text1.text

case W_TAPI_DATACOME:

′消息处理语句

case MW_TAPI_BUSY:

′消息处理语句

default:

′其他处理语句

End Select

End Sub

以上方法在作者编写的“TAPI远程监控系统”中使用,效果很好。

回到目录

用VB设计VCD播放器

当你在用老牌的XingPlay或是华丽的《超级解霸5.0》的时候,你有没有想过拥有一个你自己编写的软解压播放器呢?其实你只要掌握一点VB的技巧,那么要实现这个愿望就变得很简单了。

笔者在初步研究了Windows的SYSTEM.INI后发现,通过VB的多媒体控件MCI.VBX可以打开MPEG压缩文件(如VCD2.0版的.DAT文件)。

首先你的Windows系统中SYSTEM.INI文件关于[MCI]中需有MPEGVideo项(一般Windows95和Windows98中都已有此项,通过安装XingPlay或CCDVP95等软件也可增加此项)。

其次在VB中建立一个新窗口,将MCI.VBX加入ToolBox中,将MCI控件拖放至窗体Form上,调整其大小,将九个按钮(从左至右为:Prev、Next、Play、Pause、Back、Step、Stop、Record和Eject)中Record按钮Visible属性设为False,其余按钮的Visible属性和Enabled属性设置为True,以上按钮的设置可通过MMControl的属性栏内“自定义”项来设置。

假设光驱为E:,VCD碟片文件为E:\MPEGAV\MUSIC01.DAT。

源代码如下:

Private Sub Form_ Load()

MMControl.DeviceType=″MPEGVideo″

MMControl.Name=″E:\MPEGAV\MUSIC01.DAT″

MMControl.Command=″OPEN″

MMControl.Command=″PLAY″

End Sub

Sub Form_Unload(Cancel As Integer)

MMControl.Command=″close″

End Sub

笔者通过实践发现Step和Back按钮功能不明显,所以对以上两个按钮进行了一些改进。

Sub MMControl_ StepClick(Cancel As Integer)

j=MMControl.Position+100′数值100为前进量,可适当调整

If j>MMControl.Length Then

MMControl.From=MMControl.Length

Else

MMControl.From=j

End If

MMControl.Command=″Play″

End Sub

Sub MMControl_ BackClick(Cancel As Integer)

i=MMControl.Position-100′数值100为后退量,可适当调整

If i<0 Then

MMControl.From=0

Else

MMControl.From=i

End If

MMControl.Command=″Play″

End Sub

MCI控件还有很多属性,如画面播放位置hWndDisplay属性等,读者可参阅相关资料自行摸索,这里不再介绍。读者还可以通过建立通用对话框来打开文件,以解决VCD文件名不统一或多文件的问题。

调整好窗体Form的标题、图标、颜色等,然后编译成EXE文件,你就可以在Windows下拥有自己的VCD播放器了。

另外,因电脑性能差异及VCD解码质量的不同,播放画面质量和音质将有所差异。

回到目录

用VB为软件增加注册功能

作者:郭瑞刚

在尊重软件著作权的时代,电子注册版软件的应用也越来越广。它的出现使用户对程序中未受限制的功能有了一定了解,起到了推广和传播作用,同时也很好地保护了制作人的切身利益。那么,我们如何制作一个电子注册版软件呢?

经过摸索,笔者利用VB也简单地制作了一个电子注册版软件。

设计原理

利用API中的“GetVolumeInformation”函数提取使用者机器的硬盘序列号为特征码,注册时提交此码,经过软件著作权人加以运算,给出注册码,最后软件使用人输入注册码完成整个注册过程(为使说明简单,本例中以特征码减101做为注册码)。

新建一模块文件

新建一模块文件,并将如下声明的语句和常量添加到Module1.Bas模块中:

Declare Function GetVolumeInformation Lib "kernel32" Alias "GetVolumeInformationA"

(ByVal lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal

nVolumeNameSize As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength As

Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String, ByVal

nFileSystemNameSize As Long) As Long

Global GetVal As Long

编程时需注意的是要将声明语句写在同一行中。

窗体设置

在Form1上添加2个文本框,Name属性分别设置为Text1、Text2;再添加1个按钮,Name属性设置为Command1。

添加代码

将如下程序代码添加到Form1的Form1_Load事件中:

Private Sub Form_Load()

Dim TempStr1 As String * 256

Dim TempStr2 As String * 256

Dim TempLon1 As Long

Dim TempLon2 As Long

………

‘读取是否注册的信息,如何控制这里不再说明

………

Call GetVolumeInformation("C:", TempStr1, 256, GetVal, TempLon1, TempLon2, TempStr2, 256)

Text1.Text = GetVal ‘提取本机C盘的序列号至文本框一

End Sub

将如下程序代码添加到Command1的Command1_Click事件中:

Private Sub Command1_Click()

If Text2 〈〉 CStr(GetVal) Then

MsgBox "注册码不正确,请认真检查输入是否正确。"

Else

MsgBox "你已经成功注册,请重新启动本软件。"

………

(将正确注册的信息写入,使软件功能以后不受限制。具体方法依个人爱好进行设置。)

………

End If

End Sub

至此,我们可以运行一下程序。你会发现我们已经简单地实现了利用硬盘序列号制作电子注册版软件的功能。

回到目录

《编程爱好者》订退方法

请在下面的文本框内输入您订阅本刊的邮件地址,并按右面的订阅按钮即可。如果您觉得这份刊物还不错的话,欢迎把它推荐给您的朋友。

欢迎订阅

不知道您看了这期刊物有什么想法或者是意见,欢迎向我提出来。

本人感激不尽,我的联系方法如下:

Homepage: http://www.pfan.net

E-mail: pfan2000@163.net

OICQ: 15987743

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有