代码实现

2024-10-31

代码实现(精选9篇)

代码实现 篇1

0 引言

托管代码调用非托管代码, 必定存在参数传递问题, 但其参数传递方法不仅与托管代码之间参数传递方法不同, 而且与托管代码之间参数传递方法也不相同。.NET平台提供了多种参数传递方法, 本文就托管代码调用非托管代码及其参数传递的实现方法进行了研究。

1 托管代码调用非托管代码的方法

托管代码可以通过静态 DLL 入口点的方式来访问非托管代码, DllImport 属性用于指定包含外部方法实现的DLL名称。DllImportAttribute是System.Runtime.InteropServices命名空间的一个属性类, 它提供对从非托管 DLL 导出的函数进行调用所必需的信息, 除必须提供包含入口点的DLL名称外, 其它参数都是可选的。用DllImport属性修饰的方法必须具有static和extern修饰符。

假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

extern “C” __declspec (dllexport) void WINAPI setInt (int value) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void setInt (int value) ;

C#代码中, 该方法只有声明, 没有实现。

2 数据传递的各种方法

2.1 基本数据类型参数传递

基本数据类型包括整型、浮点型、布尔型、字符型, C#和C/C++之间存在这些数据类型的对应关系。

2.1.1 参数传入

以C的unsigned int为例, 假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

extern “C” __declspec (dllexport) void WINAPI setUInt (unsigned int value) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void setUInt (uint value) ;

该方法只能将托管代码的参数传递到非托管代码。

2.1.2 参数传出

以C的double为例, 假定动态链接库Test.DLL导出的非托管代码C函数声明为:

extern “C” __declspec (dllexport) void WINAPI calc (double* value) ;

或extern “C” __declspec (dllexport) void WINAPI calc (double& value) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void calc (ref double value) ;

该方法既能将托管代码的参数传递到非托管代码, 也能将非托管代码的参数返回到托管代码。如果不需要将托管代码的参数传入非托管代码, 则只需要将C#类声明方法参数的ref修改为out即可。

2.1.3 函数返回值传递

如果函数返回值为基本数据类型, 则只需要将void修改为相应的数据类型即可。如果返回值为基本数据类型指针, 则需要将void修改为IntPtr, 并且需要调用System.Runtime.InteropServices.Marshal类的相应方法进行处理。

2.2 字符串参数传递

字符串是应用程序中常用的数据类型, .NET平台提供了string类型。因此字符串参数的传递实际上是.NET的string类型和C/C++中的char[]或char*类型的传递。

2.2.1 参数传入

假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

extern “C” __declspec (dllexport) void WINAPI setString (const char * value) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void setString (StringBuilder value) ;

该方法只能将托管代码的参数传递到非托管代码。

2.2.2 参数传出

假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

extern “C” __declspec (dllexport) void WINAPI setString (char * value) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void setString (ref StringBuilder value) ;

该方法既能将托管代码的参数传递到非托管代码, 也能将非托管代码的参数返回到托管代码。如果不需要将托管代码的参数传入非托管代码, 则只需要将C#类声明方法参数的ref修改为out即可。

2.2.3 函数返回值传递

如果函数返回值为字符串, 则只需要将void修改为IntPtr, 并且需要调用System.Runtime.InteropServices.Marshal类的相应方法进行处理。

2.3 结构参数传递

基本数据类型和字符串参数只能传递一个数据项, 当数据项较多时, 一般采用结构来描述。传递结构参数时, 必须在C#代码中声明与C/C++结构相对应的结构, 而且考虑效率因素, 一般通过指针或引用传递。如标识屏幕位置的C#结构声明为:

public struct Pos

{

public int x;

public int y;

}

2.3.1 参数传递

假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

extern “C” __declspec (dllexport) void WINAPI movePos (Pos* dest) ;

或extern “C” __declspec (dllexport) void WINAPI movePos (Pos& dest) ;

则C#类中声明外部方法为:

[DllImport ("Test") ]

static extern void movePos (ref Pos dest) ;

2.3.2 函数返回值传递

如果函数返回值为基本数据类型, 则只需要将void修改为IntPtr, 并且需要调用System.Runtime.InteropServices.Marshal类的相应方法进行处理。

2.4 回调函数传递

回调函数在Windows API中经常用到, 其调用关系如图1所示:

假定动态链接库Test.DLL导出的非托管代码C函数声明如下:

typedef void (_WINAPI *callback) (int value) ;

extern “C” __declspec (dllexport) void WINAPI callFunc (callback fn) ;

在C#代码中, 首先要定义委托函数类型public delegate void callback (int value) ;

然后在C#类中声明外部方法callFunc和回调函数实现方法callbackImpl:

[DllImport ("Test") ]

static extern void callFunc (callback fn) ;

static void callbackImpl (int value)

{

Console.WriteLine ("callbackImpl paramter value = {0}.", value) ;

}

采用以下方式调用callFunc方法:callFunc (new callback (callbackImpl) 。回调函数对参数的处理方法与2.1到2.3所述相同。

摘要:基于.NET平台的应用程序开发, 经常会需要调用Windows API等非托管代码DLL, 托管代码和非托管代码之间的参数传递是一个不可缺少的环节。.NET平台提供了多种参数传递方法, 每种方法都有其适用范围, 就托管代码调用非托管代码及其参数传递方法进行了探讨。

关键词:托管代码,非托管代码,调用,参数传递,C#

参考文献

[1]Christian Nagel.C#高级编程 (第4版) [M].李敏波, 译.北京:清华大学出版社, 2006.

[2]Microsoft Corporation, CSharp Language Specification[EB/OL].http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/csharp%20language%20specification.doc.

[3]Microsoft Corporation.平台调用教程[EB/OL].http://msdn.mi-crosoft.com/zh-cn/library/aa288468 (VS.71) .aspx.

[4]百川汇海.C# (.net) 中的DllImport[EB/OL].http://www.cn-blogs.com/xumingming/archive/2008/10/10/1308248.html.

代码实现 篇2

这篇文章主要介绍了Python实现线程池代码分享,本文直接给出实例代码,需要的朋友可以参考下

原理:建立一个任务队列,然多个线程都从这个任务队列中取出任务然后执行,当然任务队列要加锁,详细请看代码

import threadingimport timeimport signalimport os class task_info(object): def __init__(self): self.func = None self.parm0 = None self.parm1 = None self.parm2 = None class task_list(object): def __init__(self): self.tl = [] self.mutex = threading.Lock self.sem = threading.Semaphore(0) def append(self, ti): self.mutex.acquire() self.tl.append(ti) self.mutex.release() self.sem.release() def fetch(self): self.sem.acquire() self.mutex.acquire() ti = self.tl.pop(0) self.mutex.release() return ti class thrd(threading.Thread): def __init__(self, tl): threading.Thread.__init__(self) self.tl = tl def run(self): while True:tsk = self.tl.fetch()tsk.func(tsk.parm0, tsk.parm1, tsk.parm2) class thrd_pool(object): def __init__(self, thd_count, tl): self.thds = [] for i in range(thd_count):self.thds.append(thrd(tl)) def run(self): for thd in self.thds:thd.start() def func(parm0=None, parm1=None, parm2=None): print ‘count:%s, thrd_name:%s‘%(str(parm0), threading.currentThread().getName()) def cleanup(signo, stkframe): print (‘Oops! Got signal %s‘, signo)os._exit(0) if __name__ == ‘__main__‘: signal.signal(signal.SIGINT, cleanup) signal.signal(signal.SIGQUIT, cleanup) signal.signal(signal.SIGTERM, cleanup) tl = task_list() tp = thrd_pool(6, tl) tp.run() count = 0 while True: ti = task_info() ti.parm0 = count ti.func = func tl.append(ti) count += 1 time.sleep(2) pass

基于VSS代码数据解析的实现 篇3

一、关键技术与服务配置

为了能在JAVA中使用VSS提供的非界面调用方式,可以使用ANT工具。采用其提供的类实现与VSS数据交换功能。

1、俘获Source Safe事件

(1)MSVSSGET对象

MSVSSGET对象允许用户通过版本或时间取得Vss代码。实现时采用以下方法调用:

以上代码指出,当Source Safe Explorer工具被启动的时候,它寻找一个叫ssaddin.ini的文件。这个文件包含Source Safe附加项的信息,如果这个文件存在,Source Safe创建这个文件中提及的一个附件项实例。这个实例包括:登陆用户名、指定代码库源位置、取代码后目标位置、代码源是否为递归拿取设置、目标是否为可写设置标志、指定库中代码位置、通过版本或时间拿取的设置等。

(2)MSVSSHISTORY对象

MSVSSHISTORY对象可以取得指定时间、指定标签或指定开发人员的录入历史数据。代码实现中要设置如下信息:创建VSS的控制句柄MSVSSHISTORY对象。传入附加信息:登陆用户名称、本地目标位置、VSS库中路径、VSS源代码库路径、输出报告文档、设置需要的版本起始与结束时间或设置两个需要比较的标签标识名。

2、有效解析的VS S配置

VSS报告数据可以保存为两种格式的文本文件。报告文档解析前需要相关人员定制自己的界面格式。

文本格式的设置通过VSS界面启动->指定类的历史->diff>Format中的Visual或Source Safe选项设置。设置界面如下:

其一为单列格式,形如:

二、VSS数据解析实现

解析VSS提供的报告文档模块包括以下功能的实现:流文件处理、文件内整行数据处理、行末数据处理等,下面介绍个别功能的具体实现。

1、读取有效文档

读取指定文档,实现Buffered Reader流解析,通过指定文件读取内容,以便下一步处理,实现流程片段如下:

2、整行数据处理

☆添加数据处理;

☆删除数据处理

☆修改数据处理

☆作者信息处理

……

以上为解析VSS报告文档的实例说明。以行方式读入文档流,再处理不同类型的数据。其中不同数据类型之间有关联的部分需要特别考虑处理。

三、SQL数据录入

根据一次解析多次使用的指导思想,解析后的数据需要保存到Oracle数据库,方便以后的使用。数据录入模块的实现主要有以下部分组成:链接数据库、添加数据、修改数据、删除数据、移动数据、复制数据等。下面仅举例说明其中的几项,数据库表单部分的创建等相关功能及其维护不作讲解。

1、数据库链接及其关闭数据库

数据录需要先正确链接到指定的数据库,把数据导入到指定表单,通过以下步骤实现:

●连接数据库

●例如登陆IP为10.00.10.10:1521机器上共享的数据库VS

●取得vss表单中主关键字为codeid的最大数据

●数据录入完毕后,最不能忘记的事情就得算是关闭数据库了,就是常说的”出入关门“。

2、添加数据

解析完毕的数据保存到临时变量,并且要及时提交到数据库,通过数据库代码实现“insert into codechange……”,

以上数据为定制数据,包括数据为:代码名称、修改的开发人员、修改生效的标识、修改日期、修改时间、代码总改动量、代码添加量、代码删除量、代码修改量、代码长度、修改的注释内容、提交到的代码库名称等,视工作中需要的数据进行实际添加,添加规则符合SQL语句规范及其SQL表单建立原则。

四、结语

上述说明的是一个基于VSS,解析文档、数据入SQL数据库的代码解析实现,不包括查询数据的实现过程。此实现的Server端采用SQL Server组织管理“代码改变数据”(用来存放代码类名,提交者,提交版本,提交日期,提交时间,添加行数,删除行数,修改行数,修改版次,代码行数)和运行解析工具(定制运行时间)。Client端查询与其他资料库整合。它的主要特点是具有数据直观性、方便查询、统计等。开发人员通过提供的数据可以知道与自己相关的接口或模块那些有改变,可以获取代码改变信息。同时此系统可以提供给管理人员代码开发的实际数据,用于开发工作量的检查,新工作的规划、评估等。此系统的实现,使得开发人员对代码的修改更加直观,管理人员可以得到有效的代码开发数据。

摘要:为了方便代码检查分析、数据统计,为开发管理提供数据依据。本文基于Visual SourceSafe提供的API,采用JAVA语言、SQL等相关技术,建立一个针对开发人员代码修改、查询的数据解析实现。实际测试表明,应用此解析产生的数据可以为开发人员、管理人员提供相关查询数据作依据。目前,本系统已经为开发团队代码统计、查询等提供直接数据参考。

关键词:VSS:微软版本控制软件,SQL:结构化查询语言,ANT:Java开发界领先的构建工具

参考文献

[1]Cay S.Horstmann&Gary Cornell.Core JAVA,Volume II:Advanced Features Eighth Edition[M]陈昊鹏王浩姚建平等译.机械工业出版社,2010.

[2]贾佳,白瑞林,黄晓江,赵洁《嵌入式机器视觉实用彩色图像二值化方法》[J]江南大学学报(自然科学版),2011:11-15.

[3]史新元《Oracle Database11g SQL开发指南》[M].清华大学出版社.2011.

[4]开心就好.VisualSourceSafe讲义(网络免费技术讲座)[OL].网络信息技术有限公司&清华大学章鱼网络协会.2009.

[5]Matthew Bennett《.Oracle Developer编程指南》[M]武欣罗云峰刘侃等译.机械工业出版社,2002.

[6]Caucho Technology,Inc.[OL]Resin2.1.Copyright C1998-2001 Caucho Technology.All Rights Reserved.2001.

代码实现 篇4

最近刚换工作不久,没太多的时间去整理工作中的东西,大部分时间都在用来熟悉新公司的业务,熟悉他们的代码框架了,最主要的是还有很多新东西要学,我之前主要是做php后台开发的,来这边之后还要把我半路出家的前端学好、还要学习C++,哈哈,总之很充实了,每天下班回家都可以睡的很香(一句话总结,就是吃得香、睡的香~)。再说说换工作时候吧,今年年初正式毕业半年了,感觉自己技术增长很快,原公司里面程序员的地位还不如运营,所以想换个工作,面试了3家(2家大的、一家小的),都给offer了,当然从大公司里面挑了个各方面综合(工资、干什么、交通等等)还不错的,反正感觉就很顺利的进来了(比毕业的时候容易多了),哈哈,越努力、越幸运,越幸运、越努力!。从这周开始,继续整理博客,免得给自己造成懒得习惯。

刚来这个公司,熟悉了环境,老大就开始让我做一个迁移、修改代码的工作,我想说的是,这种工作真没劲~~,看别人的代码、改别人的代码、这里改个变量、那里改个文件名・・・・・・,都是些没技术含量、很繁琐的事情,不过通过迁移代码顺便熟悉下环境也好。扯了这么多,说说今天的主题吧――代码编码格式改变,由于某些原因,需要将代码从A机房迁移到B机房,这两个之间不能互相访问,但是历史原因导致A机房的代码全是utf8编码的,B机房要求是GBK编码,看看这个怎么解决。

编码问题

先说说为什么会有编码问题,就拿上面那个例子来说,B机房这边数据库全是GBK编码的,因此从数据库中取出来的数据都是GBK的,从数据库中取出来的数据是GBK编码的,要在展示的时候不乱码,在不对数据库取出的数据转换的情况下,就需要发送header的时候设置编码为GBK,输出的文件(html、tpl等)都必须是GBK的,看看下面这个图会更清楚点:

DB(GBK) =>php等(编码格式不限但如果代码文件中有汉字,文件就要是gbk编码或者在汉字输出的时候转化为gbk) =>header(GBK)=>html、tpl(GBK)

或者还有一种方式只在出库的时候在代码中将utf8转化为gbk,总的来说utf8还是更流行点,问题更少点

DB(GBK) =>php等(utf8,并将从数据库取出的数据转化为utf8) =>header(utf8) =>html、tpl(utf8)

只要按照上面这两种规范编码格式,就不会出现乱码情况,起码我测试的第一种方式是没问题的,所以我猜第二种也ok,好了,现在就来写一个转换文件编码格式的小脚本:

#!/usr/bin/python# -*- coding: utf-8 -*-#Filename:changeEncode.pyimport osimport sysdef ChangeEncode(file,fromEncode,toEncode): try: f=open(file) s=f.read() f.close() u=s.decode(fromEncode) s=u.encode(toEncode) f=open(file,”w“); f.write(s) return 0; except: return -1;def Do(dirname,fromEncode,toEncode): for root,dirs,files in os.walk(dirname): for _file in files:_file=os.path.join(root,_file)if(ChangeEncode(_file,fromEncode,toEncode)!=0): print ”[转换失败:]“+_fileelse: print ”[成功:]“+_filedef CheckParam(dirname,fromEncode,toEncode): encode=[”UTF-8“,”GBK“,”gbk“,”utf-8“] if(not fromEncode in encode or not toEncode in encode): return 2 if(fromEncode==toEncode): return 3 if(not os.path.isdir(dirname)): return 1 return 0if __name__==”__main__“: error={1:”第一个参数不是一个有效的文件夹“,3:”源编码和目标编码相同“,2:”您要转化的编码不再范围之内:UTF-8,GBK“} dirname=sys.argv[1] fromEncode=sys.argv[2] toEncode=sys.argv[3] ret=CheckParam(dirname,fromEncode,toEncode) if(ret!=0): print error[ret] else: Do(dirname,fromEncode,toEncode)

脚本很简单,使用也很简单

代码如下:

./changeEncode.py target_dir fromEncode toEncode

这里要注意下,几种常见编码的关系:

us-ascii编码是utf-8编码的一个子集,这个是从stackoverflow上得到的,原文如下ASCII is a subset of UTF-8, so all ASCII files are already UTF-8 encoded,

我试了下确实是的,在不加汉字的时候显示编码为us-ascii,加了汉字之后,变为utf-8,

还有就是ASNI编码格式,这代表是本地编码格式,比如说在简体中文操作系统下,ASNI编码就代表GBK编码,这点还需要注意

还有一点就是一个在linux下查看文件编码格式的命令是:

代码如下:

file -i *

可以看到文件的编码格式。

当然了,上面的可能有些文件中有特殊字符,处理的时候会失败,但一般程序文件是没有问题的。

以上就是本文所述的全部内容了,希望对大家学习python能够有所帮助。

代码实现 篇5

关键词:Android,飞行模式,编程

Android操作系统是Google公司于2007年发布的一种智能手机操作平台, 它是一个由操作系统、中间件、用户友好界面和应用软件组成的, 全面整合的移动软件平台。自推出以来, Android受到了业界的广泛关注, 基于Android的智能手机的发展也极其迅猛, 目前在智能手机的市场占有率已经稳居第一。然而遗憾的是, Android系统并没有提供定时自动开关机功能, 因此, 习惯夜晚关机的用户必须每日晚上手动进行关机操作, 次日早晨再手动开机, 比较繁琐。另外, 很多厂商开发的基于Android系统的手机并不支持关机闹钟功能, 一旦关机后, 设定的闹钟就不再起作用, 给用户带来很多不便。因此, 越来越多的用户目前倾向使用启用飞行模式来代替关机操作, 因为在飞行模式下, 闹钟是可用的。但系统同样没有提供定时自动开关飞行模式的设置选项, 该文的目的就是介绍如何自主编程开发这一功能。

1 飞行模式简介

手机的飞行模式又叫航空模式、航班模式。飞行模式打开后, 将关闭手机的通信功能, 即不能接打电话发短信, 与基站没有信号联系, 也不试图联系基站。同时手机的移动数据网络和WIFI模块也会被关闭。因为手机信号会干扰飞机上的电子设备, 所以飞机上不允许打开手机, 而在飞行模式下关闭了手机信号的有关功能, 手机可以开着继续使用其它功能, 如查看电话本、欣赏手机上的文章、电影等。所以叫这种模式被称为飞行模式。因为手机的电量很大部分都消耗在无线信号通信上, 飞行模式下关闭了所有无线信号通信, 因此非常省电。

2 代码实现

本系统手机客户端开发环境为Android2.3, 采用JDK1.6版和Eclipse3.7来编程实现。

代码主要由两个类组成:Airplane Mode Switch Activity类和Alarm Receiver类。其中Airplane Mode Switch Activity类是Activity类的子类, 用来实现程序主界面, 主要用来设置定时开关的时间和启动关闭程序等功能。Alarm Receiver类是Broadcast Receiver类的子类, 主要用来响应Alarm Manager发出的广播intent, 并执行打开或关闭飞行模式的代码。

由于打开和关闭飞行模式的代码流程几乎一致, 下面以打开飞行模式为例介绍一下具体的编程步骤:

1) 在主界面上设置Time Picker控件来设置打开飞行模式的时间。Time Picker继承了Frame Layout类, 可以向用户显示一天中的时间 (可以为24小时, 也可以为AM/PM制) , 并允许用户进行选择。

2) 通过Gregorian Calendar类的默认构造方法取得当前系统的时间, 并利用当前时间的年月日加上Time Picker控件中设置的小时和分钟构造出打开飞行模式的时间。需要特别注意的是, 此时需要比较此时间和当前系统时间的先后, 如何当前系统时间已经晚于此时间, 说明用户设置的是第二天这个时候自动打开飞行模式, 因此需要将此时间的日期加1。

3) 设置Intent和Pending Intent对象, Intent一般是用作Activity、Sercvice、Broadcast Receiver之间传递数据, Pending Intent可以看作是对Intent的包装, 通常通过get Activity, get Broadcast, get Service来得到pendingintent的实例, 当前activity并不能马上启动它所包含的intent, 而是在外部执行pendingintent时, 来调用封装的intent的。我们这里设置的Intnent指向Alarm Receiver类, 用来当Alarm Manager设定时间到达的时候发出广播。

4) 设置Alarm Manager对象。Alarm Manager的作用是:在特定的时刻为我们广播一个指定的Intent。简单的说就是我们设定一个时间, 然后在该时间到来时候, Alarm Manager为我们广播一个我们设定的Intent。我们通过该对象的set Repeating方法来设置一个重复的定时器, 重复时间为24小时, 也就是每天相同的时间打开飞行模式。需要注意的是, 我们开始时尝试使用Timer定时器类来实现相同的功能, 但经过实践发现, Timer类定时器在手机进入待机状态时就不再起作用, 因此不适合用在这样的场合使用。

5) 当定时器发出广播后, 由Alarm Receiver类负责处理。要实现这一点, 必须在项目的Android Manifest.xml文件中加入代码进行说明。Alarm Receiver类是Broadcast Receiver类的子类, 该类对父类的on Receive方法进行了覆盖, 自定义了当接收到广播时进行的处理代码。在这里通过Settings.System.put String (cr, Settings.System.AIRPLANE_MODE_ON, "0") 方法就可以将飞行模式打开, 之后通过广播Intent (Intent.ACTION_AIRPLANE_MODE_CHANGED) 通知系统飞行模式的状态已经发生了改变。

3 结束语

Android系统作为目前最为流行的智能手机操作系统, 在各方面的性能都比较优秀, 然而, 缺乏对自动开关机功能和关机闹钟功能的支持是一大遗憾。该文分析飞行模式的原理, 探讨了用飞行模式取代关机的可能性, 并给出了实现定时自动开关飞行模式的代码实现, 希望对系统的研究产生一定的参考作用。

参考文献

[1]郭蕊.基于Android平台的GPS定位系统的设计与实现[J].北京工业职业技术学院学报, 2012, 11 (2) .

[2]倪红军.基于Android平台的移动终端GPS研究[J].计算机技术与发展, 2012 (5) .

代码实现 篇6

关键词:VHDL,可编程逻辑器件,代码复用,用户库

1 引言

随着可编程逻辑器件技术的发展, 芯片的性能越来越强、规模越来越大、开发的周期越来越长, 使得器件应用正面临一系列新的问题:设计质量难以控制, 设计成本也越来越高。IP (Intelligence Property) 技术解决了当今芯片设计业所面临的难题。设计者可以重复使用已经设计并经过验证的IP核, 将精力集中于系统顶层及关键功能模块的设计上, 从而提高产品整体性能和个性化特性, 加快了设计效率。

如何才能提高IP核的重复使用率, 使设计资源更好地集中起来加以利用, 是可编程逻辑器件应用面临的另一个问题。在VHDL (VHSIC Hardware Description Language) 语言中, 库 (LIBRARY) 文件很好地解决了这个问题。库文件是专门用于存放预先编译好的程序包 (PACKAGE) 和数据集合体, 这些设计单元可用作其他VHDL描述的资源。用户编写的设计单元既可以访问多个设计库, 又可以加入到设计库中, 被其他单元所访问。此外, 库的使用能够实现层次化设计和功能模块化设计方法, 有利于使复杂设计具有更清晰的结构。

2 库组成

在VHDL中, 常用的库有IEEE、STD、WORK、用户库等。库文件常用的语句为元件 (COMPONENT) 和子程序 (过程和函数) , 为了使程序包能够被编译, 元件和子程序必须被添加到被称为包集合的程序包中。用户库是用户定义库的简称, 是由用户自己创建并定义的库。设计者可以把自己开发的非标准包集合和实体等汇集成在一起定义成一个库, 作为对VHDL标准库的补充。用户将需要重复使用的代码以元件和子程序的形式放到包集合中, 编译到目标库中, 生成用户库, 供其它设计单元调用。在设计中要使用某个程序包中的内容时, 用USE语句即可打开该程序包。

3 库构件说明

3.1 包集合

在用户库中, 包集合放置的是用户自己定义的元件、函数、过程。包集合包括包头和包体两部分。包头用来声明包中的类型、元件和子程序;而包体则用来存放说明中的元件源代码和子程序。程序包声明单元的语法格式为:

其中说明语句为:USE语句、类型定义、常量定义、元件声明、子程序声明及信号声明等。程序包体单元的的语法格式为:

3.2 元件

用户库通过元件定义的方式, 将一些设计好的电路单元纳入, 其他设计体则通过元件实例化的方法调用这些元件, 使得元件与其他设计实体中的端口相连接, 从而为当前设计实体引入低一级的设计层次设计。

3.2.1 元件定义

元件定义语句放在包集合的包头中, 指出包集合所包含的具体元件, 元件源代码可以独立编译, 不需要纳入包集合中。元器件定义语句的语法格式为:

其中, 常量、参数列表与元件源代码实体中的GENERIC部分相同;元件端口列表, 与元件源代码实体中的PORT部分相同。

3.2.2 元件调用

元件调用称为元件实例化, 在元件实例化过程中有位置映射和名称映射两种方法可以实现。

位置映射中参数、端口信号名称在顺序、端口状态和数据类型上必须和元件源代码保持一致, 各个参数、端口意义取决于它的位置。位置映射元件实例化语句的语法格式为:

名称映射用符号“=>”连接元件参数、端口和结构体之间的参数、端口。名称映射元件实例化语句的语法格式为:

其中, 左边列出元件源代码中参数、端口名称, 右边列出调用代码中对应的参数值、端口信号名称。左右两边的数值、信号名称可以不相同, 语句中位置顺序可以任意。

3.3 子程序

VHDL中的子程序有过程 (PROCEDURE) 及函数 (FUNCTION) 两类, 主程序和子程序之间通过端口参数列表位置关联方式进行数据传送, 子程序可以被多次调用完成重复性的任务。子程序包含子程序声明和主体两部分, 子程序声明必须要在包头中, 子程序主体则放在包体中。

3.3.1 函数

函数通常用来实现数据类型转换、逻辑运算、算术运算类型的代码共享和重用, 即输入若干参数, 通过函数运算求值, 最后直接返回一个值。函数应用分为建立和调用两个过程。

(1) 函数建立。函数分为函数声明和函数主体体, 函数声明是包集合与函数的接口界面, 放在包集合的包头部分, 而函数主体应放在包集合的包体内。函数声明首语句的语法格式为:

其中, 参数列表中为参数名、参数类别及数据类型, 函数的参数为信号或常数, 默认情况为常数。

函数体语句的语法格式为:

其中, 在RETURN后面的数据类型为函数返回值的类型;子程序声明项用来说明函数体内引用的对象和过程;顺序语句就是函数体, 用来定义函数的功能。

(2) 函数的调用。函数可以单独构成表达式, 或者作为表达式的一部分调用。函数调用语句的语法格式为:

3.3.2 过程

过程的作用是传递信息, 即通过参数进行调用代码和过程代码的信息传递。其中参数需说明类别、类型及传递方向。

(1) 过程建立。过程分为声明和过程主体, 声明应放在包集合的包头部分, 过程定义的主体代码应放在包集合的包体内。

过程声明的语法格式为:

其中, 参数声列表指明了输入、输出端口的数目和类型。

参数声明的语法格式为:

其中, 参数可以有任意多个;参数模式有in、out、inout、buffer形式;参数类型, 可以是常数、信号、变量, “in”默认为常数, “out”和“inout”默认为“变量”, 若需要将“out”和“inout”作为信号使用, 则在过程参数定义时必须指明是信号。

过程定义的语法格式为:

顺序语句;

(2) 过程的调用。过程的调用是一条语句, 调用时通过其接口返回0个或多个值。过程可以直接调用, 也可以在其他语句中调用。过程调用语句的语法格式为:

在过程语句执行结束后, 如没有特别说明, 输出和输入输出参数将按变量对待将值传递给调用者的变量。如果调用者需要输出和输入输出作为信号使用, 则在过程参数定义时要指明是信号。

4 库的调用

使用库之前, 首先需要对库进行声明。经过声明之后, 在设计中就可以调用库中的代码了。用户库声明的语法格式:

5 结束语

用户库是VHDL语言中非常重要的代码分割、共享、重用的方法, 只要将重用的代码按功能特性以元件、函数、过程形式构建成可重用部件放置在包集合内, 经过编译后生成用户库文件, 在后续编码过程中通过库声明即可调用用户库。

用户库的使用可以使代码结构更加清晰, 并且库中的代码通常要经过严格的测试和优化, 利用用户库进行电路设计, 可以在FPGA等可编程逻辑器件中达到最优的性能和最低的逻辑资源使用率, 以保证电路的性能和质量。因而, 能在降低开发成本、缩短开发周期的同时提高了设计可靠性。

参考文献

[1]孙晓东.FPGA软件设计[J].电脑编程技巧与维护, 2010, (12) :5-6.

[2]李冰, 吴金, 魏同立.基于可重构核的FPGA电路设计[J].固体电子学研究与进展, 2003, 1 (23) :108-109.

[3]侯伯亨, 顾新.VHDL硬件描述语言与数字逻辑电路设计[M].西安:西安电子科技大学出版社, 1999.

代码实现 篇7

关键词:代码重用,代码绑定,用户控件,自定义控件

代码的可重用性一直是软件开发人员最为关心的问题, 它能够降低开发投入, 提高软件的质量, 减少维护的成本。ASP.NET在构造新一代动态网站和基于网络的分布式应用提供了强有力的支持, 而且面向对象技术在ASP.NET中得到了完全实现。代码重用是面向对象开发中的一个非常重要的特性。下面介绍几种在ASP.NET下实现代码重用的方法。

1 代码绑定技术

在ASP.NET中利用code_behind表单可以使HTML代码与实现其功能的代码分开, 分别放在不同的文件中, 实现表示层与模型相分离。ASP.NET的HTML文件扩展名是.aspx, 可以仅仅包含HTML代码和服务器端控件, 代码绑定文件是一个独立的文件, 可以使用任何.NET支持的语言编写。比如, 使用C#来编写这些文件, 它的扩展名将会是".aspx.cs"。这个代码绑定文件包含了所有的和表示层相关的事件、功能函数、方法等等。在aspx文件当中, 使用@page指令来说明正在使用哪个.aspx.cs代码文件与之绑定。@page指令通过设置两个属性:src以及inherits使代码绑定文件与.aspx文件联系起来。Src属性 (c#中是Codebehind属性) 指定了包含实际代码的文件, Inherits属性指定在源文件中存在的类。这个类需要从Page类中派生。例如在HTML文件中使用<%@Page Language="c#"Auto Event Wireup="false"Codebehind="Search.aspx.cs"Inherits="Search"%>语句即指出HTML文件Search.aspx的代码文件是Search.aspx.cs。使用代码绑定技术代码重用体现在, 在需要建立两个为了相同或相似目的页面的时候使用, 即, 两个或多个外观不同的页面使用相同的代码文件, 这时候起到了很好的代码重用的作用。比如, 假设你需要为两种不同类型的用户建立两个登录页面, 并且两个页面在外观界面上面有很大不同 (但是实际上的起到的作用是非常类似的) 。这样建立两个ASPX文件, 他们可以共用一个相同的代码绑定文件, 代码文件得到重用。

使用代码绑定技术实现的代码重用其中一个较大的局限性就是一个ASPX文件仅仅能够继承一个类。这就意味着开发者将不得不为每一个ASPX页面开发一个针对它的代码绑定页面, 除非是遇到了上面的我们曾经描述过的相似情节才可以多个ASPX文件共享一个公用的代码绑定页面。如果那些ASPX页面差别很大, 则在重利用代码绑定页面的时候会有一些麻烦。

2 用户控件

2.1 用户控件的建立

建立用户控件的第一步是建立一个.ascx文件。该.ascx文件只包含方法、函数以及和用户控件相关的内容。以定义一个用户登录控件为例, 假设有两个提示标签, 两个文本框以及两个按钮。首先加入这些web控件, 命名为login.ascx, 在该用户控件中, 可以定义不同的属性, 也可以定义任意的方法, 这些属性和方法定义了用户控件的功能。在用户控件当中添加属性和方法后, 控件的开发也就基本完成了。

2.2 用户控件的使用

要将用户控件放置在其它页面中, 首先必须在该页面中使用页面编译指令.Register注册该控件。.Register编译指令语法如下:<%@Register Tag Prefix="Prefix"Tag Name="Control Name"src="filepath"Namespace="name"%>, 其中Tag Prefix属性定义了使用这个用户控件的时候想要用的名称空间。Tag Name属性定义了这个用户控件的实际名称, 这个名字将会用在页面上面标示用户控件。Src属性指定用户控件要使用的资源位置, Namespace属性是可选元素, 它指定了与Tag Prefix相关的名称空间, 这有助于进一步将用户控件分组和分类。其次引入定义的用户控件, 如:<%@Register Tag Prefix="LG"Tag Name="login"src="login.ascx"%>。当你加入一个用户控件到一个.aspx页面的时候, 相应的语法同加入一个web控件类似。首先使用标签前缀和标签名称来标示用户控件:现在, 在页面上有了这个空间, 可以设置标准的runat和id属性, 以及设置以前建立控件时建立的各个自己定义的属性。有两种方法来修改这些用户控件的属性。一种方法是在web页面当中引用这个用户控件的时候明确的设置它的各个属性的值。如:;另外一种方法是在一个.aspx文件的page_load事件中设置这些用户控件的属性。如:

在使用编译指令.Register注册了用户控件之后, 对用户控件的使用就和其它服务器控件的使用完全相同.可以在多个.aspx页面内使用, 实现代码重用。用户控件为程序员带来了很高的开发效率和重用性, 更是在性能方面有了很大的提高。

3 自定义控件

自定义控件的创建

自定义控件的过程如下: (1) 用imports导入需要用到的名称空间。 (2) 声明自己定义的名称空间 (3) 给出控件名称和继承的基类。 (4) 制定控件属性、加入控件事件。 (5) 重写Web Control的Render方法。 (6) 编译该文件并放到…bin目录下。

创建并编译自定义控件后, 可以在任何页面中就象使用用户控件一样使用它, 同样必须引用@Register编译指令, 只是Tag Name被Namespace, src被Assembl属性代替.Namespace是自定义控件的名字空间:Mycontrols。Assembly属性指定编译后的源文件:mycontrl (编译后的文件名) 。命令形式为:<%@Register Tag Prefix="AB"Namespace="Mycontrols"Assembly="mycontrl"%>。引入该命令后, 在ASP.NET页面中即可以像使用其它控件一样实现。

结束语

本文给出了在ASP.NET中实现代码重用的几种方式, 介绍了每种方式的实现与使用过程, 代码绑定技术容易实现, 但用起来受到很大限制;用户控件比较实用, 既可以简单地把常用的几个控件封装在一起, 不编写任何额外代码组成一个复合控件, 也可以从现有控件派生并重写其属性、方法或事件, 使其具有更符合自己的要求, 使用更加方便;自定义控件可以让你基于某类基本控件产生一个满足自己特殊要求的新控件, 然后像其它原有控件一样使用。几种方式中设计的复杂度呈递增性, 所以只有当前者达不到项目要求时才考虑后者的使用, 用户控件和自定义控件的代码可重用性都比较好, 恰当的使用会使软件开发过程简洁而易于维护。

参考文献

[1]Cheia payne, 赵斌.ASP.Net入门到精通[M].北京:人民邮电出版社, 2012.

代码实现 篇8

《数字化生存》的作者尼葛洛·庞蒂曾说过:“计算机不再只和计算机有关, 它将决定我们的生存。”数字化革命为电视台迎来机遇的同时, 也为传统媒体带来挑战。新媒体的发展, 毫无悬念地蚕食着传统电视的份额。综合发挥优秀节目的版权价值和节目资料的再利用价值已成为应对新媒体冲击的“突围之路”。为了使电视节目资料在支持节目创作的同时, 进入增值产业链, 创造更多经济价值, 我们将从电视台节目代码“一码到底”的设计思想出发, 共同探讨节目资料综合管理的途径与手段。

1 从节目资料到内容资产的“蜕变”, 必须完善节目资料的综合管理和评估利用手段

国家广电总局1994年颁布《广播电视宣传档案、资料管理办法》, 首次以行政法规的形式定义了广播电视节目资料的行业管理要求。在广电媒体全球化、数字化、市场化不断发展的行业背景下, 节目资料的重要价值愈发突显。节目资料数据库及媒资系统的产生正是为了解决原来对节目资料的“粗犷”管理所显现出来的不足。新技术的发展和媒体的变革促使电视媒体管理者深刻认识到节目资料的战略核心价值以及对节目生产可持续发展的重要推动作用。通过媒资系统对节目资料深入和全面的管理, 节目资料除了承担节目创作的基本功能, 更有条件变为有形资产直接产生巨大的经济效益。电视节目资料已经从单纯的生产资料“蜕变”为可产生直接经济效益的节目内容资产。

电视台作为文化产品的生产和传播机构, 一方面要会利用节目资料进行节目创作和生产, 另一方面要加强节目资料的综合管理能力, 实现从“资料”到“资产”的转变。在电视媒体经营活动过程中, 电视节目资料真正成为媒体内容资产应该具备几个基本条件:首先是广泛的可利用性, 其次是清晰的版权信息, 第三是具备合理的价值评估体系和销售平台, 使资料的二次开发可再创造价值。电视台媒资系统的建设已经使节目资料在内部的共享使用成为可能, 如何利用现有条件为节目资料的二次开发和再利用提供条件, 让节目资料走入市场真正成为创造额外价值的“内容资产”, 是广大媒资内容管理者苦心寻找的创新之道。

2 以节目代码贯穿生产全流程, 为快速形成资产元数据创造条件

2.1 编目是媒资内容管理初期的最有效手段

节目资料的管理者往往面对的是大量离散分布和保存的海量资料。在媒资系统建立初期, 首要任务是不断丰富库存资料, 以时间线和节目线两个维度在库存容量建设上不断扩充, 达到满足节目制作和安全保存的基本需求。这个时候的内容资料有以下特点。

1) 资料来源不统一, 大多以收集离散在编导手中的视频内容资料为最初目标, 来源复杂, 质量不统一。

2) 内容类别较分散, 相互之间关联性不强。大批量的资料收集和提交过程很难快速建立起有效内容管理机制, 只能做到先安全保存、后细化管理。

3) 资料内容管理主要依靠编目建立检索条件, 并通过检索系统实现媒资内容的查询和调用。

4) 管理效率较低。由于节目资料入库以后, 大部分需要靠人工建立检索数据信息, 编目工作依赖第三方人员进行, 对素材内容的拆分和编目过程由于对原始拍摄环境不了解, 造成后期管理效率不高。

在这个阶段, 对内容的拆分、筛选和编目是为后期资料使用者建立查询和检索条件的必由之路。随着资料库存的不断增多, 后期编目人员数量需求大幅增长, 管理负担不断加重。如何找到更好方法, 将节目资料管理从后端逐步引向前端, 提高管理质量和效率, 必须从电视节目生产的流程和特点去寻找突破口。

2.2 生产型媒资的建立, 使媒资代码管理模式成为可能

生产型媒资从系统组织结构上来看, 比传统资料馆型媒资系统在对节目和素材的综合管理方面存在先天优势, 主要体现在:

1) 成品节目和素材的关联关系更加直观、明确, 对素材的管理更加方便。

2) 对媒资的管理节点比传统媒资更加接近拍摄前端, 获得信息的途径更加直接。

3) 制播网络和媒资网络通过全台系统链路实现对接, 节目资料相关版权、管理信息可以直接继承和移植, 大大节省了后期拆分和编目时间, 效率更高。

4) 通过节目编导的参与, 实现了节目资料入库前对主要内容可以完成初级编目和基本信息的录入, 用户对媒资管理的参与性更强, 更有利于后期开发利用。

针对生产型媒资的系统特点, 如果能找到生产型媒资与网络化制播体系之间的联系纽带, 就可以让原本独立的媒资系统整体融入到全台网络化环境中, 变“独立作战”为“多元化管理”, 极大的拓宽了媒资管理信息的来源和渠道。为了寻找媒资系统与制播管理系统之间的结合点, 以节目代码的“身份证”方式管理节目和素材的媒资代码管理模式脱颖而出。

2.3 媒资与代码管理模式的探寻与启示

2.3.1 以节目代码管理模式实现播出版节目元数据的快速整理, 推动节目成片播出后尽快形成“内容资产”, 创造节目附加价值

北京电视台从2008年开始逐步进入全台网络化阶段, 首先实现了节目制作和播出的“代码制”管理。“一码到底”的管理方式为综合管理节目相关信息创造了条件。

1) 申报和立项阶段, 通过代码为栏目建立账户。

2) 拍摄和制作阶段, 通过节目代码综合节目文稿、节目相关人员、节目执行方案的过程信息。

3) 审查和播出阶段, 严格记录审查意见、播出安排情况;

4) 播后管理阶段, 通过代码提取节目版权信息, 完成成品节目相关管理信息的完整记录。

节目代码对成品节目的管理能力, 取决于我台节目代码体系的设计思想和管理模式, 通过代码方式在节目制播全流程中对各个节点环节的控制, 实现了过程可跟踪、内容好管理、流程可控制、信息好发布, 对成品节目资料实现快速入库, 为实现节目对外输出与销售的购销产业化创造了条件。节目代码作为整个节目生产播出流程的主线, 贯穿了节目创作的各个关键节点, 通过在各节点收集信息, 最终达到汇聚播出版节目元数据信息的目的, 加快成品节目发布过程, 减少播出后端处理环节, 促进播出版节目资料更快具备“内容资产”的基本属性。

2.3.2 以成品节目代码管理体系为依托, 探索节目素材代码管理的工作模式和实践方法, 形成“成片+素材”的复合型媒资管理模式

生产型媒资的建立, 首先确保了在整个节目生产过程中, 节目相关信息会被快速搜集并以节目元数据的形式进行保存, 为节目的二次开发创建了条件, 实现了媒资系统对节目成片管理的前移, 提高了媒资系统处理成品节目的效率。可否以此为基础, 对节目相关的素材内容也采用代码方式进行管理, 实现“成片+素材”的统一管理, 使成品节目与视频资料成为有机整体, 实现拍摄素材的媒资化快速处理呢?这样做有几个好处:

1) 相关数据的继承性将加快资料编目效率。

2) 以节目为中心聚合相关资料, 快速实现在同类素材之间建立关联关系, 形成“网状”的节目资料关系图, 加快检索效率。

3) 以素材代码作为节目资料的唯一标示, 方便以节目资料条目为中心开发节目资料对外销售平台, 实现节目资料综合利用的产业化目标。

4) 在确保节目资料被完整保存的前提下, 将素材代码与非线编EDL表相结合, 快速实现节目时间线的拆分与重组, 为未来在原节目结构基础上进行修改和重新剪辑创造条件。

为了实现以代码管理素材的目标, 素材代码一定要具备几个基本条件:

1) 方便创建, 在素材进行上载时即以一定规则产生。

2) 与成品节目代码要存在固有的关联关系。通过非线编辑过程实现素材代码与时间线EDL表的捆绑对应关系, 进而在最终形成故事板时间线的同时, 建立起节目成片EDL表与素材代码的关系, 将成片节目与每一条素材片段联系在一起。

3) 符合目前媒资内容四层编目的基本规范。由于素材的采集过程具有很高自由度, 在采集素材的同时应首先定义内容的层级, 素材代码也要与之匹配, 形成片段、场景、镜头不同层级的代码序列。

4) 以节目母体为核心, 建立素材代码纵向关系;以后期编目为手段, 建立素材条目之间的横向联系。素材代码与节目代码的匹配关系确定了本节目下所有素材的归属关系和关联关系, 我们称之为纵向关系。而通过后期编目和数据挖掘, 可以将不同节目的同一类素材建立联系, 我们称之为横向关系。

在以上这些条件中, 最重要的是通过素材代码, 我们可以建立同一节目中素材之间的纵向关系。以往媒资系统的处理形式, 大多以建立素材条目的横向关系为主。通过人工编目和计算机处理将库存资料进行归并、分类, 为检索查询提供数据条件。而纵向关系的建立, 为节目播出后的二次开发和利用提供了更科学化, 更高效率的手段。在传统编辑时代, 为了让节目适应不同需求, 我们会制作多个工作版进行保留。工作版往往与播出版的主要区别在于广告的插入、特技的使用、字幕的有无, 甚至是长短容量的不同。一个节目往往要使用磁带或硬盘保存多个版本, 占用大量存储空间。而如果能够在全流程网络中建立素材代码的工作模式, 在大规模素材库的支持下, 对于一个节目仅需要保存不同的EDL表文件, 通过EDL表文件和素材代码的关联关系, 在未来的任何时候都可以很容易的把关联素材汇集成为时间线故事板, 并且可以以此为基础对节目进行重编和再造。当节目资料真正走入市场成为可再造财富的内容资产的时候, 建立以EDL表和素材代码为核心的素材纵向关系表将会极大的提高节目的二次开发效率和数据集成度, 为开拓节目资源市场打开了一片新天地。

3 以代码方式管理节目资产为“下一代”媒资管理系统升级做好准备

随着计算机和网络技术的发展, 媒资系统必将从“管理资料”逐渐过渡到“保存历史”。媒资工作者将不会满足于我们“看到的”内容, 而会将目光最终放在那些“背后的”故事。媒资工作除了要对本地资料进行解析, 更要依赖庞大的计算机网络寻求资料之间的关系, 将碎片化的资料聚合在一起, 并通过集中分析找到资料所蕴藏的社会学价值, 毫无疑问, 这也将是下一代媒资管理系统的重大使命。依托编码学理论而产生的媒资代码管理理念, 将为下一代媒资系统的建立和发展奠定基础。代码管理方式所带来了信息聚合能力, 将传统意义上的节目资料转变为内容资产的构想, 向前推进了一大步。

参考文献

[1]林宗武, 等.新形势下广播电台内容产业发展中媒资系统的挑战.广播与电视技术, 2011 (5) .

代码实现 篇9

1 源码级代码部分自还原

计算机软件由可执行程序和相关数据构成。可执行程序作为计算机软件的最后作品,是一种CPU直接执行的机器指令序列。可执行程序不经过特别的处理,很容易被有心人通过种种逆向工程技术得到软件设计的核心思想或者核心代码,使软件产生安全隐患。

软件程序设计人员使用编程语言实现的软件的计算机表示称为源程序(或源码source code)。与源程序相比,通过可执行程序去还原软件的设计思想是“艰难的”。所谓的艰难,不是对逆向工程者而言。未加密过的可执行代码,逆向工程可以简单还原出软件的设计思想,甚至是仿真代码。故须对可执行程序进行处理,使逆向工程类操作变得艰难。

代码自还原的作用就是使程序在不运行时指令序列以加密的密文代码形式存在。而运行时,密文代码还原到明文代码状态,再执行明文代码。将可执行程序加密运行,其实有许多工具可以用。为什么不采用现成的工具,而要去独立的提出新的方法呢?原因有3方面:(1)流通的工具研究的人多,所以使用的风险大;(2)流通的工具加密的方法不能自己设定;(3)第三方工具很难做到无缝加密。

源码级代码部分自还原是将加密方案和还原方案是在软件设计时就设计于源代码中的,与软件可以做到无缝结合,加密的方法和还原的方法程序设计者可以自己决定。根据自己的要求和代码的重要程度设计加密强度。二是加密是在编译时完成,还原则在执行时完成。这就是所说的“源码级”的含义。

代码部分自还原技术对密文代码不是全部还原为明文代码再执行。为何不将密文代码全部还原了再执行呢?如将密文代码全部解开,则在将执行未执行时,密文代码已全部还原为明文代码,如CPU的控制权被夺,就有可能将明文代码还原出来,则软件思想泄露。因些,必须让密文代码执行到哪一个部分,就还原哪一个部分,执行完后即将明文代码销毁。这就是本文所提的“部份”的含义。

2 源码级代码部分自还原实现的难点

2.1 分块难

加密和解密操作是一对互逆的操作。由于要求代码在执行时要能“部份还原”,也即是执行到哪还原到哪,执行完哪销毁销毁到哪,因些,如何对代码进行分块就显得很重要。

2.2 加密和还原思路设计难点

要对代码整体进行加密和解密很容易,只需要对代码整体作为一个对象进行加密和解密操作就可以了。但要想边解密边执行,就不容易了。因为密文代码不是计算机指令。也就是说计算机不可以执行密文代码。那么,如何在密文指令中触发解密模块就成了第一个难题。

第二个难题是解密完后,解密模块要将计算机的控制权正确交给解开了的明文模块。明文模块执行完后又要将自己销毁。

3 源码级代码部分自还原实现的方法

通常高级程序设计语言都是支持函数,以C语言为例来阐明之。函数是作为一个整体进行运行的。函数的代码长度适中,故以函数作为一个基本单位进行加密和还原。即是说,就是执行到哪个函数,就将哪个函数还原成明文代码。执行完后,又将该函数的明文代码销毁。

可以将函数调用过程可以分为3个阶段:一是CPU控制权由主调函数转移到被调函数的入口地址;二是从入口地址起,开始执行被调函数的函数体代码;三是函数体代码执行完后将CPU控制权再次交回到主调函数中。

基于此,设计软件明文代码的加密过程如下:

3.1 对源码中待加密函数的改写

设软件中主调函数需要调用如下函数funcode1。且该函数需要进行加密。

3.2 软件整体加密的实现

要想对软件的函数进行加密,必须正确发界定出函数的入口地址funcode1start和函数的最后一条指令的位置funcode1end。在函数的入口地址之前插入8条连续空操作指令作为检测标志,在程序的最后一条指令之后插入4条连续空操作指令作为结束标志。这两个标志相当于一对括号,准确的将函数体界定起来。又由于是空操作指令,故不会对函数的运行产生逻辑上的负面影响。加密时只需要先查找加密的入口点的标志(8个连续的16进制值90h,它由空操作指令译码译成,记它为funcode1start,然后再查找4个连续的空操作指令,它就是待加密函数的结束位置,不妨记为funcode1end.然后对从funcode1start起funcode1end止的代码进行加密就可以了。

加密的方法是由程序设计者自己设计的。如果方法复杂,加密强度高,如果方法简单,则强度低。这可以根据自己的需要决定加密的强度。不失一般性,不妨设加密方法为最简单的单字节异或加密。

3.3 执行时部分自还原和自销毁的实现

由于在被加密函数的入口处填入了8条空操作指令,之后是对解密子程序的调用,所以,当主调函数调用加密函数时,经过8个空操作后,就会触发解密模块,然后解密子程序开始对调用它的被加密函数进行还原。一直还原到funcode1end为止。(funcode1end的位置标志为4个连续的空操作。这个标志是很容易检测到的。)

解密完成后,就将CPU控制权交回被还原函数。然后被还原函数执行。又因为在函数的返回指令前调用了部分加密函数,所以部分加密函数会将还原出来的明文代码销毁。然后再返回。

部分加密函数进行加密时也是查找调用它的函数的入口标志和结束标志。然后再进行加密。(即8个空操作和4个空操作)。

解密函数设计如下:

Delcode是明文代码销毁函数。其实现原理与解密函数decode是相似的。故不赘述。

4 技术展望

(1)源码级代码部分自还原策略无疑是一种软件保护可以考虑的思路。对程序设计人员来说是一种可行的办法。

(2)方法对多线程时函数的自还原是否有效需要进一步研究。

上一篇:小学美术课堂教学反思下一篇:优秀传统文化价值观