|
|
用户名:wpf2006 笔名:wpf2006 地区: 行业:其他 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
欢迎访问wpf2006的博客
Visual C++程序调试方法入门
概述 调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言。不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件。 这里我简要的根据自己的经验列出调试中比较常用的技巧,希望对大家有用。 本文约定,在选择菜单时,通过/表示分级菜单,例如File/Open表示顶级菜单File的子菜单Open。 设置 为了调试一个程序,首先必须使程序中包含调试信息。一般情况下,一 |
How to control the LED of your Pocket PC
By Stephane Sibue, January 11, 2001.
Print version
The LED is a part of Pocket PC specification. Generally it allows to indicate either that the battery is attached or that the Pocket PC is directly connected to the cradle. A Pocket PC can implement several LEDS, but usually there is only one. This article is translated from CodePPC.com.
Functions for handling LEDs can be found in 'coredll.dll' library, but they are not declared in the SDK (who knows why?). It is only the 'NLed.h' file that can make them appear, but the prototypes of the functions are not declared in this file.
The first thing to do is to include the 'NLed.h' file and to declare 2 functions for handling LEDs:
Initially, it is necessary to know how many LEDs are present, knowing that the number of the first one is 0. To carry out this checking, we will use the 'NLedGetDeviceInfo' function:
In case of a problem, this function returns 0. It also returns 0 if a Pocket PC does not have a LED to handle. In 99 cases out of a hundred this function returns 1.
We can now modify the state of our LED. According to the contents of the 'NLed.h' file, the LED can appear in 3 states: off, on, and blink (stop, functioning, and blinking). Each state corresponds to a value of the 'OffOnBlink' parameter of the 'NLED_SETTINGS_INFO' structure. This structure also allows to implement other effects but this exceeds the topic of this article, we will return to this implementation later. Thus we will create a function, which takes the desired state of our LED as a parameter, which can be 0 for idle (off), 1 for fixed functioning (on), and 2 for the effect of blinking (blink):
Thus, to light up the LED n°1, it is enough to write:
to make it blink:
and finally to estinguish it:
如何解决模拟器加载问题(ppc2003+winxp sp2+evc4)
| 1. | Click Start, click Run, type sysdm.cpl, and then click OK. |
| 2. | In the System Properties dialog box, click the Advanced tab. |
| 3. | Under Start and Recovery, click Settings. |
| 4. | In the Startup and Recovery dialog box, click Edit. |
| 5. | Disable PAE mode by removing the /pae option if it exists. |
| 6. | If you are using Windows XP SP2, remove the /noexecute option if it exists, and then add the /execute option. |
| 7. | On the File menu, click Save. |
| 8. | To exit Notepad, click Exit on the File menu. |
| 9. | To close System Properties, click OK two times. |
| 10. | Restart your computer. |
马云创业点评语录(一)
在VC中透明浮动按键的实现
Symbian的体系架构小节
CWinApp类,它定义了应用程序的属性,这个类也创建文档。本应用类的基类就是
CAknApplication。
Document是做为程序用来存储数据用的,一个应用程序必须有一个Document文档
类的实例,可能是用来被加载AppUi的唯一要求,这个类的基类是CAknDocument.
AppUi,负责处理与应用有关的事件,比如说是options菜单选项、文件的打开和
关闭等。
注意它将图形绘制和基于屏幕的交互操作委派给自己所拥有的Views,也负责这些
views之间的切换。AppUi的基类是CAknAppUi或者CAknViewAppUi.
比较复杂点的是View,它主要是负责显示屏幕上那些可以与用户交互的数据,并
且把用户的操作反馈给AppUi,这个正如上面所说的,是处理与应用有关的事件。
view可以继承自CCoeControl或CAknDialog或者是CAknView,看出来没有,三种基
本结构view都是唱主角的。这个很重要,反正显示的任务就交给它了,甭管是传
统、对话框还是视图结构。
应用程序外观,它可以分为三种体系结构:传统的symbianOS控制体系结构、基于
对话框的体系结构、视图体系结构。运用什么样的界面取决于程序和界面布局的
需要。只是不管你使用哪种,都是从一个基类继承而来的,就好象是CView一样。
SymbianOS应用程序是在CCoeControl类的基础上派生出我们自己的view controls
,这些都存放在应用程序的control stack中,也就是我们应用程序的视图。这些
controls会根据应用程序的需要来创建释放或显示隐藏,以产生相应的操作。
如果主体应用是对话框,那我们更应该使用这样的体系结构,使用dialogs的好处
是我们光可以靠改变resource文件来修改内容和布局,而不需要重新编译那c++代
码。
使用view的应用程序每次只能有一个活动的view,当另一个view要激活时,当前
的view就要被释放。当一个view被释放后,所以的菜单,对话框以及包含的应用
都将被关闭。每个view都被当作一个应用UI对待,它必须提供一个Id() 函数以便
为系统所标识,它也要重载DoActivateL(), DoDeactivate
(),HandleForegroundEventL(),HandlCommandL(),HandleStatusPaneSizeChange
()函数以处理各种事件。
浅析COM的思想及原理
浅析COM的思想及原理
COM--Component Object Model,即组件对象模型,它是微软提出的一套开发软件的方法与规范。它也代表了一种软件开发思想,那就是面向组件编程的思想。
一、COM编程思想--面向组件编程思想(COP)
众所周知,由C到C++,实现了由面向过程编程到面向对象编程的过渡。而COM的出现,又引出了面向组件的思想。其实,面向组件思想是面向对象思想的一种延伸和扩展。因此,就让我们先来回忆一下面向对象的思想吧。
面向对象思想是将所有的操作以及所操作的对象都进行归类(由class实现),而它的目标是要尽量提高代码的可重用性(这也是面向对象相比面向过程最大的优点之一)。比如,有两个程序A和B都需要对class C的对象进行操作,那么class C的代码就可以重用了(即A和B都可以使用class C的代码)。但是,对于这一点,面向对象做得并不够好。还是举刚才的例子,程序A和B都要对class C的对象进行操作,那么,程序A和B的编程人员都必须将class C的代码拷贝过来,然后重新编译一次,这将是多么麻烦的事!况且,如果class C的代码没有公开,那这种重用就根本不可能实现了(除非程序A和B的编程人员和class C的编程人员是同一个人或者团队,但这样局限性就相当大了)。
由于面向对象的这些局限性,很多程序员就会想,如果我们编程需要重用别人的成果时,不需要重新编译别人的代码那就好了。换句话说,我们要达到的目标是,直接重用别人的成果而不是重用别人的代码。这样说也许很抽象,举个例子大家就会比较明白。比如将class C的代码编译生成一个dll,那么当其他程序员想要重用class C时,就只需要在自己的程序中加载这个dll而不需要重新编译class C的代码了(这也就是组件必须要能动态链接的原因)。正是这种思路引出了面向组件的编程思想。
下面,我就简单介绍一下面向组件的思想。在以前,应用程序总是被编写成一个单独的模块,就是说一个应用程序就是一个单独的二进制文件。后来在引入了面向组件的编程思想后,原本单个的应用程序文件被分隔成多个模块来分别编写,每个模块具有一定的独立性,也应具有一定的与本应用程序的无关性。一般来说,这种模块的划分是以功能作为标准的。比如,一个网上办公管理系统,从功能上说它需要包含网络通信、数据库操作等部分,我们就可以将网络通信和数据库操作的部分分别提出来做成两个独立的模块。那么,原本单个的应用程序就分隔成了三个模块:主控模块、通信模块和数据库模块。而这里的通信模块和数据库模块还可以做得使其具有一定的通用性,那么其他的应用程序也就可以利用这些模块了。这样做的好处有很多,比如当对软件进行升级的时候,只要对需要改动的模块进行升级,然后用重新生成的一个新模块来替换掉原来的旧模块(但必须保持接口不变),而其他的模块可以完全保持不变。这样,软件升级就变得更加方便,工作量也更小。
说了这么多,总结一下:面向组件编程思想,归结起来就是四个字:模块分隔。这里的“分隔”有两层含义,第一就是要“分”,也就是要将应用程序(尤其是大型软件)按功能划分成多个模块;第二就是要“隔”,也就是每一个模块要有相当程度的独立性,要尽量与其他模块“隔”开。这四个字是面向组件编程思想的精华所在,也是COM的精华所在!理解了这四个字,也就真正理解了面向组件编程的思想。(这里说一点题外话,COM其实是一套规范或者说一套标准,但是在我看来,COM的核心还在于它的思想,也就是面向组件编程思想。标准谁都能定,但是思想只有一个!)
二、COM的优点
COM的优点也就是面向组件编程思想的优点。而面向组件编程思想有很多的优点,上面所说的便于软件升级只是其中之一。对于它的优点,我总结了一下,有下面几条:
1、便于重用,使软件开发更快捷
2、便于软件升级
3、便于软件开发的分工协作
4、便于用户定制自己的应用
以上几点,第一和第二点都不用再多说了,前面讲面向组件编程思想的部分里面已经充分展示出了这两点优点。在这里我解释一下第三和第四点。
如今的很多大型软件,都不可能由某一个人单独开发,甚至不会由某一个公司去单独开发。这是因为现在的很多大型软件,综合性太强,涉及的面也太广。而一个人的精力是有限的,不可能学会这么多方面的知识,也不可能掌握到这么多方面的编程技术,即使有可能,这样做的效率也是很低下的。所以,通常的情况是分工协作。仍以前面提到的网上办公管理系统为例,这个系统分为了三个模块:主控模块、通信模块和数据库模块。由于这三个模块具有相当的独立性,那么就可以将现有的所有开发人员分为三组,每一组负责一个模块。而这三组之间,只需要商量好相互间的接口就可以了。这样,对于每一个开发人员来说,就不需要掌握所有的编程技术,甚至不需要了解其他模块的具体实现,而软件仍然能有效的开发成功。这就是所谓的便于软件开发的分工协作了。
除此之外,如果一个大型的软件希望允许用户在一定程度上定制自己的应用,那么COM也是最好的选择。比方说一个软件由两个模块组成,模块A和模块B,现在软件的开发商希望给予用户一定的灵活性,希望可以允许用户自己定制模块B来实现自己特定的应用,那么就只需要公开模块B的所有接口;而用户自己编程实现模块B时也只需要实现了所有的这些接口就行了。当然,这里面还有很多问题,比如COM组件的注册,这涉及到COM标准的一些细节,在这里不作讨论。
三、COM中的几个重要概念
1、组件:
其实只要你仔细阅读了前面的部分,组件的概念应该已经很清楚了。这里所说的组件,就是前面反复在讨论的所谓“模块”。现在我只想强调一下组件需要满足的一些条件。首先是封装性,组件必须向外部隐藏其内部的实现细节,使从外部所能看到的只是接口。然后是组件必须能动态链接到一起,而不必像面向对象中的class一样必须重新编译。
2、接口:
由于组件向外部隐藏了其内部的细节,因此客户要使用组件时就必须通过一定的机制,也就是说要通过一定的方法来实现客户与组件之间的通信,这就需要接口。所谓接口就是组件对外暴露的、向外部客户提供服务的“连接点”。外部的客户见不到组件内部的细节,它所能看到的只是接口,客户也是通过接口来获取组件提供的服务。这有点像OSI网络协议分层模型,每一层就像一个组件,它内部的实现细节对于其他层是不可见的;而每一层通过“服务接入点”向其上层提供服务,这就像这里所说的接口。一般来说,接口总是固定的,也是公开的。组件的开发人员要实现这些接口,而客户则通过接口获得服务。正是接口的这种固定和公开,才使得组件和客户能够在不了解对方的情况下达成一致。
3、客户:
这里所说的客户不是指使用软件的用户,而是指要使用某一个组件的程序或模块。也就是说,这里的客户是相对组件来说的。
四、COM的实现原理与雏形模拟
COM编程的一个重要特点就是要模块化,说得具体一些,就是要将客户和组件分隔开来,而客户和组件之间又是通过接口来通信的。下面,我就介绍一下COM是怎样将客户与组件分隔开来,又是怎样利用接口来实现客户与组件间的通信的。
首先我要讲讲接口。COM中的接口实际上是一个函数地址表,当组件实现了这个接口后,这个函数地址表中就填满了组件所实现的那些接口函数的地址。而客户也就是通过这个函数地址表获得组件中那些接口函数的指针,从而获得组件所提供的服务的。从某种意义上说,我们可以把接口理解为c++中的虚拟基类;或者说,在c++中可以用虚拟基类来实现接口!这是因为COM中规定的接口的存储结构,和c++中的虚拟基类在内存中的结构是一致的。其存储结构如下图:
虚函数表
vtbl指针------>Fun1()指针-------->
Fun2()指针-------->
Fun3()指针-------->
…………
Vtbl指针指向一个虚函数表,而这个虚函数表的表项就是指向这些虚函数的指针。
接口有了,那么组件又是怎样实现接口的呢?实际上,如果用虚拟基类来实现接口,那么组件就是对这个虚拟基类的继承。大家知道,当某个类继承于一个虚拟基类的时候,它就要实现这个虚拟基类里声明的虚函数,这就正好与组件实现接口这一点相吻合。举一个例子来说明,有一个接口InterfaceA,组件ComponentB要实现这个接口,那么就可以这样用c++语言来描述:
//接口:
class InterfaceA
{
virtual void Fun1()=0;
virtual void Fun2()=0;
};
//实现了接口InterfaceA的组件:
class ComponentB: public InterfaceA
{
virtual void Fun1()
{
printf("Fun1\n");
}
virtual void Fun2()
{
printf("Fun2\n");
}
};
而客户只需要得到一个指向ComponentB实体的InterfaceA指针就可以获得ComponentB组件的服务了:
//使用了组件ComponentB的客户:
……
ComponentB CB;
InterfaceA *pIA=&CB; //获得指向ComponentB实体的InterfaceA指针,以下客户就可以只通过接口来获取组件的服务
pIA->Fun1();
pIA->Fun2();
……
但是我们注意到,这样做组件ComponentB和客户还是没有被完全分隔开。因为在客户代码里需要创建ComponentB实体,这对于只能看到接口而对组件一无所知的客户来说,是不可以接受的(比如客户不会知道组件的类名叫ComponentB)。解决这个问题的方法是在实现组件的动态链接文件(比如dll文件)里创建组件的实体,而不是在客户代码里创建组件实体。通常组件都是以dll的形式出现的,而在实现组件的dll里都会实现一个叫CreateInstance的函数,这个函数可以被外部的客户调用。它返回一个接口的指针,当客户调用这个函数后就能够获得指向组件实体的接口指针了。它的实现也很简单:
//在实现组件ComponentB的dll里:
InterfaceA *CreateInstance()
{
ComponentB CB;
InterfaceA *pIA=&CB;
return pIA;
}
当然,真正的CreateInstance函数没有这么简单,我上面的代码只是一个简单的模拟。有个CreateInstance函数之后,客户代码就变成了:
//使用了组件ComponentB的客户:
……
InterfaceA *pIA=CreateInstance(); //获得指向ComponentB实体的InterfaceA指针,以下客户就可以只通过接口来获取组件的服务
pIA->Fun1();
pIA->Fun2();
……
这样,组件和客户就完全被分隔开了,而连接它们的只有接口以及一个CreateInstance的函数。
以上就是COM的基本原理了。当然,我前面也说了,COM其实是一套规范,它定义了很多标准,比如COM规定每个接口都必须继承于一个叫IUnknown的接口。我这里基本上没有提及它的这些标准,只是希望能通过对它进行一个简单的模拟来说清楚它的实现原理。下面就给出我模拟COM机制实现的一套COM的雏形,希望能对大家理解COM有帮助。
1、实现了组件ComponentB的ComponentDll.dll:
//Interface.h
//接口
class InterfaceA
{
public:
virtual void Fun1()=0;
virtual void Fun2()=0;
};
//Component.h
//组件(实现了接口InterfaceA)
class ComponentB: public InterfaceA
{
public:
virtual void Fun1()
{
printf("Fun1\n");
}
virtual void Fun2()
{
printf("Fun2\n");
}
};
//ComponentDll.cpp
//CreateInstance函数
ComponentB instance;
extern "C" _declspec(dllexport) InterfaceA *CreateInstance()
{
InterfaceA *pIA=&instance;
return pIA;
}
2、客户Client.exe:
//Client.cpp
#include "Interface.h"
#pragma comment(lib,"ComponentDll")
int main(int argc, char* argv[])
{
InterfaceA *pIA=0;
pIA=CreateInstance();
if(pIA!=0)
pIA->Fun1();
return 0;
}
MFC消息映射
在MFC类实现中,采用消息映射实现对消息的响应,从而改变了在SDK中的循环结构,使得消息的流转更加隐蔽。
在SDK中有分三部分构成:
WNDCLASS wnd;
wnd.lpfnWndProc = WndProc ; // 首先将回调函数设置好
SDK循环结构,进行消息循环
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DisptachMessage(&msg);
}
而在另一处有回调函数的实现:
LPRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE: ... break;
case WM_PAINT: ... break;
case WM_LBUTTONDOWN: ... break;
case WM_LBUTTONUP:... break;
case WM_MOUSEMOVE:... break;
case WM_CHAR: ... break;
case WM_TIMER: ... break;
case WM_CLOSE: ... break;
case WM_DESTROYS: ... break;
case WM_QUIT: ... break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_XXX: break;
default: break;
}
break;
default: break;
}
DefWindowProc(hWnd,msg,wParam,lParam);
}
消息映射中为:
在MFC类定义结构中申明一个语句:
DECLARE_MESSAGE_MAP()
然后在全局空间实现中出现使用如下语句进行消息映射:
BEGIN_DECLARE
ON_WM_LBUTTONDOWM()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_PAINT()
ON_COMMAND(ID,lpFunc)
END_DECALRE
在类成员函数的实现中,将上面的消息映射函数进行实现。常用命令有固定的消息名称:
ON_WM_LBUTTONDOWN()映射函数为ONLBUTTONDOWN()函数,ON_WM_LBUTTONUP映射函数为LBUTTONUP()函数,ON_WM_MOUSEMOVE()映射函数为ONMOUSEMOVE()函数,ON_WM_PAINT()映射函数为ONPAINT()函数,而ON_COMMAND中的映射函数即为lpFunc函数。
情况下,消息映射声明不通过手工进行修改,而是在ClassWizard中进行修改,这样修改,可以避免因为手工修改时遗漏某个部分或者是输入时出现的一些小bug。
MFC的消息流转为从当前类APP流转到CWndApp,再流转到CWndThread类,在流转到CCmdTarget类,当CCmdTarget类中消息还不符合时,在流转到CWndThread中进行消息匹配。
虽然MFC消息比较难以理解,以及消息相对比较复杂,但是MFC消息函数的出现,使得对每个消息的实现变得很独立,比SDK中一连串的消息判断要清晰明白的多。
深入浅出中将MFC中消息映射设置成这么一个结构:
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
struct AFX_MSGMAP_ENTRY // MFC 4.0 format
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
typedef void (CCmdTarget::*AFX_PMSG)(void);
#define DECLARE_MESSAGE_MAP() \
static AFX_MSGMAP_ENTRY _messageEntries[]; \
static AFX_MSGMAP messageMap; \
virtual AFX_MSGMAP* GetMessageMap() const;
其中的AFX_MSGMAP_ENTRY 又是另一个数据结构:
其中的AFX_PMSG 定义为函数指针:
然后我们定义一个宏:
#define DECLARE_MESSAGE_MAP() \
static AFX_MSGMAP_ENTRY _messageEntries[]; \
static AFX_MSGMAP messageMap; \
这个数据结构的填充有三个宏来实现:
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_MSGMAP theClass::messageMap = \
{ &(baseClass::messageMap), \
(AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) }; \
AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{
#define ON_COMMAND(id, memberFxn) \
{ WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },
#define END_MESSAGE_MAP() \
{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
rtual AFX_MSGMAP* GetMessageMap() const;
};
常用linux命令
蓝屏故障
NDIS中间层驱动程序
NAT在NDIS中间层驱动中的实现
c++友元函数示例
111
TCHAR *info = new TCHAR[1024];
wcscpy(info,str.GetBuffer(str.GetLength()));
在evc中打开网页程序
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = TEXT("http://www.163.com");
ShExecInfo.lpParameters =NULL;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&ShExecInfo);
DES算法
2、DES算法
一、DES算法
美国国家标准局1973年开始研究除国防部外的其它部门的计算机系统的数据加密标准,于1973年5月15日和1974年8月27日先后两次向公众发出了征求加密算法的公告。加密算法要达到的目的(通常称为DES 密码算法要求)主要为以下四点:
☆提供高质量的数据保护,防止数据未经授权的泄露和未被察觉的修改; | |
☆具有相当高的复杂性,使得破译的开销超过可能获得的利益,同时又要便于理解和掌握; | |
☆DES密码体制的安全性应该不依赖于算法的保密,其安全性仅以加密密钥的保密为基础; | |
☆实现经济,运行有效,并且适用于多种完全不同的应用。 |
1977年1月,美国政府颁布:采纳IBM公司设计的方案作为非机密数据的正式数据加密标准(DES棗Data Encryption Standard)。
目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。
DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。
通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。
DES算法详述
DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位,整个算法的主流程图如下:
其功能是把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,其置换规则见下表:
58,50,12,34,26,18,10,2,60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,
57,49,41,33,25,17, 9,1,59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7,
即将输入的第58位换到第一位,第50位换到第2位,...,依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分,L0是输出的左32位,R0 是右32位,例:设置换前的输入值为D1D2D3......D64,则经过初始置换后的结果为:L0=D58D50...D8;R0=D57D49...D7。
经过16次迭代运算后。得到L16、R16,将此作为输入,进行逆置换,即得到密文输出。逆置换正好是初始置的逆运算,例如,第1位经过初始置换后,处于第40位,而通过逆置换,又将第40位换回到第1位,其逆置换规则如下表所示:
40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58 26,33,1,41, 9,49,17,57,25,
放大换位表
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10,11,
12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21,
22,23,24,25,24,25,26,27,28,29,28,29,30,31,32, 1,
单纯换位表
16,7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10,
2,8,24,14,32,27, 3, 9,19,13,30, 6,22,11, 4,25,
在f(Ri,Ki)算法描述图中,S1,S2...S8为选择函数,其功能是把6bit数据变为4bit数据。下面给出选择函数Si(i=1,2......8)的功能表:
选择函数Si
S1:
14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13,
S2:
15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9,
S3:
10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12,
S4:
7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14,
S5:
2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3,
S6:
12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,
S7:
4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12,
S8:
13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,
1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,
7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,
2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11,
在此以S1为例说明其功能,我们可以看到:在S1中,共有4行数据,命名为0,1、2、3行;每行有16列,命名为0、1、2、3,......,14、15列。
现设输入为: D=D1D2D3D4D5D6
令:列=D2D3D4D5
行=D1D6
然后在S1表中查得对应的数,以4位二进制表示,此即为选择函数S1的输出。下面给出子密钥Ki(48bit)的生成算法
从子密钥Ki的生成算法描述图中我们可以看到:初始Key值为64位,但DES算法规定,其中第8、16、......64位是奇偶校验位,不参与DES运算。故Key 实际可用位数便只有56位。即:经过缩小选择换位表1的变换后,Key 的位数由64 位变成了56位,此56位分为C0、D0两部分,各28位,然后分别进行第1次循环左移,得到C1、D1,将C1(28位)、D1(28位)合并得到56位,再经过缩小选择换位2,从而便得到了密钥K0(48位)。依此类推,便可得到K1、K2、......、K15,不过需要注意的是,16次循环左移对应的左移位数要依据下述规则进行:
循环左移位数
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
以上介绍了DES算法的加密过程。DES算法的解密过程是一样的,区别仅仅在于第一次迭代时用子密钥K15,第二次K14、......,最后一次用K0,算法本身并没有任何变化。
二、DES算法理论图解
DES的算法是对称的,既可用于加密又可用于解密。下图是它的算法粗框图。其具体运算过程有如下七步。
三、DES算法的应用误区
DES算法具有极高安全性,到目前为止,除了用穷举搜索法对DES算法进行攻击外,还没有发现更有效的办法。而56位长的密钥的穷举空间为256,这意味着如果一台计算机的速度是每一秒种检测一百万个密钥,则它搜索完全部密钥就需要将近2285年的时间,可见,这是难以实现的,当然,随着科学技术的发展,当出现超高速计算机后,我们可考虑把DES密钥的长度再增长一些,以此来达到更高的保密程度。
由上述DES算法介绍我们可以看到:DES算法中只用到64位密钥中的其中56位,而第8、16、24、......64位8个位并未参与DES运算,这一点,向我们提出了一个应用上的要求,即DES的安全性是基于除了8,16,24,......64位外的其余56位的组合变化256才得以保证的。因此,在实际应用中,我们应避开使用第8,16,24,......64位作为有效数据位,而使用其它的56位作为有效数据位,才能保证DES算法安全可靠地发挥作用。如果不了解这一点,把密钥Key的8,16,24,..... .64位作为有效数据使用,将不能保证DES加密数据的安全性,对运用DES来达到保密作用的系统产生数据被破译的危险,这正是DES算法在应用上的误区,留下了被人攻击、被人破译的极大隐患。
取得设备信息
如何获得deviceid
, arrOutBuff[i]);
;
WindowsCE下Unicode和Ansi字符间互相转换的例子
,TEXT("信息"
);
;
;
,sendcount);
;
;
全程键盘钩子的一种简单实现

)
; //加载DLL
;
;