写个stl程序

明天就要acm课考试了,可是一学期几乎没去上过课(感觉有点对不住lcy老师啊。、、),肿么办。。没办法,只能临时抱抱佛脚,于是拿出了尘封已久的《算法竞赛入门经典》,话说当初刚接触acm的时候真心挺佩服刘汝佳的,大神啊,大二是就是世界第四了。可一年多过去后发现自己对这个没多少兴趣了。。

闲话不多说,切入正题,翻书的时候看到这样一道小题:

移动小球

你有一些小球,从左到右依次编号为1,2,3,……,n。指令A x y表示把小球x移动到小球y左边,B x y表示把小球x移动到小球y右边。指令保证合法(x不等于y)。输入小球个数n和指令条数m及m条指令,从左至右输出最后的序列。n可高达500000,m可高达100000.

样例输入:

6 2

A 1 4

B 3 5

样例输出:

2 1 4 5 3 6

 

这道题时间规模很大,因此书上采用数组模拟链表的方式实现。详见书。。

这里给出我的一个解法,用stl的list容器。

代码如下:

#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
int main()
{
int n,m,x,y;
char type[3];
list<int> ball;
list<int>::iterator it;
while(scanf(“%d%d”,&n,&m)!=EOF)
{
for(int i=1;i<=n+1;i++)
ball.push_back(i);
for(int j=1;j<=m;j++)
{
scanf(“%s%d%d”,type,&x,&y);
if(type[0]==’A')
{
it=find(ball.begin(),ball.end(),y);
ball.remove(x);
ball.insert(it,x);
}
else
{
it=find(ball.begin(),ball.end(),y);
ball.remove(x);
ball.insert(++it,x);
}
}
ball.pop_back();
for(it=ball.begin();it!=ball.end();it++)
{
cout<<*it<<’ ‘;
}
cout<<endl;
ball.clear();
}
return 0;
}

这里有一点值得注意,因为list的迭代器不能实现+1等随机遍历(list实质是链表),所以只好用++操作替代,因而可能造成迭代器越界(find()返回ball.end()时)。所以这里我多创建一个元素,在输出前删除。由于使用while(scanf()!=EOF),所以每组数据结束后都要清空ball。

初识Greasemonkey

1. 每个用户脚本后缀名必须是.user.js,例如:helloworld.user.js,其内容:

// ==UserScript==
// @name          Hello World
// @namespace     http://diveintogreasemonkey.org/download/
// @description   example script to alert "Hello world!" on every page
// @include       *
// @exclude       http://diveintogreasemonkey.org/*
// @exclude       http://www.diveintogreasemonkey.org/*
// ==/UserScript==

alert('Hello world!');

2. 分析一下用户脚本元数据

用//==UserScript==与//==/UserScript==用于标识脚本的起始,其中包含6行元数据描述。这段注释可以放在脚本的任何位置,但是一般来说是放在脚本的顶部。

//@name Hello World

这是定义你脚本的名子,它将显示在安装对话框中,以及在“Manage User Scripts”对话框。这个名子应该简短并且能够表达脚本的含义。这个元数据可以被省略,如果省略,默认是脚本文件名减去.user.js扩展名。

//@namespace http://diveintogreasemonkey.org/download/

这个元数据一般是URL,用于区分具有相同名子的脚本,如果你有一个域名,你可以使用域名,否则你可以用tag:URI。这个元数据也可以被省略,如果省略,默认使用下载脚本的域名。

//@description  example script to alert “Hello world!” on every page

这个元数据用于定义可读的描述信息,最好不要超过两句。这个信息将会显示在安装对话框和“Manage User Scripts”对话框。当然,这个元数据可以被省略,默认值是空字符串。

// @include       * // @exclude       http://diveintogreasemonkey.org/*
// @exclude       http://www.diveintogreasemonkey.org/*

@include与@exclude用于定义脚本可以用于哪些站点,*是通配符。上面的例子就是说,脚本可以用在所有站点,除了http://diveintogreasemonkey.org/*与http://www.diveintogreasemonkey.org/*。这两个元数据都可以被省略,如果这两个元数据没有被定义,那么脚本将被用于所有站点。

3. 编写用户脚本

alert('Hello world!');

当然,以上就是脚本的真正逻辑。其实为了避免你的脚本程序与要注入的页面中原有的脚本冲突,Greasemonkey在幕后帮你做了很多事情,他把你的代 码包装成匿名函数,虽然你可以忽略这些,但是这里却有个潜在的问题,你所定义的变量或函数不可以被其它的脚本调用。举例来说:

function helloworld() {
    alert('Hello world!');
}

window.setTimeout("helloworld()", 60);

以上的脚本一定会报错(”helloworld is not defined” ),这是因为当一个用户脚本执行完一次后,变量或函数便失效,这就意味着当你期待使用window.setTimeout函数调用你自己的函数时,便会报 错。解决的办法是你可以将你的函数定义成window对象的属性,例如:

window.helloworld = function() {
    alert('Hello world!');
}

window.setTimeout("helloworld()", 60);

然后,这并不是一个最好的解决方案,因为很有可能你要注入脚本的页面中也定义了相同名称的window对象属性,这样就会引起冲突,最好的方案是你定义一个匿名函数,并将其作为参数传递给window.setTimeout。例如:

window.setTimeout(function() { alert('Hello world!') }, 60);

shell编程笔记

大一上学期的一些笔记:

1.linux系统地服务启动的借口在etc/init.d/目录下
2.启动加载程序的项目/etc/rc.d/rc.local里的数据
3.命令、参数间的多个空白都会被忽略掉
4.sh shell.sh
sh的参数:
-n
-x
5.开头必须:
#!/bin/bash
6.exit 0表示结束script并会传一个0给系统
7.交互式脚本常用命令:read
read -p “提示字符串” 变量名
8.date –date=string    列出相应日期。
date +%Y%m%d        按指定格式显示
如:
date –date=”2 days ago” +%Y%m%d
9.declare    定义变量类型
数值计算:$((计算式))
10.script的执行方式区别:
直接命令执行(绝对路径/相对路径/$PATH内),或是bash或sh来执行,script都会使用一个新的bash来执行(即子进程)。所以创建的变量在父进程内无效
而用.或source执行,则是在父进程内执行,创建的变量有效
11.test        测试
文件类型判断:
-e    是否存在
-f    是否存在且为文件
-d    是否存在且为目录
文件权限检测:
-r
-w
-x
-u
-g
-k    是否有Sticky bit属性
-s    是否存在且为“非空白文件”
两个文件比较:
test file1 -nt file2
-nt    (newer than)判断file1是否比file2新
-ot    (old than)判断file1是否比file2旧
-ef    判断file1和file2是否为同一文件,用于hard link的判断上。主要意义在于判定两个文件是否均指向同一个inode
两个整数之间的判定:
test n1 -eq n2
-eq    两值相等
-ne    两值不等
-gt    n1大于n2
-lt    n1小于n2
-ge    n1大于等于n2
-le    n1小于等于n2
判字符串;
test -z string    判字符串是否为0,若string为空字符串,则为true
test string    string是否非零,非空为true
test str1=str2    相等传true
test str1!=str2    不等传true
多重判定(重要):
-a    同时成立传true。如test -r file -a -x file,file同时具有r与x权限时回传true
-o    任何一个状态成立回传true
!    反向状态,

win32汇编笔记

大一上学期的一些笔记:

1.一个应用程序可能有多个窗口。
2.一个应用程序实例(进程)只有一个消息队列。
3.每个窗口都有自己的窗口过程(回调函数)。
4.操作系统有自己的一个系统消息队列。
5.消息循环的各个api在user32.dll中。
6.PostMessage将消息放入指定程序的消息队列中。
SendMessage将消息直接传给对应的窗口过程(callback函数)。
PostQuitMessage将WM_QUIT消息传给消息循环。
8.RegisterClass的参数为指向结构体WndClass的指针。
9.WndClass的lpfnWndProc参数放窗口过程的地址。
10.窗口过程(callback函数)用于处理传入的消息。
11.有些实时性很强的消息如SetCursor等不通过Dispatch函数的派发,而是直接由系统调用窗口过程。
一个win32窗口程序的源程序模板:
_WinMain函数:
获取窗口句柄GetModuleHandle
注册类RegisterClassEx
建立并显示窗口CreateWindowEx  ShowWindowEx  UpdateWindowEx
消息循环GetMessage(进入user32.dll由系统取消息)  (TanslateMessage等(非必要)) DispatchMessage(进入user32.dll由系统调用窗口过程)
_ProcWinMain函数:
窗口过程,用于接收和处理消息
主函数:
call _WinMain
invoke ExitProcess NULL

12.RtlZeroMemory,@stWndClass,sizeof @stWndClass用于将结构体变量@stWndClass各成员置0.局部变量初始化十分重要,要牢记。
13.WNDCLASSEX结构体
cbsize
style        CS_VREDRAW CS_HREDRAW CS_KEYCVTWINDOW CS_DBLCLKS等等
lpfnwndproc
cbclsextra    保留
cbwndextra    保留
hinstance
hicon
hcursor        光标句柄,指定光标形状
hbrbackground    BRUSH句柄(也可以使用颜色值,如:COLOR_BACKGROUND COLOR_HIGHLIGHT COLOR_MENU COLOR_WINDOW     注:使用颜色值时后面+1)
lpszmenuname
lpszclassname
hiconsm        小图标

14.获取BRUSH的句柄:用函数GetStockObject(如:invoke getstockobject,WHITE_BRUSH)
15.CreateWindowEx,dwExStyle,lpClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hwWndParent,hMenu,hInstance,lpParam
hMenu    菜单句柄,当dwStyle为WS_CHILD时,表示子窗口ID,子窗口没有菜单
16.WNDCLASSEX中的style(默认风格)中的值开头为CS_(CLASS STYLE),CreateWindowEx中的dwStyle的值开头为WS_(WINDOW STYLE)
17.dwExStyle的值也要牢记。。
18.hinstance是模块句柄,也就是一个应用程序实例的句柄。一个应用程序实例可能会有多个窗口。另外,一个窗口也有句柄。两者不可混淆!!
19.createwindowex返回建立的窗口的句柄。
20.类是一个应用程序实例的,所以WNDCLASSEX中才有个参数hInstance,用于取得模块句柄。
21.Button和Edit等都是子窗口。
22.程序开始时,系统会发送WM_CREATE消息到模块的消息队列中,消息循环开始后就会从消息队列读取该消息并传到窗口过程(本人猜测)

关于消息循环:
.while TURE
invoke GetMessage,addr @stmsg,NULL,0,0    (从消息队列取消息)
.break .if eax==0
invoke TranslateMessage,addr @stmsg(非必要,将一些键盘扫描码消息转为键盘ascii码消息)
invoke DispatchMessage,addr @stmsg(将消息派发给相应窗口过程)
.endw
MSG结构体:
hwnd    消息要发向的窗口句柄(注意:不是模块句柄)
message
wParam
lParam
time
pt    POINT结构体,表示消息放入消息队列时的鼠标坐标
23.createwindowex时用了某个类也就用了该类中确定的窗口过程
24.一个应用程序实例(模块)只有一个消息队列,一个消息循环,但可能有多个窗口,因此也就有可能有多个窗口过程。
25.GetMessage原型:
GetMessage,lpMsg,hWnd,wMsgfiltermin,wMsgfiltermax
lpMsg:指向一个MSG变量的指针
hWnd:表示要获取发向哪个窗口的消息。NULL表示获取本应用程序的所有消息。
后两个参数:指定获取特定编号范围的消息。0表示获取所有编号的消息。
26.WM_QUIT消息的返回值为0
27.当有按键按下或放开时触发消息:WM_KEYDOWN或WM_KEYUP或WM_SYSKEYDOWN或WM_SYSKEYUP
但其值为扫描码,TranslateMessage将其转化成WM_CHAR或WM_SYSCHAR消息。
28.遇到非键盘消息,TranslateMessage不做处理。
29.windows是抢占式多任务系统,任务间每20ms切换一次。
30.关于窗口过程:
WindowProc proc hwnd,uMsg,wParam,lParam
hwnd    要操作的窗口句柄
一个窗口过程可能会为基于同一个类的多个窗口服务,所以要指定窗口句柄。
这四个参数与MSG结构的前四个参数相同。
一条消息(MSG类型变量)中的hwnd指定了要操作哪个窗口。
不同消息后两个参数值代表的意义不同。
callback函数的返回值:
处理不同消息,返回不同值。
如:处理WM_CREATE消息时返回0表示执行成功,返回-1表示执行失败。
createwindowex时向窗口过程收到的消息:
WM_GETMINMAXINFO    获取窗口大小以便初始化
WM_NCCREATE        非客户区建立
WM_NCCALCSIZE        计算客户区大小
WM_CREATE        窗口建立
updatewindow时窗口过程收到的消息只有一条:WM_PAINT
31.单击窗口右上角关闭按钮触发WM_CLOSE消息
if uMsg == WM_CLOSE
invoke DestroyWindow…………
invoke PostQuitMessage,NULL(该函数会发送WM_QUIT消息给消息循环)  这个函数的参数就是WM_QUIT消息的MSG结构的wParam
32.结束程序时务必在摧毁窗口后用postquitmessage函数向消息循环发送WM_QUIT消息以退出消息循环。这一点很重要。
33.PostMessage,hWnd,Msg,wParam,lParam
SendMessage,hWnd,Msg,wParam,lParam
34.wsprintf是win32 api中唯一一个参数个数不定的函数。
35.FindWindow,lpClassName,lpWindowName(返回找到窗口的句柄)
36.不同消息的wParam和lParam是不同的。
37.WM_COPYDATA消息的COPYDATASTRUCT结构:
COPYDATASTRUCT
dwData    DWORD    ?    ;附加字段
cbData    DWORD    ?    ;数据长度
lpData    DWORD    ?    ;数据位置指针
COPYDATASTRUCT    ENDS
资源
38.资源源文件中
菜单 ID MENU [DISCARDABLE]指定菜单的ID值和内存属性
数值型ID的范围:1~65535    字符串在内存中的线性地址总是大于10000h
菜单项:
menuitem 菜单文字,命令ID[,选项列表]
或menuitem SEPARATOR
或popup 菜单文字[,选项列表]
命令ID:但菜单被选中时会发送WM_COMMAND消息,消息的参数就是命令ID
39菜单的装载:
菜单可以在createwindowex中的参数hMenu指定句柄,那么菜单句柄如何获得?用api:LordMenu,hInstance,菜单的ID
40.WM_COMMAND的两个消息:
wParam高位=wNotifyCode    通知码
wParam低位=wID        命令ID
lParam=hwndCtl        发送消息的子窗口句柄(工具栏、按钮等)(对于菜单或加速键引起的WM_COMMAND消息则lParam为0)
菜单消息的通知码是0,加速键消息的通知码是1
程序运行中动态修改菜单:
AppendMenu,hMenu,uFlag,uIDNewItem,lpNewItem
InsertMenu,hMenu,uPosition,uFlags,uIDNewItem,lpNewItem
ModifyMenu,hMenu,uPosition,uFlags,uIDNewItem,lpNewItem
DeleteMenu,hMenu,uPosition,uFlags
RemoveMenu,hMenu,uPosition,uFlags
uFlags一般用两种值:MF_BYCOMMAND  MF_BYPPOSITION
对于popup菜单
DeleteMenu:全删
RemoveMenu:仅移去菜单项,菜单在内存中还是存在的(可以在其他地方引用)
对于非popup菜单,两者相同
41.系统菜单:指按下了标题栏图标后弹出的菜单。
42.选中系统菜单项发送WM_SYSCOMMAND消息
系统菜单的句柄:GetSystemMenu,hWnd,FALSE
系统菜单的默认菜单项的命令ID(系统预定义):
保存    SC_RESTORE
移动    SC_MOVE
大小    SC_SIZE
最小化    SC_MINIMIZE
最大化    SC_MAXIMIZE
关闭    SC_CLOSE
43.右键弹出菜单
TrackPopupMenu,hMenu,uFlags,x,y,nReserved,hWnd,lpRect
该函数执行后在x,y处弹出属于hWnd窗口的菜单(即WM_COMMAND消息发往该窗口)(x,y以屏幕左上角为基准)
uFlags:一般用TPM_LEFTALIGN
该参数还可用于指定用左键还是右键选定菜单项:TPM_LEFTBUTTON   TPM_RIGHTBUTTON
lpRect指向一个RECT结构,用于指定一个区域,在这个区域外单击鼠标菜单才会消失,如果为NULL,则在菜单外单击,菜单就会消失。
在客户区右击弹出菜单,所以要处理WM_RBUTTONDOWN消息。在该消息中调用TrackPopupMenu
一般在单击处弹出菜单,所以要要获取鼠标坐标GetCursorPos,lpPoint
lpPoint指向POINT结构
POINT    STRUCT
x  DWORD  ?
y  DWORD  ?
POINT    ENDS
LordMenu载入的不是popup菜单,popup只能在第二层及以下。用GetSubMenu
invoke GetSubMenu,hMenu,nPos
.if eax
mov hSubMenu,eax
.endif
nPos:菜单项的索引,从0开始
右键菜单一般性代码范例:
local:@stPos:POINT
……
invoke GetCursor,addr @stPos
invoke TrackPopupMenu,hSubMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL
44.菜单将激活,即用户在菜单上按动鼠标时,windows在菜单弹出之前会向窗口过程发送WM_INITMENU消息,可以在这个消息的处理中进行菜单项的检测和设置:
GetMenuState,hMenu,uId,uFlags
GetMenuState函数的返回值:
失败返回-1
成功则:
MF_CHECKED
MF_DISABLED
MF_GRAYED
MF_HILITE高亮
MF_MENUBARBREAK
MF_MENUBREAK
MF_SEPARATOR
以上的组合值
如何检测菜单状态:
invoke GetMenuState,hMenu,IDM_XXX,MF_BYCOMMAND
.if eax&MF_CHECKED(表示菜单项选中)
…………
.endif

EnableMenuItem,hMenu,uIDEnableItem,uEnable(uEnable取值:MF_ENABLED  MF_DISABLED  MF_GRAYED)(菜单项在可用、禁用、灰化之间转化)
CheckMenuItem,hMenu,uIDCheckItem,uCheck(uCheck取值:MF_CHECKED  MF_UNCHECKED)
CheckMenuRadioItem,hMenu,idFist,idLast,idCheck,uFlags
45.没有与窗口相连的菜单要用DestroyMenu来释放内存
SetMenu,hWnd,hMenu用于在不同情况下给程序以不同的菜单(如未打开文件和打开文件下窗口的菜单是不同的,这就需要在rc文件中建多个菜单)

c语言win32 sdk笔记

大一上学期的一些笔记

GetShortPathName(“”,shortpath,sizeof shortpath)
mciSendString(cmd,”",0,NULL)
mciSendString的声明在mmsystem.h中
OPENFILENAME结构体
lStructSize=sizeof(ofn);
lpstrFile=szfile;
lpstrFile[0]=TEXT(‘’);
nMaxFile=sizeof(szfile);
lpstrFilter=TEXT(“all*.*text*.txtmp3*.mp3……”);
nFilterIndex=1;
lpstrFileTitle=NULL;
nMaxFileTitle=0;
lpstrInitialDir=NULL;
hwndOwner=hwnd;
Flags=OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST

ZeroMemory函数:局部变量的置0
zeromemory(&结构体名,sizeof(结构体名));

socket编程:
windows独有的函数都以WSA开头。
api执行完后结果放到lasterror中
GetLastError()
FormatMessage()将错误码转换为错误消息
recv(sock,buffer,sizeof(buffer)/sizeof(TCHAR),0)
send(sock,buffer,sizeof(buffer)/sizeof(TCHAR),0)

逆向笔记

大一上学期的一些笔记:

1.用堆栈存放局部变量
编译器非优化模式下用ebp寻址。ebp-xxxx    参数则为ebp+xxxx
编译器优化模式下用esp直接寻址
2.局部变量分配与清除堆栈:
一、sub esp,n
…………
add esp,n
二、add esp,-n
…………
sub esp,-n
三、push reg(reg为某个寄存器)
…………
pop reg
3.利用寄存器存放局部变量:
如果寄存器不够用,会利用堆栈。逆向时必须及时确定当前寄存器的变量是哪个变量。
4.如果函数有两个参数,用ebp传址,则两参数地址一般为ebp+08  ebp+0c
push ebp
mov ebp,esp
push ecx
mov eax,dword ptr [ebp+08]
mov ecx,dword ptr [ebp+0c]
………………
5。全局变量一般位于.idata区的一个固定地址上,访问时直接用硬编码的地址直接对内存寻址.
6.数组:基址加变址寻址
7.开始时xor一个寄存器往往是将其作为一个变量使用。
【基址+n】一般为给数组或结构赋值,其中基址为常量或寄存器。
8.lea有时等价于add
lea eax,[eax+8]等价于add eax+8
lea的效率远远高于add,这种技巧可以使多个变量的求和在一个指令周期内完成
9.大写字母:41h——5Ah大写字母的第5位为0
小写字母:61h——7Ah小写字母的第5位为1
10.c语言strlen()在优化模式下的汇编代码:
mov ecx,FFFFFFFF    ;如果看到这句,程序很可能是要获得字符串的长度了
sub eax,eax
repnz
scasb
not ecx
dec ecx
je xxxxxxxx
11.测试寄存器是否为0:
cmp eax,00000000h

or eax,eax

test eax,eax
12.置寄存器0FFFFFFFFh
xor eax,eax/sub eax,eax
dec eax

stc
sbb eax,eax
13.转移指令:
jmp _lable_

push _lable_
ret
14.获取编辑框字符串常用api:
GetWindowTextA(W)
GetDlgItemTextA(W)
GetDlgItemInt
判断完注册码后常常显示对话框,告诉用户是否正确,显示对话框的常用api:
MessageBoxA(W)
MessageBoxExA(W)
MessageboxIndirectA(W)
DialogBoxParamA(W)
DialogboxIndirectParamA(W)
CreateDialogParamA(W)
CreateDialogIndirectParamA(W)
ShowWindow
程序每次启动都会将注册码读出来加以判断,决定是否以注册版的模式工作,根据序列号放置位置不同,可用不同的api断点:
(1)序列号在注册表中:可用RegQueryValueExA(W)
(2)序列号在ini文件中:可用GetPrivateProfileStringA(W)、GetPrivateProfileIntA(W)、GetProfileStringA(W)、GetProfileIntA(W)
(3)序列号在一般文件中,CreateFileA(W)、_lopen()
15.数据约束性(密码相邻性):(仅限于明文比较注册码的保护方式)真正正确的注册码会在某个时刻出现在内存中,但位置不定。大多数情况下会在输入序列号的内存地址+-90h的地方。它们会共同位于一个小堆栈区域(加密者一般用局部变量放临时计算出来的注册码),使得它们可以在同一个watch窗口中看到。
16.模块句柄hInstance是实例的基地址
17.DialogBoxParam函数原型:
int DialogBoxParam(
HINSTANCE hInstance,    模块句柄
LPCTSTR lpTemplateName,    对话框ID
HWND hWndParent,    父窗口句柄
DLGPROC lpDialogFunc,    对话框处理函数指针(程序会跳到这里执行)
LPARAM dwInitParam    初始化值
);
18.去除某个对话框的方法:
先用exescope打开查看资源,若对话框为资源,记下ID,用w32dasm,打开对话框参考,找到对应id的对话框,双击来到代码处。
若为DialogBoxParam,用jmp跳过(EndDialog后面)
若主窗口也为DialogBoxParam则可修改前一个DialogBoxParam的TemplateName和lpDialogFunc使之指向主窗口。
对话框不是资源时,而常用断点又拦不下来,这是可以试试消息断点。如WM_DESTROY。
19.时间限制:
(1)每次运行多少时间
(2)时间段限制,如用30天
(1)
SetTimer函数:
UINT SetTimer(HWND hWnd,UINT nIDEvent,UINT uElapse,TIMERPROC lpTimerFunc)
hWnd        窗口句柄
nIDEvent    计时器标识
uElapse        指定计时器时间间隔,单位毫秒
lpTimerFunc    回调函数,超时时系统调用该函数,如果为NULL,则超时将向相应窗口发送WM_TIMER消息
该callback函数原型:
void CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
KillTimer()销毁计时器
timeSetEvent(…………)多媒体计时器
GetTickCount()返回系统自成功启动以来的时间(毫秒数)(两次调用相减就得到程序运行时间)
c语言用time()获取系统时间
(2)
取得时间的api:
GetSystemTime
GetLocalTime
GetFileTime
软件主要记录两个时间:
(1)首次运行时间
(2)上次运行时间(每次运行时都获取一次系统时间,若大于上次运行时间,则更新,不然则说明用户将系统时间改回去了)
时间一般记录在注册表或文件或扇区中,不起眼的地方
#define WM_TIMER 0×0113
可见WM_TIMER就是0×0113

json的资料

json是种轻量级格式。json类似于键值对,但可以表示复杂得多的结构,可以嵌套对象(个人理解)。

json有两种结:

1. “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表 (hash table),有键列表(keyed list),或者关联数组 (associative array)。

2.值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

json对象的获取,访问,修改:

将 JSON 数据赋值给变量

例如,可以创建一个新的 JavaScript 变量,然后将 JSON 格式的数据字符串直接赋值给它:   var people = { “programmers”: [ { "firstName": "Brett", "lastName":"McLaughlin", "email": "aaaa" },   { "firstName": "Jason", "lastName":"Hunter", "email": "bbbb" },   { "firstName": "Elliotte", "lastName":"Harold", "email": "cccc" }   ],

“authors”: [   { "firstName": "Isaac", "lastName": "Asimov", "genre": "science fiction" },   { "firstName": "Tad", "lastName": "Williams", "genre": "fantasy" },   { "firstName": "Frank", "lastName": "Peretti", "genre": "christian fiction" }   ],

“musicians”: [   { "firstName": "Eric", "lastName": "Clapton", "instrument": "guitar" },   { "firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano" }   ] }   这非常简单;现在 people包含前面看到的 JSON 格式的数据。但是,这还不够,因为访问数据的方式似乎还不明显。

访问数据

尽管看起来不明显,但是上面的长字符串实际上只是一个数组;将这个数组放进 JavaScript 变量之后,就可以很轻松地访问它。实际上,只需用点号表示法来表示数组元素。所以,要想访问 programmers 列表的第一个条目的姓氏,只需在 JavaScript 中使用下面这样的代码:   people.programmers[0].lastName;   注意,数组索引是从零开始的。所以,这行代码首先访问 people变量中的数据;然后移动到称为 programmers的条目,再移动到第一个记录([0]);最后,访问 lastName键的值。结果是字符串值 “McLaughlin”。   下面是使用同一变量的几个示例。   people.authors[1].genre // Value is “fantasy”   people.musicians[3].lastName // Undefined. This refers to the fourth entry, and there isn’t one   people.programmers[2].firstName // Value is “Elliotte”   利用这样的语法,可以处理任何 JSON 格式的数据,而不需要使用任何额外的 JavaScript 工具包或 API。

修改 JSON 数据

正如可以用点号和括号访问数据,也可以按照同样的方式轻松地修改数据:   people.musicians[1].lastName = “Rachmaninov”;   在将字符串转换为 JavaScript 对象之后,就可以像这样修改变量中的数据。

转换回字符串

String newJSONtext = people.toJSONString();

可以将 任何JavaScript 对象转换为 JSON 文本。并非只能处理原来用 JSON 字符串赋值的变量。为了对名为 myObject的对象进行转换,只需执行相同形式的命令:

String myObjectInJSON = myObject.toJSONString();

下面是和xml之间的对比:

(例子来自百度)

用XML表示部分省市数据如下:

<?xml version=”1.0″ encoding=”utf-8″?>

<country>

<name>中国</name>

<province>

<name>黑龙江</name>

<cities>

<city>哈尔滨</city>

<city>大庆</city>

</cities>

</province>

<province>

<name>广东</name>

<cities>

<city>广州</city>

<city>深圳</city>

<city>珠海</city>

</cities>

</province>

<province>

<name>台湾</name>

<cities>

<city>台北</city>

<city>高雄</city>

</cities>

</province>

<province>

<name>新疆</name>

<cities>

<city>乌鲁木齐</city>

</cities>

</province>

</country>

用JSON表示如下:

{

name:”中国”,

province:[

{

name:"黑龙江",

cities:{

city:["哈尔滨","大庆"]

}

},

{

name:”广东”,

cities:{

city:["广州","深圳","珠海"]

}

},

{

name:”台湾”,

cities:{

city:["台北","高雄"]

}

},

{

name:”新疆”,

cities:{

city:["乌鲁木齐"]

}

}

]

}

很明显,xml的可读性高于json,但是不适合人读的往往适合计算机读,json这是如此,json相当高效。

JSON在线校验工具:

BeJson

关于linux的参数执行顺序。。

        今天在看正则表达式的时候遇到了两个问题,用vi打开/etc下的sysctl.conf的时候会发现有许多空白行和注释行。但是有时候stdout的时 候并不需要这些信息,若是打印时则更能节省纸张资源。-_-!于是我用grep命令将其去除,具体指令为grep -v ‘^$’ /etc/sysctl.conf|grep -v ‘^#’可是运行完该句之后的结果着实让我头疼,因为我发现注释行仍然出现了,而且前面还多了一个数字。往上一检查才发现自己多打了一个n。。命令变成了 grep -vn ‘^$’ /etc/sysctl.conf|grep -v ‘^#’。
        这对我来说是个不错的收获。因为大家都知道管道命令会把前者的stdout转换为后者的stdin,而碰巧的是n正好有是grep的一个参数,用于输出行 号。于是后者的stdin的每行的开始都有了行号。这样每行的开始都不是#字符了,注释也就自然没被去除。看来管理时真的要小心谨慎,一不小心结果就会发 生错误。另外,如果有些童鞋在不是自己的主机上执行该命令的时候会发现命令完全正确,可是结果还是有类似错误。这时候很可能是因为grep被该用户 alias过的原因。比如该用户alias grep=’grep -v’.这样会有更奇怪的结果哦(会有两列行号^_^)当然这点如果多执行命令的话也是可以发现的,其实type grep一下就·ok。而且一般人不会这么做,毕竟v用于显示没有指定字符串的行。如果真是这个原因,怎么改呢?很简单,去改下用户目录下 的.bashrc文件吧。这个是login shell会读取的文件。里面会初始化一些命令别名,然后会注册一些环境变量。login时会被~/.bash_profile调用。如果发现grep被 alias成带v参数,就赶紧把它注释掉吧。要想立刻生效的话,手动读取一下吧。source ~/.bashrc 这样就ok了。
这时候,,又想到一个问题,上述命令中的参数v和n是哪个先执行呢。联系到最近在win32汇编上学的c调用、stdcall都是右边参数先入栈来看的 话,我想linux应该也类似吧(。。。纯属个人胡扯~~~~)。那样应该是自左向右顺序执行的。从结果来看,空行确实被去除了,那是不是真的是自左向右 的顺序呢。于是验证了一下。grep -nv ‘^$’ /etc/sysctl.conf|grep -v ‘^#’结果空行还是被去除了。看来假设不对。如果自左向右,那么-n执行后每行都有行号,再执行-v不会去除空行。当然这里有个问题,那就是我不清楚第 一个参数执行后是否真正影响了输出,如果行号没被算进去的话执行-v后还是会去除空行的。这样参数执行顺序的问题还是不敢下定论。。可是大年夜的没有网络 可用。看来有机会得去百度一下了。。
不过,这时候,,,天亮了。。下午四五点起床的孩子通宵无压力。。O~睡觉去了。。。
以上分析纯属本人臆测,OS为Cent OS。内核为2.6.32-71.e16.i686。不过我开了下gentoo,发现gentoo的用户~目录下好像没有.bashrc文件、、、
(以上均为本人学习过程中的杂乱思绪,不免大量错误,不做任何参考。。)

2012.1.23