我现在是怎么读源代码的

如果你有更好的方法请告诉我

1. 有文档先读文档。尽管多数库可能根本么文档,但一个简短的tutorial一般还是有的。读一读有个大概观念是很重要的。尽管网上,甚至是源码附带的文档可能已经不是最新了,但读一读总比不读好。注意:这些文档一般是英文的,有的是日文的

2.读之前的准备。先用ctags生成tags文件,这样在emacs里读代码时,可以M-.从调用这个函数的地方直接跳转到它定义的地方,M-*再跳回去,很方便。这个功能一般的ide也能实现。但注意对c这样成熟的静态语言,tags比较好用。但是对ruby这样动态语言就不太好了。因为tags本质上是一种静态方法。更好的动态方法是运行一个ruby解释器,通过它运行源码来找出定义的地方,这个我还在研究。

3.不管懂不懂,先读一遍再说。好歹先有个印象。

4.通过tutorial先写一个简单的例子。然后用调试器一步一步的调试这个例子。ruby的命令行调试器虽然不好看但是真心比VS的好用

5.重复3-4步,边读/调试边做笔记。直到觉得差不多为止。

关于类图这个事。我查了一下,有像cflow这样的软件,但是只能生成c的流程图。我觉得机器生成的流程图比较简陋,起不到多大作用。考虑到多数ide也不支持生成类图。VS也是旗舰版才支持类图。我觉得这玩意儿虽然好看,作用不大。

关于插件,语法高亮是必要的。所以ruby major mode得有,其次调试器必要。另外textmate.el必要。一个如Fastri这样的插件很有用,但我还没装,也可以自己切到浏览器去看文档,就是麻烦点。

Lisp真是一门好语言

lisp真是一门终极的编程语言。我接触lisp也不过一个月时间?现在发自肺腑的这么觉得。为什么?因为lisp又高级又基础,lisp没有python或者ruby里那些便利的数组或者hash操作函数,很多时候,lisp的数据只由2个部分组成:

(AAA . BBB)

第一个元素AAA称为car部分,剩下的另外一半。不管有多少,称为cdr部分。也就是对称的第二个元素。这叫con cell元素。很多复杂的数据结构,比如数组,hash表,红黑树,二叉树都是由它实现的。你说它不基础?但是lisp又很高级,c语言的一个特性是,机器效率虽高,但是人工效率很低。而lisp不同,《黑客与画家》中指出,lisp只需要c语言十分之一的代码就能实现同等的功能。而lisp甚至能直接操作cpu的寄存器,这是哪种高级虚拟机语言能实现的?

lisp很简洁,用一句话就能概括lisp的语法:

例如(A B C)

用圆括号括起来称为一个列表,列表中第一个原子被视为函数,其他原子被视为变量。而由单括号‘前导的元素什么也不视为(不求值),只按原样返回。

完了,就这么简单。剩下的都是细节。要知道真理都是很简洁的,比如e=mc2,真理总结出来都这么简单。所以lisp很强。

用多数人可以理解的话说,lisp没有”保留字“。我们知道每种语言包括c但是有保留字的。这意味着2点:

1.他们的处理语句和数据是分开的,不一样的。
2.他们都是被限制了的

但是lisp没有保留字,为什么呢?你看多数语言像c++,Java根本就没有所谓符号(symbol),ruby有符号,但是应用很少。lisp不同,lisp大多数原子都是符号。比如(print atom-1 atom-2),每一个符号可以连接着一个函数定义,或者一个变量定义,这个例子就是对atom-1,atom-2 两个符号进行求值,找出他们的变量定义然后交给print这个函数去运算。你可以把它调过来。(atom-1 print atom-2) ,这个例子就是对print,atom-2 两个符号进行求值,找出他们的变量定义然后交给atom-1连接的函数去运算,区别可能是print可能是一个系统预先定义好的函数,而atom-1可能是用户自定义函数。所以说lisp是没有保留字,也不需要保留字的。

所以我们就可以看到了,lisp一个有名的特点,数据和语句是一样的,是怎么实现的了。非常简单,同样的东西,你把它放在列表第一个,就是函数,否则就是变量,如果加上单引号不求值,那就是数据。如此,lisp也可以实现非常强大的宏系统,这也是独一无二的,其他语言都不能,因为他们都不可以把数据和语句区别开来。简单的说,宏就是接受一个参数,然后返回对应的代码,插入到调用宏的位置

( defmacros (args)
`(defun aaaaa(,args)
;; process ))
这样的东西

把对应的代码恢复到对应位置,只要求值,就和普通的代码无异。所以lisp可以。而其他语言不可以。你返回一段语句,这段货的数据类型是啥?它就是数据,不是语句。要运行它,eval它,然后只能得到一个结果(以我对ruby粗浅的了解,它已经比java灵活太多了)。不像lisp可以替代源代码中的一个部分,比如替代函数中的一部分,这段代码可以操作参数,其他语言可以么?

但是lisp这么强大,为什么1958年就被发明,半个世纪以来,lisp没有广泛的应用?

lisp并非没有得到过应用。在教学领域,lisp是一门非常广泛使用的语言,那些不急功近利的学校比如麻省理工,入门课都采用schme(一门lisp的方言),而在商业领域,有名的《黑客与画家》的作者P··G在创立世界第一家互联网企业viaweb时,使用的是lisp。lisp之所以没有被广泛应用,是因为它太强大了,这么说似乎有点欠揍,但强大就意味着灵活,而灵活就意味着几乎没有语法。那些商业公司想要的只是稳定,把工作完成,他们并不在乎你用什么语言开发。他们才恨不得每一行都是钉死的,所有人都用一个名字写函数,因为这样可以花更少的钱维护。ruby之父松本行宏曾这么说:

而lisp的问题在于,只要你掌握了s表达式,想写出什么样的程序都行,这意味lisp是没有语法的。这在应用上带来了一定的麻烦。我不希望自己的语言是没有语法的。所以ruby加入了一定的语法限制。

而在程序员的角度来说,以我看来,大多数人似乎不那么聪明,多数人喜欢用一种死语言(java/c++)也无可厚非,因为他们的思维可能就是死的。lisp可能更适用于强大的黑客,自己或者少数人每个人都很强的类型,它是一种黑客语言,而不是一种商业语言。

综上所述,lisp是灵活的,天马行空的,没有限制的。在我看来,一旦使用lisp,就不会想在去使用其他语言。lisp有一种和谐的美。我认为,Fortran,c++,java这样的东西是应需而生的,他们是为了满足当下的需要和硬件条件而设计使用的。而lisp从开始就是为了迎合真理和美而生。所以50年过去了,lisp还没有过时。lisp就是计算机界的真理,记得漫画《风云》中有这么一句,因为不管到哪里,真理(或者是类似的词)就是真理,所以绝世好剑的形状在哪都是一样的。lisp也是一样。以后可能会出现别的名字的语言,也可能不叫lisp,但是真理总是真理,所以绝世好剑的形状总是一样的。

但是从现实的角度来看,我们要编程,如何运用lisp呢?

  1. emacs使用emacs lisp作为架构语言(不仅仅是扩展语言),这是绝佳的学习lisp的途径
  2. common lisp和scheme作为lisp最有名的两门方言,广为人知。但是在教育领域应用比较多。实际用途似乎比较少
  3. GNU组织使用guile作为gnu通用扩展语言,但是我没听说哪有它的应用。
  4. 时下最火的clojure,你可能听说过,这是一种运行在java虚拟机上的lisp,编译为java字节码,具有和java一样的速度,使用它可以无缝使用jdk里的所有库和java的无数第三方库,现在你知道它为啥火了。clojure的一个子集可以编译为javaascript运行在浏览器中,这带来了无尽的可能,尽情的享受那些愚民们的成果吧,node.js貌似也行。
禁止结束进程

Windows内核学习之进程保护器(防止任务管理器结束进程)

写了三天左右,思路什么的都很清晰,真正实现的时候就各种问题,蓝屏蓝到麻木了,幸好是虚拟机,半年前就打算看驱动了,因为各种原因耽搁了,现在什么都要重新来,这篇文章就当是开门贴吧。

主要功能:防止任务管理器结束进程。

主要原理:HOOK SSDT表中的NtOpenProcess,如果传入的是保护进程的PID,则返回无效句柄。

这个Windows进程保护器的主要界面如下:

防止任务管理器结束进程

利用此程序实现的禁止任务管理器中结束进程的效果图:

禁止结束进程

实现过程总结

应用程序层:

//为listcontrol添加右键菜单
#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam))
#endif
case WM_CONTEXTMENU:
{
UINT xPos;
UINT yPos;
HWND hwndContext;
hwndContext = (HWND)wParam;
HWND hWndlist= GetDlgItem(hDlg, IDC_PROCESS_LIST);
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
// 来自 hWndlist 的消息
if(hwndContext == hWndlist)
{
// 非右键点击
if (xPos == -1 || yPos == -1)
{
break;
}
HMENU hMenu=LoadMenu(hIns,MAKEINTRESOURCE(IDR_MENU1));
HMENU hMenuTrackPopup=GetSubMenu(hMenu,0);
TrackPopupMenu(hMenuTrackPopup,TPM_LEFTALIGN | TPM_RIGHTBUTTON,xPos,yPos, 0, hDlg, NULL);
DestroyMenu(hMenu);
}
// 做你自己的事
break;
}
TrackPopupMenu倒数第二个参数,要为当前对话框的句柄,否则无法响应菜单ID。
//初始化listcontrol

VOID ListIni(HWND hDlg)
{
HWND hWndlist;
LVCOLUMN ColInfo1 = {0};
LVCOLUMN ColInfo2 = {0};
LVCOLUMN ColInfo3 = {0};
LVCOLUMN ColInfo4 = {0};
LVCOLUMN ColInfo5 = {0};
hWndlist= GetDlgItem(hDlg, IDC_PROCESS_LIST);
SendMessage(hWndlist, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES);
ColInfo1.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
ColInfo1.iSubItem = 0;
ColInfo1.fmt = LVCFMT_CENTER;
ColInfo1.cx = 100;
ColInfo1.pszText = "进程名";
ColInfo1.cchTextMax = 50;
ColInfo2.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
ColInfo2.iSubItem = 0;
ColInfo2.fmt = LVCFMT_CENTER;
ColInfo2.cx = 50;
ColInfo2.pszText = "PID";
ColInfo2.cchTextMax = 50;
ColInfo3.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
ColInfo3.iSubItem = 0;
ColInfo3.fmt = LVCFMT_CENTER;
ColInfo3.cx = 80;
ColInfo3.pszText = "EPROCESS";
ColInfo3.cchTextMax = 50;
ColInfo4.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
ColInfo4.iSubItem = 0;
ColInfo4.fmt = LVCFMT_CENTER;
ColInfo4.cx = 210;
ColInfo4.pszText = "路径";
ColInfo2.cchTextMax = 50;
ColInfo5.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
ColInfo5.iSubItem = 0;
ColInfo5.fmt = LVCFMT_CENTER;
ColInfo5.cx = 50;
ColInfo5.pszText = "状态";
ColInfo5.cchTextMax = 50;
::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(0), LPARAM(&ColInfo1));
::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(1), LPARAM(&ColInfo2));
::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(2), LPARAM(&ColInfo3));
::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(3), LPARAM(&ColInfo4));
::SendMessage(hWndlist, LVM_INSERTCOLUMN, WPARAM(4), LPARAM(&ColInfo5));
}
//与驱动间的通信
传入要保护的进程PID数组
bRet = DeviceIoControl(hDevice, IOCTL_PROTECTPROCESS_CONTROL, ProPid, sizeof(ULONG)*100,
NULL,0,&dwOutput, NULL);
//从驱动中获取当前进程列表
bRet = DeviceIoControl(hDevice, IOCTL_GETPROCESS_CONTROL,&de, sizeof(ULONG),ProcessList,
sizeof(_ProcessList)*100,&dwOutput, NULL);
驱动层:
#pragma PAGEDCODE
struct _ProcessList
{
UCHAR ProcessName[30]; //进程名
ULONG PID;//PID
ULONG Eprocess;//Eprocess
ULONG ProCount;
}ProcessList[100];
#pragma PAGEDCODE
ULONG ProPid[100];

当时看的是Windows驱动开发详解,把变量换到分页内存中,害我蓝屏了30多次。

//获取进程列表
VOID EnumProcessList()
{
ULONG EProcess , FirstEProcess ;
ULONG dwCount = 0 ;
PLIST_ENTRY ActiveProcessLinks;
ULONG dwPidOffset =0x84;
ULONG dwPNameOffset = 0x174;
ULONG dwPLinkOffset = 0x88;
ULONG dwProcessId;
PUCHAR pImageFileName;
FirstEProcess = EProcess = ( ULONG ) PsGetCurrentProcess() ;

while ( EProcess != 0 )
{
dwProcessId = * ( (PULONG) ( EProcess + dwPidOffset ) ) ;
pImageFileName = ( PUCHAR ) ( EProcess + dwPNameOffset ) ;
if ( ( LONG ) dwProcessId >= 0 )
{
//DbgPrint( "[Pid=%8d] EProcess=0x%08x %s\n" ,dwProcessId , EProcess , pImageFileName ) ;
strcpy((char*)ProcessList[dwCount].ProcessName,(char*)pImageFileName);
ProcessList[dwCount].PID=dwProcessId;
ProcessList[dwCount].Eprocess=EProcess;
ProcessList[dwCount].ProCount=0;
dwCount ++ ;
}
ActiveProcessLinks = ( PLIST_ENTRY ) ( EProcess + dwPLinkOffset ) ;
EProcess = ( ULONG ) ActiveProcessLinks->Flink - dwPLinkOffset ;
if ( EProcess == FirstEProcess )
{
break ;
}
}
DbgPrint ( "ProcessNum = %d\n", dwCount ) ;
ULONG i=0;
ProcessList[0].ProCount=dwCount;
DbgPrint ( "ProcessNum = %d\n", ProcessList[0].ProCount ) ;
for (i=0;iMajorFunction)
{
case IRP_MJ_CREATE:
DbgPrint("IRP_MJ_CREATE被调用\n");
break;
case IRP_MJ_CLOSE:
DbgPrint("IRP_MJ_CLOSE被调用\n");
break;
case IRP_MJ_DEVICE_CONTROL:
DbgPrint("IRP_MJ_DEVICE_CONTROL被调用\n");
IoControlCode=IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode)
{
case IOCTL_PROTECTPROCESS_CONTROL:
inSize=IrpStack->Parameters.DeviceIoControl.InputBufferLength;
outSize=IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
inBuf=(long*)pIrp->AssociatedIrp.SystemBuffer;
RtlCopyMemory(ProPid,inBuf,sizeof(ULONG)*100);
break;
case IOCTL_GETPROCESS_CONTROL:
PVOID pInputBuffer, pOutputBuffer;
ULONG outputLength, inputLength;
DbgPrint("COMM_BufferedIo\r\n");
outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;
pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer;
DbgPrint("COMM_BufferedIo UserModeMessage = '%s'", pInputBuffer);
for (int i=0;iIoStatus.Information = outputLength;
break;
default:
break;
}
break;
default:
DbgPrint("未知请求包被调用\n");
break;
}
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
KdPrint(("Leave HelloDDKDispatchRoutine\n"));
return status;
}

使用emacs而非普通ide的几个理由

轻便:emacs包括海量的文档也只有28M, 而eclipse一般是100多M,这就算轻便的了,visual studio是以G记的。而且emacs在启动时会占用更小的内存,更小的资源占用意味着更稳定,可以反复启动多次也不觉得浪费时间

支持:ide里eclipse只有对java和c++算是全功能,其他语言支持较少。visual studio因为是微软产品,除了对微软自家东西之外没有任何支持。而对python和ruby等开源语言或者clojure等新兴语言甚至是小众语言。这些ide要对一门新语言支持,等把。而emacs和vim等文本编辑器就好得多。

可定制性:在ide中想增加一个新功能,哪怕比较简单。提交bug报告然后等新版本吧,还不一定有。在emacs里你只要用lisp写新的代码然后hook到已有的模式,甚至直接改写已有模式就行了。

文本编辑功能:在emacs中即使在特定模式一般全局按键都是可用的,比如跳转到行首行尾,按词移动等。eclipse里也有类似特性但是emacs里更多。

因为ide能做的emacs大部分都能做到,而emacs能做的很多ide都无法实现,所以干嘛要用ide呢,无非是要付出时间去学习而已

Ruby与emacs IDE,第一季

emacs安装后自带一个ruby模式,但是这个ruby mode功能弱的只能用敷衍来形容。与之相对c++和python就提供了完善的支持。不公平啊。所以不自己配置是肯定不行的。但是配置这货的过程充满了艰辛,就和我天天早起喝得叫人撞墙的中药一个味儿。现在想起来从一个小白起到能获得一个勉强能跑的emacs环境真是奇迹。问题在于相关的过程极度缺乏正规的文档化,有用的文章几乎都出自个人的摸索,分布于广大的互联网上各个blog里,很多是被封锁的,而且很大一部分都是用日文写成的,所幸的是这两点对我都不是问题。

ruby其实和emacs是很有渊源的。ruby的作者,松本行宏先生,在发布ruby前最有名的作品就是emacs的一个扩展。他的作业环境毫无疑问也是emacs。但是现在要设置emacs却如此麻烦。需要注意的是我配置的是ruby开发环境,而不是rails的,而且是1.9,很不成熟。首先是主模式,在ruby的源码包下misc目录里,有一堆el文件 ,这就是ruby在emacs中的基本。

ruby-mode.el 这是基本ruby-mode主模式。
inf-ruby.el 在ruby主模式里运行内置的irb
ruby-electric.el 一个加强副模式
rubydb3x.el 在emacs里调用debugger

要在emacs里使用这些文件需要把他们拷贝到执行路径中,我新建了名为myEmacsEl的文件夹并将其添加到执行路径中。我的.emacs如下:

(set-default-font "DejaVu Sans Mono-14")
(set-fontset-font (frame-parameter nil 'font)
    'han'("WenQuanYi Micro Hei"))
(defun toggle-fullscreen()
  (interactive)
  (x-send-client-message
   nil 0 nil "_NET_WM_STATE" 32
   '(2 "_NET_WM_STATE_FULLSCREEN" 0))
)
(run-with-idle-timer 0.1 nil 'toggle-fullscreen)
(run-with-idle-timer 0.1 nil 'delete-other-windows)
(tool-bar-mode nil)

;;;;;;;;
;;ruby;;
;;;;;;;;
(setq ruby-program-name "/home/???/.rvm/rubies/ruby-1.9.3-p194/bin/irb --inf-ruby-mode")
;Allows syntax highlighting to work, among other things
(global-font-lock-mode 1)
; directory to put various el files into
(add-to-list 'load-path "/home/???/myEmacsEl/ruby")
; loads ruby mode when a .rb file is opened.
(autoload 'ruby-mode "ruby-mode"
  "Mode for editing ruby source files" t)
(setq auto-mode-alist
      (append '(("\\.rb$" . ruby-mode)) auto-mode-alist))
(setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
                     interpreter-mode-alist))
; set to load inf-ruby and set inf-ruby key definition in ruby-mode.
(autoload 'run-ruby "inf-ruby"
  "Run an inferior Ruby process")
(autoload 'inf-ruby-keys "inf-ruby"
  "Set local key defs for inf-ruby in ruby-mode")
(add-hook 'ruby-mode-hook
          '(lambda ()
             (inf-ruby-keys)
         ))
; adding ruby electric
(add-hook 'ruby-mode-hook
          (lambda()
            (add-hook 'local-write-file-hooks
                      '(lambda()
                         (save-excursion
                           (untabify (point-min) (point-max))
                           (delete-trailing-whitespace)
                           )))
            (set (make-local-variable 'indent-tabs-mode) 'nil)
            (set (make-local-variable 'tab-width) 2)
            (imenu-add-to-menubar "IMENU")
            (define-key ruby-mode-map "\C-m" 'newline-and-indent)
            (require 'ruby-electric)
            (ruby-electric-mode t)
            ))
;ruby debug
(autoload 'rubydb "rubydb3x" "run rubydb on program file in buffer" t)
;Auto-complete.el
(add-to-list 'load-path "/home/???/myEmacsEl/auto-complete")
(require 'auto-complete)
(global-auto-complete-mode t)
(add-to-list 'ac-dictionary-directories "/home/???/myEmacsEl/auto-complete/dict")
(require 'auto-complete-config)
(ac-config-default)
(add-to-list 'load-path "/home/???/.rvm/gems/ruby-1.9.3-p194/gems/rcodetools-0.8.5.0")
(require 'auto-complete-ruby)

从ruby标记往下是ruby的。

要注意的部分如下;
(setq ruby-program-name “/home/???/.rvm/rubies/ruby-1.9.3-p194/bin/irb –inf-ruby-mode”)
设置irb解释器的变量,务必要设定,否则inf-ruby内置解释器无法工作。因为我用的是rvm所以路径比较特殊。–inf-rubymode这个选项也是必须的,否则虽然可以用但是输出会很难看。这里用一个变量来确定irb的位置,我是很喜欢的,因为以后可以用pry之类的加强型irb替代。
(add-to-list ‘load-path “/home/???/myEmacsEl/ruby”)
追加路径

ruby-mode的主要功能就是tab的缩进功能被大幅在增强了,比如if或者循环可能嵌套很多层,按一下tab或者在回车时就可以正确缩进到当前应该缩进的位置,而不是仅仅插入一个制表符。
ruby-electric为ruby-mode提供一个副模式,其主要功能就是你在输入class或者def,while等等时会自动在下一行插入一个end,不要你手动去输了,而且双引号括号等等输入一个会自动出来一对,就跟eclipse一样。
inf-ruby自动hook到了ruby主模式上,按下C-c c-s会在emacs中出来一个irb,可以把buffer内的源代码分部分自动发到这个irb里去执行,方便的很。
rubydb3x.el这个就有点麻烦了,正确设定好.emacs后,按下M-x运行rubydb函数,在弹出来的minibuffer中输入当前ruby的全部路径和文件名才行,会自动在emacs里打开一个调试器,这实在说不上方便,我估计只是赋值一个变量的事儿,但是现在的我还做不到,而且ruby自带的调试器实在说不上好。

现在已经有了自动高亮,自动缩进,自动插入end和一个勉强可用的调试器

接下来是加入自动完成,可以自动输入代码中那些为了说明用途而长长的函数名还是很好的。

我用的是auto-complete.el,网址:http://www.cx4a.org/software/auto-complete/ 这货就叫这名字,是一个日本程序员的作品,令人不安的是从2010年后它就没有更新了,当然你也可以用yasppnet,或者其他自动完成后端。auto-complete提供了一个安装脚本,甚至还提供了一个Make文件,但是你读一遍就会发现它实际上就是把一些el文件放在安装的位置而已,所以你也可以手动做这些事,下载安装包,解压之后把所有的el文件和dict目录放在执行路径下,编辑.emacs文件。然后要再从这个作者的网站下载一个auto-complete-ruby.el文件放在路径下,因为auto-complete是一个泛用模式,它会给所有的主模式添加一个副模式,而auto-complete-ruby.el是为ruby特化,可是他需要require rodetools,这玩意儿从哪呢,gem install rcodetools.但是我就奇怪,你gem安装它和emacs有何关,能require到么?然后我在启动emacs时看到了一个warning,解决办法是你到rcodetools的目录下看看,那里面有很多el文件,把它的目录加入执行路径就没事了,这一点所有人都没提到。

悲剧的是auto-complete据我测试,似乎只按照预先定义好的字典和buffer里的上下文进行补全。就是说比如你导入一个第三方库,然后声明一个这个库里的对象,是没法补全他的方法的。因为ruby是动态语言,似乎也没法和java一样补全,因为在运行前无法确定对象的类型好像,我也不是很懂。这在技术上是毫无难度的,连我都可以想到,先运行补全位置之上的所有代码,之后对补全对象调用methods方法,然后根据出来的内容进行补全即可。但是没有必要:1.如果上面的代码有错误怎么办,这是很常见的 2.运行代码尤其当工程很大时要消耗大量时间,如果对这个进程进行优先级调度,则每次运行补全的结果会不一样。3 至少我是没见过ruby的库公共接口有java一样又臭又长的函数名

你可以用yas,但是我估计他和auto-complete没什么区别。Rsense是用java写的,不过按理只有速度上的提示而已。以后再努力尝试更多的补全插件。

我大致是按http://kimiboku.wordpress.com/2011/11/20/emacs-ruby/ 来的,中间也参考了无数其他网页,我看youtube一个视频里它只用了ruby-mode,yas,mate三个模式,mate我还没有尝试,但是基本的上面都有了,勉强也运行的起来。要进一步深入,我估计还是得学会emacs lisp,读懂那些长长的代码,因为文档实在太少了,靠文档和别人的经验活下去,实在只能靠运气。

RVM

从官方安装RVM出现编译安装解释器出现错误的解决本办法

RVMRVM = ruby version manager,它本质上是一组shell脚本,通过从官方下载源码编译来获得ruby解释器,通过它可以让多个版本的解释器共存于一个环境下,这是很方便的。

使用rvm,有很多好处,你可以同时拥有多个ruby版本来运行不同的服务,而且每个解释器可以有自己的gems(第三方库)。而且由于是从官方下载源码编译,它可以第一时间拥有最新的解释器版本,而不用苦逼的等包管理器更新,实际上现在apt里也没有1.9.3版本的ruby。而且出于特殊目的用到老版本时,可以放心的安装而不会影响到现有服务。

从官方安装rvm,并且按照rvm requirement安装所有依赖后,编译安装解释器出现错误

Retrieving rubygems-
There is no checksum for 'http://production.cf.rubygems.org/rubygems/rubygems-.tgz' or 'rubygems-.tgz', it's not possible to validate it.
If you wish to continue with unverified download add '--verify-downloads 1' after the command.
There has been an error while trying to fetch the source. 
Halting the installation.

搜索后有人给出答案:
It looks like a bug, but it most likely is fixed already as I can not reproduce it, update RVM and try again:
rvm get stable
rvm rubygems current

升级rvm,然后重新安装rubygems,解释器出现错误的问题就解决了。

Win7如何安装不兼容的VC++6.0(图文)

寡人今天写程序。可让人生气的是写的所有的程序没一个对的,不能连接运行。原来经过好多次的纠结后来才知道是win7不兼容导致的结果。多费解。好久才弄好。所以来发表个日志,希望有同样问题的孩子们可以试试。废话不说了,以下是正题:

运行setup.exe安装程序,会弹出如下的的程序兼容性助手提示:此程序存在已知的兼容性问题,这个是Win7在警告用户VC++6.0存在兼容性问题:此程序存在已知的兼容性问题。如下图,选中不再显示此消息,点“运行程序”。

之后再有遇到“此程序存在已知的兼容性问题”的提示时候,也按这个做法处理!

win7 vc++6.0不兼容安装

接着安装,进入选择安装类型这一步的时候,要注意。点“Custom”自定义安装类型

win7 vc++6.0不兼容安装

Custom自定义安装里,点中Tools组件,更改选项

win7 vc++6.0

把其中的OLE/Com Object Viewer取消,不选择:

win7 vc++6.0

再返回到组件选择的时候,Tools就变为灰色的勾了,因为里面我们取消了OLE/Com Object Viewer这一顶

win7 vc++6.0不兼容

:其他的就默认安装就可以了,要注意的上面已经都交代了,安装完成,出现安装成功的提示:

解决Win7安装vc++6.0不兼容问题

安装完成后,启动VC6的时候,也出现“此程序存在已知的兼容性问题”的提示,按上面第一步中的处理:选中不再显示此消息,点“运行程序”。搞定,哈哈。

为什么字节码+虚拟机的模式比机器码+编译器更流行?

众所周知现在的软件行业是解释型语言的天下,无论是开源轻量级语言Python/Perl/Ruby还是企业级应用Java甚至微软新搞出来的.Net系列/C#,都基于字节码+虚拟机模式。这么做毫无疑问比机器码+编译器更慢,而且机器码+编译器也并非不能实现高等语言,那么why?

Hacks and Painters里给出的解答是:字节码十分接近机器码,因此为字节码编写基于硬件的解释器比编写编译器更容易!

想象一下。接近自然语言的高等语言+编译器+机器码与接近机器语言的字节码+解释器+机器码。当然是后者更容易,但是后者就额外需要把源代码翻译成字节码的编译器,但这个编译器只要实现一次就够了!(最复杂的部分只要做一次就够),而针对不同的硬件编写解释器是相对十分容易的。

另外如Hacks and Painters所说的,增加软件中间层,会降低执行效率,但能使编程更灵活,开发出的东西更强大。换句话说,这是一个不断抽象,不断接近人类自然思维的过程。

字节码更通用,更灵活,更强大,不拘于平台限制。其唯一的缺点是降低代码运行效率,但是在硬件速度18个月翻一番的今天,这并不重要。

python最大的问题是data structure

python是个很棒的开发语言,语法简洁精练,重要的功能基本都有内置函数。到目前为止我感觉最大的问题在于数据类型,因为他非常容易弄混。

python不像C,不是强类型语言。不需要提前声明变量的数据类型。用到的时候把什么值赋给变量,变量就是什么类型。这乍看起来很方便,但是实际上却非常混乱。因为如果你统一声明所有的变量,那么查阅变量类型是很方便的,像python这样变量类型的定义可能散布在代码的各个角落。尤其是数字,是作为字符对待还是作为数值对待?一旦比较作为数字的数和作为字符的数就是出错。

变量中数的数据类型,我感觉这是目前最容易出错的地方。

DLL文件怎么打开?及DLL格式文件的作用

DLL文件的存在是为了实现软件程序代码的精简化模块化。当我们在系统中运行某一个软件时,这个软件的很多功能可能就是DLL文件提供的。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该DLL中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。

Windows系统以及Windows版本程序中有许多DLL文件。 他们允许各种程序动态连接上实现需要的功能,如与外部设备和硬盘的输入和输出的通信。他们也可能被引用的Mac跨平台的应用程序。那么DLL文件怎么打开?您可以使用下面这些软件:

WindowsWindows系统

Microsoft Visual Studio 2010 (中文页面)
Microsoft Visual FoxPro
Resource Hacker (天空软件下载 汉化版)

注意:删除DLL文件或修改DLL文件的内容,可能会导某些程序无法打开或运行错误,提示没有DLL文件。因此一般情况下不建议您打开DLL文件或进一步对其进行编辑操作。

文件分割技术浅析

所谓文件分割就是指把一个较大的文件,分割成多个较小的文,在一次上传或下载该大文件下载不完的情况下,就可以分次上传或下载这些分割后的小文件,winrar压缩工具中就有实现文件分割的功能。

以个人的理解,一般的分割,其实就是把文件的二进制码,分成数份分别存储,然后在实际要用时,再按照分割后小文件的前后顺序,组合回原文件,这些操作并不复杂,只要把小文件的位置准确放回,不要把位置弄错,就应该不会出什么问题。

一个小程序,实现文件分割,然后将它们合并,基本上可以认为没有什么难度(和上几篇hook的程序比起来),明白原理就行了。
分割的目标文件依然是calc.exe(计算器程序)

文件分割技术

上面的代码就是设置分割后的子文件以及子文件的大小,一共把文件分成了10份,每份大小为原大小十分之一,而最后一个子文件大小为 nFilesize - nFilesonsize[0] * 9,它是做收尾工作,所以特别对待。

文件分割技术

这个就是循环即是实现根据子文件的大小进行二进制码写入,如果对文件打开为什么要分为字符模式以及二进制模式的设置还不怎么清楚的朋友看到这里应该可以有所收获了吧,b 的意义就是当想要这样打开一个程序文件时,体现读写流的形式是二进制,从而可以直接对这些非文档文件进行操作。

图中的一个循环写入已经完成了一切的分割,我也没有必要多解释了。而重新合并也和分割操作差不多,找到所有的分给后子文件,将其按照分割的顺序写成分割前的文件。

文件分割技术

还是循环写入,方向只不过变为由子文件到原文件。结果测试:

文件分割技术

运行第一个程序进行分割。

文件分割技术

这些就是分割后的子文件,当运行第二个程序时就会合并如初。

文件分割技术

计算器正常运行。