Calendar
| September 2008 | | Su | Ma | Tu | We | Th | Fr | Sa | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | | | | | 3 MONTH 4 3 YEAR 4 |
|
|
[极品垃圾]
你爷爷的,居然在老子的博客里发垃圾
by SingleSword posted on 2008-4-1 0:48:06 Weather: 阴 |
跑去删这些垃圾,发现居然删除功能不能用。。。。 而且要删也只能一条条删,真他妈不方便, 只好把数据库下下来裸搞,木哈哈哈哈,方便,搞定。 |
|
[莫名奇妙]
公司搬到苏州了
by SingleSword posted on 2008-3-18 15:05:00 Weather: 小雨 |
公司又搬到苏州了,自从毕业以来,在上海呆了8个月,北京7个月,合肥28个月,不知道要在苏州呆多久,不知道以后会不会再搬。漂来漂去居无定所,不知道何时才是尽头,他爷爷的,这年头要混口饭吃真难啊。 |
|
[如获至宝]
Self-Deleting Executables
by SingleSword posted on 2007-12-10 11:21:27 Weather: 阴 |
This is a subject that tends to come up every so often in the newsgroups, so I thought I'd write an article about the techniques I've collected to enable an executable to delete itself from disk (whilst running, that is). There is very little information on the web, and what information exists is also hard to find.
Why would you want a program to delete itself? The only good reason I know of is an un-install program that needs to remove an application, as well as itself in order to completely remove the application from disk. I'm sure there are other good reasons for self-deleting executables, but un-installation is probably the most common.
I know many different methods, each of which I will describe shortly. I must take this opportunity to mention that only one of these techniques has been developed by myself. Apart from the last method, I am presenting the same material described by Jeffrey Richter in his January 1996 MSJ column, titled "Win32 Q&A". Click here to read the original article. The rest of the techniques were originally developed by Gary Nebbett - or heavily influenced by his work. So, I hope no-one thinks I am ripping off other people's ideas because all these techniques have existed for years before I encountered them.
There used to be two methods for a program to delete itself - actually doing it from the same program, and forcing a separate program to do it on your behalf. When Windows XP came out the "self-deleting" executable became a part of history - it is no longer possible for a Windows program (which runs on any version of Windows) to delete itself. However there are lots of techniques which can achieve the same effect - the ones I know about are listed below.
Why the obvious doesn't work
If you try to run the following code, nothing will happen. TCHAR szFilePath[_MAX_PATH];
GetModuleFileName(NULL, szFilePath, _MAX_PATH);
DeleteFile(szFilePath);
The code above retrieves the full path to the current executable, and then tries to delete the file whilst running. This code will fail - because all 32bit versions of Windows (95, 98, ME, NT, 2000, XP etc) use a mechanism called memory-mapped files to load an executable image into memory.
When the Windows loader runs an executable, it opens the executable's disk file and maps that region of disk into memory, effectively loading the executable into memory. This disk file is kept open during the lifetime of the process, and is only closed when the process terminates. Because of this lock on the file, it is normally impossible to delete an executable file whilst it is running. Just run notepad.exe, then try to delete the notepad executable - it won't work.
The MoveFileEx method
I'm going to mention this technique even though it doesn't really solve our problem, because it is quite useful to know and can be handy in other situations. MoveFileEx(szExistingFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
The MoveFileEx API moves a file to a new location. When you pass NULL as the second parameter, this causes the file to be moved "nowhere", effectively deleting the file. Now, ordinarily this would fail if you tried this with the path to the current executable. However, if we specify MOVEFILE_DELAY_UNTIL_REBOOT in the dwFlags parameter, this tells Windows not to move (or delete) the file until the system is shutdown or rebooted.
There are a few problems with this technique. Firstly, you cannot remove the directory that the executable resides in. Second, the file is not deleted immediately - if your system doesn't get rebooted very often, then the file will stay around. But the biggest problem is that MoveFileEx is not implemented on Windows 95/98/ME. Today this is not really a problem and the MoveFileEx is the neatest, safest way for a program to delete itself.
The WININIT.INI method
Under Windows 95/98/ME, an application called WININIT.EXE runs each time the system is started. This application looks for a file called WININIT.INI. If this file exists, WININIT.EXE looks for a section called [Rename]. Each entry in the [Rename] section specifies a file rename operation which will occur (once) when time the system starts. This method is obviously very similar to the MoveFileEx method described above. [Rename]
NUL=c:\dir\myapp.exe
c:\dir\new.exe=c:\dir\old.exe
The filename to the left of the equal sign specifies the new name of the filename on the right. When NUL is used as the new filename, the file is deleted. This means that an application can write an entry into WININIT.INI, specifying NUL and the applications own full path.
You must be careful when writing an entry to the [Rename] section. You cannot use WritePrivateProfileString API call, because this function prevents any duplicate entries from occuring under the same section. This restriction would prevent there from being more than one "NUL=" entry. Therefore you must manually write any entry if you want to use this technique.
The Self-Deleting Batch File method
This is quite a well known method, and was documented in MSDN some time ago. This technique works on both Windows 95 and Windows NT. It works because MS-DOS batch files are able to delete themselves. To test this technique, create a small batch file containing the single command: del %0.bat
The batch file, when run, deletes itself and issues an error "The batch file cannot be found". This error is just a simple message, so it can be safely ignored. By itself this isn't too useful, but when modified to delete our executable it solves our problem, albeit in a rather forceful manner. Our executable will create a batch file (called C:\DelUs.bat) with the following content: :Repeat
del "C:\MYDIR\MYPROG.EXE"
if exist "MYPROG.EXE" goto Repeat
rmdir "C:\MYDIR"
del "\DelUS.bat"
This batch file repeatedly attempts to delete the specified file, and will run continuously consuming CPU until it succeeds. When the execuable has been deleted, the batch file then deletes itself.
The executable needs to spawn off the batch file using CreateProcess, and then should exit immediately. It would be a good idea to give the batch file's thread of execution a low priority so that it doesn't get much execution time until the original executable has terminated.
The sourcecode download at the top of this article contains the full code to this technique.
The COMSPEC method
This is a method kindly shared by Tony Varnas, who recently emailed me this snippet: BOOL SelfDelete()
{
TCHAR szFile[MAX_PATH], szCmd[MAX_PATH];
if((GetModuleFileName(0,szFile,MAX_PATH)!=0) &&
(GetShortPathName(szFile,szFile,MAX_PATH)!=0))
{
lstrcpy(szCmd,"/c del ");
lstrcat(szCmd,szFile);
lstrcat(szCmd," >> NUL");
if((GetEnvironmentVariable("ComSpec",szFile,MAX_PATH)!=0) &&
((INT)ShellExecute(0,0,szFile,szCmd,0,SW_HIDE)>32))
return TRUE;
}
return FALSE;
}
This method is very similar to the batch-file method (above) but is alot neater in its implementation. It works under all 32bit versions of Windows (95,98,ME,NT,2000,XP), as long as the COMSPEC environment variable is defined. This is always defined (by default) to be the full path to the operating system's command interpreter. For Windows 95, this is "command.exe". For Windows NT, this is "cmd.exe".
The function will only work if the executable has exited, so it is important to call this function and then exit immediately. It works by spawning a copy of the system's command interpreter, and asking it to perform the following command: del exepath >> NUL
This deletes the current executable, and pipes the output to NUL (no output). The shell process is created with a hidden window as well, so the whole process is invisible.
The DELETE_ON_CLOSE method
The CreateFile API call accepts several flags which affect how a file is created or opened. One of these flags, FILE_FLAG_DELETE_ON_CLOSE, specifies that the file will be deleted when the last handle to it is closed. The basis to this technique will be to run an executable with this flag set, so that when it exits, it is deleted automatically.
The first step is to create an empty file with the DELETE_ON_CLOSE flag specified. The exact binary content of the current executable file is then copied into this new file, in effect duplicating the executable on disk. A new process is then created (using the new executable file). This has the effect that the duplicate file's handle count is incremented. Also, when the new process was created, the full path of the current process was passed through the command-line argument.
Next, the current executable (which wants to delete itself) closes the file handle used to create the new process, and then exits. Now, the duplicate's file-handle count is decremented, but because CreateProcess incremented its handle count when it started, the file is not deleted.
At this point, the duplicate executable has started running. The PID specified on the command-line is used to open a handle to the original process. The duplicate waits for the original process to terminate, using WaitForSingleObject. When this call returns, the duplicate can call DeleteFile on the filename also specified through its command-line argument. The original executable (the one that wanted to delete itself) has been successfully deleted. This just leaves the duplicate copy, which exits normally. The duplicate's file-handle count drops to zero, the DELETE_ON_CLOSE flag comes into effect, and the duplicate file is deleted also.
It sounds a bit complicated, but it's not too difficult. Here's the steps one more time: [ Current process ]
1. Create a new file with FILE_FLAG_DELETE_ON_CLOSE.
2. Copy the current executable's content into the new file.
3. Create a new process with the duplicate executable:
4. Pass the current executable's full path and PID in the call to CreateFile.
5. Sleep for a short time to give the new process time to start.
6. Close the new file.
7. Exit current process.
[ Duplicate process ]
8. Wait for the process specified on command-line to die.
9. Delete file specified on command-line.
10. Exit duplicate process.
There are just a couple of technicalities to mention. First, when the "new" process is spawned, the "old" process must sleep for a short period, enough to let the Windows loader open the file and create the process (thus incrementing it's file count).
Second, the new process must wait until the old process terminates, which releases its file count.
Third, when the duplicate executable is created, it must also have the FILE_SHARE_DELETE flag specified, otherwise CreateProcess will fail, because it won't be able to open the file whilst we have it open with the DELETE_ON_CLOSE flag set.
Obviously this method will require careful coding, because the program must be written in such a way so that it can perform these dual tasks. The "new" executable must know that it's job is to delete the file specified on the command line, for instance.
It's a little messy, but it does work very well. In fact, the uninstall program that I wrote, which is included with the software you can download from this site, uses this very method. I've included an example program which demonstrates this technique.
An alternative method is to write a very small stand-alone executable, which it's sole task is to delete the file-name specified on it's command-line. This executable could then be imbedded as a "payload" to the executable which wants to delete itself. This payload would be created and executed in the same way as described above.
The Ultimate Self-Deleting Executable!
This inline assembly snippet is short and simple. I can't claim credit for this code - I found it posted on usenet some time ago. The author's name is Gary Nebbett, author of "Windows NT Native API Reference". Actually this technique was first published in Windows Developer Journal around 1996. #include <windows.h>
int main(int argc, char *argv[])
{
char buf[MAX_PATH];
HMODULE module;
module = GetModuleHandle(0);
GetModuleFileName(module, buf, MAX_PATH);
CloseHandle((HANDLE)4);
__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret
}
return 0;
}
This snippet ONLY works under Windows NT and 2000. As soon as you compile and run the above program, it just disappears from disk! It works because under NT and 2000 the OS keeps a usermode HANDLE reference to the memory-mapped file which backs the executable image on disk. This HANDLE always has a value of "4" under these OSs.
Unfortunately this gem only works under NT/2000, not XP or .NET Server. This is because these OSs no longer maintain a usermode HANDLE to the executable's memory-mapped file - this section object is only accessible in kernel using a pointer reference. So although this technique is incredibly slick (it is the only true self-deleting method) it is no longer as-is.
Now for Windows 9x!
Thanks must go to Tony Varnas again for some great detective work. He managed to unearth the following assembler snippet which works exactly like the snippet above, but this time for Windows 95,98,ME (tested on all three). #include <windows.h>
int main(int argc, char *argv[])
{
char buf[MAX_PATH];
HMODULE module;
module = GetModuleHandle(0);
GetModuleFileName(module, buf, MAX_PATH);
__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push FreeLibrary
ret
}
return 0;
}
Solution for XP+
After the original self-deleting technique Gary Nebbett posted a solution on Jan 19 2002 which works for XP. The following code should be packaged as a DLL which is callable from RunDLL32. The idea is that an external program (RunDLL32) is used which first waits for the original executable to finish. The DLL which is loaded into RunDLL then performs the original self-deleting trick. This is possible because the kernel maintains references to DLLs differently to the main executable. #include <windows.h>
#pragma comment(linker, "-export:CleanupA=_CleanupA@16?)
extern "C" void CALLBACK CleanupA(HWND, HINSTANCE, PSTR, int)
{
static MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(&mbi, &mbi, sizeof mbi);
PVOID module = mbi.AllocationBase;
CHAR buf[MAX_PATH];
GetModuleFileName(HMODULE(module), buf, sizeof buf);
__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push FreeLibrary
ret
}
}
The idea that an external program could be used to self-delete it's parent is what influenced me to develop the following technique which works for all versions of Windows, but does not require a separate DLL which is dropped to disk.
The Definitive Self Deleting Executable
I am pleased to present what I believe is the definitive self-deleting executable, for all versions of Windows.
Now this technique is complicated so I won't include the code here - please get it from the sourcecode zipfile (selfdel05.c). Instead I will describe how it works and the issues involved.
The neat thing about this technique is that the spawned child process never really executes (no windows ever appear) - only the "self-deleting" code in the child gets to execute. After the parent process terminates and is deleted, the child process terminates using ExitProcess, preventing anything further from happening. Effectively an arbitrary child-process is hijacked and coerced into deleting it's parent.
My first version of this technique (inside selfdelxp.c) used CreateRemoteThread to inject the code into the suspended child process. This was quite neat because the child never ran - only the injected thread with the self-deleting code ever executed. The downside to this technique is that it only ran on Windows-NT based platforms.
The latest version (selfdel05.c) does not use CreateRemoteThread to inject code into the child. It therefore works on all versions of Windows. The self-deleting code is injected into the spawned child by hijacking the primary thread of the process. The thread's stack is manipulated in such a way so that space is "allocated" on the stack - into which the self-deleting code is written. The instruction-pointer for the thread is then altered so that it points to the injected code on the thread's stack. When the child process (and primary thread) is resumed the code executes right off the stack, deleting the parent process, and then exits.
There are issues involved with this last technique. The first is the injection of code into an already running thread - this is not a desirable thing to do, but because the thread's "real" execution is never resumed (the process exits as soon as the parent is deleted) it seems like a viable way to do this.
The second issue involves the Win32 environment. When a child process is created in a suspended state the program has not started executing yet - there is still alot of Win32 environment setup that must be performed before the entry-point to the executable is called. So when we hijack this thread to do our bidding, we are doing so in an environment that is not yet fully initialized, and is not ready for Win32 API calls (it is still mid-way through executing some internel part of the OS!). The API calls that are made (WaitForSingleObject, DeleteFile etc) do however work - but this is not guaranteed in furture OS releases.
The exact same issue exists when you CreateRemoteThread into a process that was started as suspended - the OS hasn't yet finished intializing your process's environment before the remote thread starts to execute. This is why alot of Win32 API calls will fail (such as RemoveDirectory).
Conclusion
I've used this article to describe all the methods I know of to delete an executable whilst it is running. You can take your pick of the techniques, but the last method presented is currently the only one which works well for all versions of Windows. |
|
[如获至宝]
Hardcore Rap(硬核说唱)
by SingleSword posted on 2007-5-31 17:38:18 Weather: 小雨 |
| 硬核说唱涉及到好几种不同的音乐感受,其特征可以概括为对峙性和侵略性,它表现为:热情奔放的主题、猛烈强劲的鼓点、吵杂的取样与制作、或是其中任意几种的结合。硬核说唱是强硬的、体察民情的、激烈的、而且常常是威胁性的(不过威胁并不是总都存在,它也有幽默和生机勃勃的一面。)匪帮说唱(Gangsta rap)是与硬核说唱最普遍联系的一种风格,二者之间有很多的交叠,特别是在90年代的硬核说唱歌手之中,不过并不是所有的硬核说唱都是围绕着匪盗的主题。最早的硬核说唱出现在80年代后期的东海岸,那时候艺人们开始远离了派对节奏以及对扩音器技术的夸夸其谈,他们的音乐和语言开始反映这个布满沙砾的、粗糙而残酷的城市环境,通常它们也是在这个环境中被创作和被欣赏。在任何关于匪帮说唱的具体准则被制定出来之前,像New Yorks Boogie Down Productions和L.A.s Ice-T这样的艺术家们正把他们对街头生活的观察详尽地记录到磁带中;与此同时,Public Enemy混乱的声音拼贴正为录制能力设定新的标准,而N.W.A则以一种过多的大男子气展现着犹太人与匪徒们荒凉萧瑟的生活方式。在90年代初期,硬核说唱与西海岸的匪帮说唱本质上是同义的,直到1993年Wu-Tang Clan的出现,他们极少的、降到最低限的鼓点和萦绕着弦声与钢琴的小样成为被广泛效仿的风格。以它充满冲撞与猛力击打的唱片和城市街头恶棍坚毅不屈的精神,硬核说唱在90年代后半期成为说唱音乐里最受欢迎的混和音乐风格,现在它的主题混合了派对颂歌,匪盗们对金钱、性、暴力的执迷,以及偶尔的社会评论。像the Notorious B.I.G., DMX, 和Jay-Z这样的艺人们已经成为了白金销量的超级明星,而Master P也打着“源自匪帮的南方硬核”的牌子成为一支有利可图的商业力量,尽管他并没有制作出同样水平的混合热门单曲。 |
|
[如获至宝]
上周日曹庵摘草莓
by SingleSword posted on 2007-4-3 21:17:32 Weather: 大雪 |
继续贴照片
浙江版合影

四版合影

|
|
[如获至宝]
上周六的学友版版聚
by SingleSword posted on 2007-4-3 21:14:12 Weather: 晴 |
贴个照片
 |
|
[如获至宝]
自己写的Base64编码的Delphi实现
by SingleSword posted on 2006-8-15 16:50:52 Weather: 晴 |
unit untBase64;
interface
function Base64Encode(Source: string): string; function Base64Decode(Source: string): string;
implementation
uses Classes;
const Base64Codes: array [0..63] of Char = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/');
type TDecodeSec = packed record Bytes: array [0..2] of Byte; end;
TEncodeSec = packed record Bytes: array [0..3] of Byte; end;
procedure DeSecToEnSec(const DeSec: TDecodeSec; var EnSec: TEncodeSec); begin Move(DeSec, EnSec, SizeOf(DeSec));
with EnSec do begin Bytes[3] := Bytes[2] and $3F; Bytes[2] := (Bytes[2] shr 6) or ((Bytes[1] and $F) shl 2); Bytes[1] := (Bytes[1] shr 4) or ((Bytes[0] and $3) shl 4); Bytes[0] := Bytes[0] shr 2; end; end;
procedure TranslateEnSec(var EnSec: TEncodeSec); function Translate(const B: Byte): Byte; begin Result := 0; case Char(B) of 'A'..'Z': Result := B - Ord('A'); 'a'..'z': Result := B - Ord('a') + 26; '0'..'9': Result := B - Ord('0') + 52; '+': Result := 62; '/': Result := 63; end; end; begin EnSec.Bytes[0] := Translate(EnSec.Bytes[0]); EnSec.Bytes[1] := Translate(EnSec.Bytes[1]); EnSec.Bytes[2] := Translate(EnSec.Bytes[2]); EnSec.Bytes[3] := Translate(EnSec.Bytes[3]); end;
procedure EnSecToDeSec(const EnSec: TEncodeSec; var DeSec: TDecodeSec); begin DeSec.Bytes[0] := (EnSec.Bytes[0] shl 2) or (EnSec.Bytes[1] shr 4); DeSec.Bytes[1] := (EnSec.Bytes[1] shl 4) or (EnSec.Bytes[2] shr 2); DeSec.Bytes[2] := (EnSec.Bytes[2] shl 6) or EnSec.Bytes[3]; end;
function Base64Encode(Source: string): string; var Len: Integer; Sections: Integer; i: Integer; ss: TStringStream; DeSec: TDecodeSec; EnSec: TEncodeSec; Left: Integer; begin try Len := Length(Source); Sections := Len div 3; Left := Len mod 3;
if (Len mod 3) = 0 then SetLength(Result, Sections * 4) else SetLength(Result, (Sections + 1) * 4);
FillChar(Result[1], Length(Result), '=');
ss := TStringStream.Create(Source); try ss.Seek(0, soBeginning);
for i := 0 to Sections - 1 do begin ss.ReadBuffer(DeSec, 3); DeSecToEnSec(DeSec, EnSec);
Result[i * 4 + 1] := Base64Codes[EnSec.Bytes[0]]; Result[i * 4 + 2] := Base64Codes[EnSec.Bytes[1]]; Result[i * 4 + 3] := Base64Codes[EnSec.Bytes[2]]; Result[i * 4 + 4] := Base64Codes[EnSec.Bytes[3]]; end;
if Left > 0 then begin FillChar(DeSec, SizeOf(DeSec), 0);
ss.Read(DeSec, Left); DeSecToEnSec(DeSec, EnSec);
i := Sections * 4 + 1; if Left = 1 then begin Result[i] := Base64Codes[EnSec.Bytes[0]]; Result[i + 1] := Base64Codes[EnSec.Bytes[1]]; end else begin Result[i] := Base64Codes[EnSec.Bytes[0]]; Result[i + 1] := Base64Codes[EnSec.Bytes[1]]; Result[i + 2] := Base64Codes[EnSec.Bytes[2]]; end; end; finally ss.Free; end; except end; end;
function Base64Decode(Source: string): string; var ss: TStringStream; DeSec: TDecodeSec; EnSec: TEncodeSec; Len: Integer; Sections: Integer; i: Integer; Left: Integer; begin try Len := Length(Source); Sections := Len div 4; if Sections = 0 then Exit;
if Source[Len - 1] = '=' then begin SetLength(Result, Sections * 3 - 2); Left := 1; end else if Source[Len] = '=' then begin SetLength(Result, Sections * 3 - 1); Left := 2; end else begin SetLength(Result, Sections * 3); Left := 0; end;
ss := TStringStream.Create(Source); try ss.Seek(0, soBeginning);
for i := 0 to Sections - 2 do begin ss.Read(EnSec, SizeOf(EnSec)); TranslateEnSec(EnSec); EnSecToDeSec(EnSec, DeSec);
Move(DeSec, Result[i * 3 + 1], SizeOf(DeSec)); end;
ss.Read(EnSec, SizeOf(EnSec)); TranslateEnSec(EnSec); EnSecToDeSec(EnSec, DeSec);
i := (Sections - 1) * 3 + 1;
case Left of 0: begin Result[i] := Char(DeSec.Bytes[0]); Result[i + 1] := Char(DeSec.Bytes[1]); Result[i + 2] := Char(DeSec.Bytes[2]); end; 1: Result[i] := Char(DeSec.Bytes[0]); 2: begin Result[i] := Char(DeSec.Bytes[0]); Result[i + 1] := Char(DeSec.Bytes[1]); end; end; finally ss.Free; end; except end; end;
end.
|
|
[郁闷心情]
资料全丢了!!!!!
by SingleSword posted on 2006-8-12 20:37:14 Weather: 晴 |
| NNDX,今天用PMagicNT合并分区,结果倒腾了一天,分区没并成,却把数据全丢了。 |
|
[如获至宝]
用API求文件MD5的C++代码
by SingleSword posted on 2006-8-1 17:09:56 Weather: 小雨 |
#define MD5_BUFSIZE 1024 #define MD5_LEN 16 #define MD5_STRLEN 32
BOOL FileMD5(LPCTSTR lpszFileName, TCHAR szMD5[]) { HANDLE hFile = NULL; if ((hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ) == INVALID_HANDLE_VALUE) { return FALSE; }
HCRYPTPROV hProv = 0; if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) { CloseHandle(hFile); return FALSE; }
HCRYPTHASH hHash = 0; if (CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash) == FALSE) { CloseHandle(hFile); CryptReleaseContext(hProv, 0);
return FALSE; }
BYTE rgbFile[MD5_BUFSIZE]; BOOL bResult = FALSE; DWORD cbRead = 0;
while (bResult = ReadFile(hFile, rgbFile, MD5_BUFSIZE, &cbRead, NULL)) { if (cbRead == 0) { break; }
if (CryptHashData(hHash, rgbFile, cbRead, 0) == FALSE) { CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CloseHandle(hFile);
return FALSE; } }
if (bResult == FALSE) { CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CloseHandle(hFile);
return FALSE; }
DWORD cbHash = MD5_LEN; BYTE rgbHash[MD5_LEN];
bResult = CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0);
if (bResult == TRUE) { CHAR rgbDigits[] = "0123456789ABCDEF";
for (int i = 0; i < cbHash; ++i) { BYTE b = rgbHash[i]; szMD5[i * 2] = rgbDigits[b >> 4]; szMD5[i * 2 + 1] = rgbDigits[b % 16]; }
szMD5[MD5_STRLEN] = '\0'; }
CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); CloseHandle(hFile);
return bResult; }
|
|
[极品垃圾]
通过QQWry.dat查询IP信息的Delphi代码
by SingleSword posted on 2006-6-5 19:55:34 Weather: 大雪 |
unit untIPSearcher;
interface
type TIPSearcher = class private FBuffer: Pointer; procedure ReadString(Offset: Cardinal; var Area, Detail: String); function ReadSingleStr(Offset: Cardinal): String; procedure ReadString1(Offset: Cardinal; var Area, Detail: String); public constructor Create; destructor Destroy; override; procedure LoadIPFile(const FileName: String); procedure SearchIP(const IPStr: String; var Area, Detail: String); end;
implementation
uses Classes, SysUtils, Dialogs, Windows;
{ TIPSearcher }
function IPToCardinal(const IPStr: String): Cardinal; var TmpA: Integer; TmpB: Integer; TmpC: Integer; TmpD: Integer; p: Integer; TmpStr: String; begin TmpStr := IPStr;
p := Pos('.', TmpStr); TmpA := StrToInt(Copy(TmpStr, 1, p - 1));
TmpStr := Copy(TmpStr, p + 1, Length(TmpStr) - p); p := Pos('.', TmpStr); TmpB := StrToInt(Copy(TmpStr, 1, p - 1));
TmpStr := Copy(TmpStr, p + 1, Length(TmpStr) - p); p := Pos('.', TmpStr); TmpC := StrToInt(Copy(TmpStr, 1, p - 1));
TmpStr := Copy(TmpStr, p + 1, Length(TmpStr) - p); TmpD := StrToInt(TmpStr);
Result := ((TmpA and $FF) shl 24) or ((TmpB and $FF) shl 16) or ((TmpC and $FF) shl 8) or (TmpD and $FF); end;
constructor TIPSearcher.Create; begin FBuffer := nil; end;
destructor TIPSearcher.Destroy; begin if FBuffer <> nil then FreeMem(FBuffer);
inherited; end;
procedure TIPSearcher.LoadIPFile(const FileName: String); var ms: TMemoryStream; begin if FBuffer <> nil then FreeMem(FBuffer); ms := TMemoryStream.Create; ms.LoadFromFile(FileName); GetMem(FBuffer, ms.Size); ms.Seek(0, soBeginning); ms.ReadBuffer(FBuffer^, ms.Size); end;
function TIPSearcher.ReadSingleStr(Offset: Cardinal): String; var Tmp: Cardinal; begin case PByte(Offset + Cardinal(FBuffer))^ of 0: begin Result := ''; Exit; end; 2: begin Tmp := PCardinal(Offset + Cardinal(FBuffer))^; Tmp := Tmp shr 8; Result := ReadSingleStr(Tmp); end; else Result := PChar(Offset + Cardinal(FBuffer)); end; end;
procedure TIPSearcher.ReadString(Offset: Cardinal; var Area, Detail: String); var Tmp: Cardinal; Str: PChar; begin case PByte(Offset + Cardinal(FBuffer))^ of 0: begin Area := '未知数据'; Detail := ''; Exit; end; 1: begin Tmp := PCardinal(Offset + Cardinal(FBuffer))^; Tmp := Tmp shr 8; ReadString1(Tmp, Area, Detail); end; 2: begin Tmp := PCardinal(Offset + Cardinal(FBuffer))^; Tmp := Tmp shr 8; Area := ReadSingleStr(Tmp); Tmp := Offset + 4; Detail := ReadSingleStr(Tmp); end; else Area := PChar(Offset + Cardinal(FBuffer)); Tmp := Offset + Length(Area) + 1; Detail := ReadSingleStr(Tmp); end; end;
procedure TIPSearcher.ReadString1(Offset: Cardinal; var Area, Detail: String); var Tmp: Cardinal; begin case PByte(Offset + Cardinal(FBuffer))^ of 0: begin Area := '未知数据'; Detail := ''; Exit; end; 2: begin Tmp := PCardinal(Offset + Cardinal(FBuffer))^; Tmp := Tmp shr 8; Area := ReadSingleStr(Tmp); Tmp := Offset + 4; end else Area := PChar(Offset + Cardinal(FBuffer)); Tmp := Offset + Length(Area) + 1; end;
Detail := ReadSingleStr(Tmp); end;
procedure TIPSearcher.SearchIP(const IPStr: String; var Area, Detail: String); var Cursor: Cardinal; Ptr: Pointer; IPStart: Cardinal; IPEnd: Cardinal; IPCardinal: Cardinal; BytePtr: PByte; Min: Integer; Max: Integer; Cur: Integer; Found: Boolean; begin IPCardinal := IPToCardinal(IPStr); IPStart := PCardinal(FBuffer)^; IPEnd := PCardinal(4 + Cardinal(FBuffer))^; Min := 0; Max := (IPEnd - IPStart) div 7; Found := False;
while Min <> Max do begin Cur := (Min + Max) div 2; Cursor := Cur * 7 + IPStart;
if IPCardinal < PCardinal(Cursor + Cardinal(FBuffer))^ then Max := Cur else if IPCardinal > PCardinal(Cursor + Cardinal(FBuffer))^ then Min := Cur + 1 else begin Min := Cur; Max := Cur; Found := True; end; end;
Cursor := Min * 7 + IPStart; if Found then Cursor := Cursor + 3 else Cursor := Cursor - 4;
Cursor := PCardinal(Cursor + Cardinal(FBuffer))^ shr 8 + 4; ReadString(Cursor, Area, Detail); end;
end.
|
|
[莫名奇妙]
QQ上高速
by SingleSword posted on 2006-5-8 16:09:47 Weather: 晴 |
五一开着QQ跑长途
合肥->上海->嘉兴->乌镇->杭州->上海->无锡(寻找丢失的钱包)->合肥
可把QQ累坏了哦~~~~ |
|
[如获至宝]
今天在做自画控件的时候,碰到的一个画不出来的问题
by SingleSword posted on 2006-4-17 20:07:43 Weather: 大雪 |
发现经常会画不出来,查原因,是设了DoubleBuffered := True的原因。
跟踪VCL源码,发现是在TWinControl.WMPaint里,if not FDoubleBuffered or (Message.DC <> 0) then这一句判断的时候 Message.DC=0,还不知道为什么有的时候会为0,但是根据VCL的特性,这个应该就是本控件的DC。
于是在控件基类的WMPaint里这样写,问题解决。
procedure TSkinControl.WMPaint(var Message: TWMPaint); var DC: HDC; begin DC := 0; if Assigned(Parent) and (Message.DC = 0) then begin DC := GetDC(Handle); Message.DC := DC; end;
inherited;
if DC <> 0 then ReleaseDC(Handle, DC); end;
问题尚未深究,不保证不出问题,先用着再说,怕忘了,记录一笔。 |
|
[如获至宝]
发两张草莓PP
by SingleSword posted on 2006-3-27 14:41:30 Weather: 大雪 |
|
[如获至宝]
VCL中透明控件的实现(此实现方法不能处理控件重叠的情况)
by SingleSword posted on 2006-2-28 18:11:02 Weather: 大雪 |
procedure TXControl.Paint; var SaveIndex: Integer; MemDC: HDC; Bitmap: HBITMAP; i: Integer; begin inherited;
if Assigned(Parent) then begin MemDC := CreateCompatibleDC(Canvas.Handle); Bitmap := CreateCompatibleBitmap(Canvas.Handle, Width, Height); try SelectObject(MemDC, Bitmap);
SaveIndex := SaveDC(MemDC); SetViewportOrgEx(MemDC, -Left, -Top, nil); IntersectClipRect(MemDC, Left, Top, Left + Width, Top + Height); SendMessage(Parent.Handle, WM_ERASEBKGND, MemDC, 0); SendMessage(Parent.Handle, WM_PAINT, MemDC, 0); RestoreDC(MemDC, SaveIndex);
SaveIndex := SaveDC(Canvas.Handle); for i := 0 to ControlCount - 1 do begin if (Controls[i].Visible or (csDesigning in Controls[i].ComponentState) and not (csNoDesignVisible in Controls[i].ControlStyle)) then begin ExcludeClipRect(Canvas.Handle, Controls[i].Left, Controls[i].Top, Controls[i].Left + Controls[i].Width, Controls[i].Top + Controls[i].Height); end; end; BitBlt(Canvas.Handle, 0, 0, Width, Height, MemDC, 0, 0, SRCCOPY); RestoreDC(Canvas.Handle, SaveIndex); finally DeleteObject(Bitmap); DeleteDC(MemDC); end; end; end;
|
|
[如获至宝]
最近搞了辆QQ来开
by SingleSword posted on 2006-2-17 13:42:20 Weather: 大雪 |
这周一买了辆绿色QQ,还不错,嘿嘿。
我真是艺高人胆大,从驾校出来后第一次自己真正开车, 居然直接就上长江路,太猛了我。
刚开始容易熄火,现在基本不熄啦,帅!
VDAY晚上开着车带MM出去high,真是爽,嘿嘿,有车就是好。
NNDX,前天晚上居然抛锚了,弄了半天是电瓶挂掉,郁闷啊郁闷,200块大洋就酱米了。 |
|
[如获至宝]
根据浏览器句柄得到IHTMLDocument2的指针
by SingleSword posted on 2006-1-11 9:37:27 Weather: 大雪 |
procedure GetDocumentPtrFromWnd(Wnd: HWND; var pDoc: IHTMLDocument2); type TObjectFromLResult = function(LRESULT: LRESULT; const IID: TGUID; wParam: WPARAM; out PObject): HRESULT; stdcall; var GetDocPtr: TObjectFromLResult; hModule: THandle; Msg: Cardinal; lRes: Cardinal; begin hModule := LoadLibrary('OLEACC.DLL'); try if hModule <> 0 then begin GetDocPtr := GetProcAddress(hModule, 'ObjectFromLresult'); if @GetDocPtr <> nil then begin Msg := RegisterWindowMessage('WM_HTML_GETOBJECT'); SendMessageTimeOut(Wnd, Msg, 0, 0, SMTO_ABORTIFHUNG, 1000, lRes); if GetDocPtr(lRes, IID_IHTMLDocument2, 0, pDoc) <> S_OK then begin pDoc := nil; end; end; end; finally FreeLibrary(hModule); end; end; |
|
[如获至宝]
Delphi中创建ActiveX控件
by SingleSword posted on 2006-1-4 21:32:44 Weather: 小雪 |
第一次干这种事,记录一下。
先新建一个ActiveX Library,再建一个TypeLibrary,然后添加相应的Interface及CoClass,关键在于,要给Interface一个实现。
新建一个类,从TActiveXControl继承,并实现之前建的Interface,要在initialization里加上如下代码:
TActiveXControlFactory.Create( ComServer, TXXControl, TWinControl, Class_XXControl, 1, '', 0, tmApartment);
这样就可以了。 |
|
[郁闷心情]
原来郁闷也可以让人发飙
by SingleSword posted on 2006-1-2 23:57:57 Weather: 晴 |
郁闷,很郁闷,狂郁闷,暴郁闷~~~~~~ 郁闷到掉渣~~~~~~~~~
上浩方虐鸟~~~~ 居然在TTR这种鬼图上日了一个UD, APM飙升至196,从头到尾压着打。 |
|
[如获至宝]
生平第一次去看演唱会
by SingleSword posted on 2006-1-2 2:22:34 Weather: 晴 |
| 见到靓颖了,聆听了现场版海豚音,实在太HIGH了。 |
|
[如获至宝]
今天心情很好。
by SingleSword posted on 2005-12-27 23:42:50 Weather: 晴 |
晚上学车的时候,起步平稳,没空油声也没有突突突,不时地能顾及到后视镜,超车N辆,换档自如,遇不平路面处理过度自然。
木哈哈哈哈哈,偶真是天才啊~~~~~~ |
|
[如获至宝]
VCL中实现有句柄控件底色透明的方法(不完美版)
by SingleSword posted on 2005-12-20 11:34:33 Weather: 大雪 |
要让一个有句柄的控件底色透明,初步想法,是在控件的WM_ERASEBKGND的时候,直接返回什么都不做,发现不行,框框里留下的是桌面上的东东。
后google后找到一种办法,在Paint的时候代码如下:
SaveIndex := SaveDC(DC); { 设置自己DC的视点至(-Left, -Top)处,对应于父控件的(0, 0) } SetViewportOrgEx(DC, -Left, -Top, @pt); { 将自身所在位置加入Clip区 } IntersectClipRect(DC, Left, Top, Left + Width, Top + Height); { 下面两句强制刷新父控件,并用自己的DC取代父控件的DC,使得父控件能刚好把自己所在位置的底图画在自己的DC上 } SendMessage(Parent.Handle, WM_ERASEBKGND, DC, 0); SendMessage(Parent.Handle, WM_PAINT, DC, 0); SetViewportOrgEx(DC, pt.X, pt.Y, nil); RestoreDC(DC, SaveIndex);
这种做法有几个缺点: 1、VCL中对WM_PAINT的封装,使用了wParam来传递DC,故使得SendMessage(Parent.Handle, WM_PAINT, DC, 0);有效,或是标准处理方法根据Handle来得到需要Paint的DC,就不行了; 2、若是在父控件中使用直接处理WM_PAINT的方法重绘,则上述操作无效,具体原因正在研究中 |
|
[莫名奇妙]
第一次用Delphi在调WebService的时候加Soap头验证
by SingleSword posted on 2005-12-19 11:45:56 Weather: 晴 |
不是什么高深的东西,不过第一次干,记录一下
procedure ws: WebServiceSoap; H: XXXHeader; begin ws := GetWebServiceSoap; H := XXXHeader.Create; try H.Username := 'xxx'; H.Password := MD5('xxx'); (ws as ISOAPHeaders).Send(H); ws.someMethod; finally H.Free; ws := nil; end; end; |
|
[郁闷心情]
今天又发现一个变态的事情,暴郁闷
by SingleSword posted on 2005-12-18 0:08:25 Weather: 大雪 |
在给Control SetWindowRgn的时候发现, 如果该Control的Parent的Parent改变了的话, 该Control的Region又变为默认的了。
猜测如果Parent改变,Region也会变,但是因为太忙,今天没有时间试。 |
|
[如获至宝]
自绘控件内部的标准控件的子控件不被刷新的问题解决
by SingleSword posted on 2005-12-15 14:56:00 Weather: 晴 |
标题很拗口,解释一下,免得以后自己也看不懂。
自绘控件TX,内部放一个TForm,再在这个TForm内放一个控件,比如TButton。当自绘控件因为处理鼠标事件而重绘的时候发现TForm被正常刷新了,而TForm内部的控件没有被刷新。
初步解决办法,在Form重绘的时候,强制刷新内部的控件,在TForm的Paint事件里写如下代码:
procedure TForm1.FormPaint(Sender: TObject); var i: Integer; DC: HDC; begin for i := 0 to ControlCount - 1 do begin if Controls[i] is TWinControl then begin DC := GetDC(TWinControl(Controls[i]).Handle); Controls[i].Perform(WM_PAINT, DC, 0); ReleaseDC(TWinControl(Controls[i]).Handle, DC); end; end; end;
但是这个办法并不是最完美的,因为这样要并没有普适性,更好的办法正在研究中……
果然不完美,刚刚试验,当子控件内部还有子控件的时候,子控件中的子控件还是没有刷新。 |
|
[如获至宝]
VCL中DoubleBuffered属性以及TWinControl的WMPaint的研究
by SingleSword posted on 2005-12-14 9:23:56 Weather: 晴 |
前几天做的自绘控件,直接从TWinControl继承下来,并且自己处理WM_PAINT消息,发现有一个很严重的问题,在自绘控件上放标准控件的时候,随着自绘控件的刷新,标准控件没有被刷新。初步猜测是自绘控件刷新的时候,把整个区域按自己的意愿画了。想到的解决办法,就是在自绘的时候,把子控件的Rect从自己的DC里Clip掉。
昨天晚上查看VCL源码,仔细研究了一下TWinControl处理WM_PAINT消息的方法,分析如下:
procedure TWinControl.WMPaint(var Message: TWMPaint); var DC, MemDC: HDC; MemBitmap, OldBitmap: HBITMAP; PS: TPaintStruct; begin if not FDoubleBuffered or (Message.DC <> 0) then begin if not (csCustomPaint in ControlState) and (ControlCount = 0) then inherited else PaintHandler(Message); end else begin DC := GetDC(0); MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom); ReleaseDC(0, DC); MemDC := CreateCompatibleDC(0); OldBitmap := SelectObject(MemDC, MemBitmap); try DC := BeginPaint(Handle, PS); Perform(WM_ERASEBKGND, MemDC, MemDC); Message.DC := MemDC; WMPaint(Message); Message.DC := 0; BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY); EndPaint(Handle, PS); finally SelectObject(MemDC, OldBitmap); DeleteDC(MemDC); DeleteObject(MemBitmap); end; end; end;
先看if语句:
{ 当未设DoubleBuffered或是控件有自身的DC的时候 } if not FDoubleBuffered or (Message.DC <> 0) then begin { 当非自画并且没有子控件的时候,调用父类的处理函数 } if not (csCustomPaint in ControlState) and (ControlCount = 0) then inherited else PaintHandler(Message); { 关键就在这里,一般情况下,直接调用PaintHandler } end
再找到PaintHandler函数,如下:
procedure TWinControl.PaintHandler(var Message: TWMPaint); var I, Clip, SaveIndex: Integer; DC: HDC; PS: TPaintStruct; begin DC := Message.DC; if DC = 0 then DC := BeginPaint(Handle, PS); try { 当没有子控件的时候,调用PaintWindow } if FControls = nil then PaintWindow(DC) else begin { 可以看到,下面的代码是针对有子控件的情况处理 } SaveIndex := SaveDC(DC); try Clip := SimpleRegion; { 遍历子控件 } for I := 0 to FControls.Count - 1 do with TControl(FControls[I]) do { 当子控件Visible并且处于非设计期或是设计期不隐藏并且控件不透明, 则调用ExlucdeClipRect这个API把子控件的Rect从当前控件中Clip掉 } if (Visible and (not (csDesigning in ComponentState) or not (csDesignerHide in ControlState)) or ((csDesigning in ComponentState) and not (csDesignerHide in ControlState)) and not (csNoDesignVisible in ControlStyle)) and (csOpaque in ControlStyle) then begin Clip := ExcludeClipRect(DC, Left, Top, Left + Width, Top + Height); if Clip = NullRegion then Break; end; if Clip <> NullRegion then PaintWindow(DC); finally RestoreDC(DC, SaveIndex); end; end; PaintControls(DC, nil); finally if Message.DC = 0 then EndPaint(Handle, PS); end; end;
从上面的函数可知,TWinControl在自绘的时候,会自动把可视的子控件所占的区域从DC中去掉,再回到PaintHandler中,发现csCustomPaint这个状态,是在什么时候设置的?在Controls.pas里找来找去,发现,这是在子类TCustomControl里用到的,查看TCustomControl的WMPaint函数,就可以看到
procedure TCustomControl.WMPaint(var Message: TWMPaint); begin Include(FControlState, csCustomPaint); inherited; Exclude(FControlState, csCustomPaint); end;
很简单的代码,但是很明确地告诉了一个信息,TCustomControl就是专门用来做自绘的,明白了这样一个原理,就毫不犹豫地把我的控件改成从TCustomControl继承了。
再来看TWinControl.WMPaint的else部分,这里面处理了DoubleBuffered的情况,想看一下VCL究竟是怎么来做DoubleBuffer的:
DC := GetDC(0); MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom); ReleaseDC(0, DC); MemDC := CreateCompatibleDC(0); OldBitmap := SelectObject(MemDC, MemBitmap); try DC := BeginPaint(Handle, PS); Perform(WM_ERASEBKGND, MemDC, MemDC); Message.DC := MemDC; WMPaint(Message); Message.DC := 0; BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY); EndPaint(Handle, PS); finally SelectObject(MemDC, OldBitmap); DeleteDC(MemDC); DeleteObject(MemBitmap); end;
可以看到在这段代码里,使用了桌面DC作为双缓冲的MemBitmap,来作为WM_ERASEBKGND时MemDC的位图刷,然后再将MemDC拷贝到当前DC上,所以当设DoubleBuffered为True并没有处理WM_PAINT的时候,自绘控件看起来就是全透明的。也就是说,其实这个DoubleBuffered属性并不是真正意义上的完全的双缓冲,而只是迈出了双缓冲的第一步——在重绘时不刷新背景。其实这个有很多方法可以实现,比如可以把窗体类的背景刷设成nil。 |
|
[莫名奇妙]
今天下午好惊险
by SingleSword posted on 2005-11-14 20:32:36 Weather: 小雨 |
辛辛苦苦写了一下午的程序,给树控件加上了拖放功能, 居然一个误操作,把本应该commit的东东去revert了。
幸好我手快,又因为下午的内容比较单一,在半小时内又 重新敲了回来,天啊,吓得小心肝扑通扑通乱跳。 |
|
[如获至宝]
准备再试一次ATC,给自己加油,列了准备要素如下
by SingleSword posted on 2005-9-6 1:07:41 Weather: 晴 |
1 C++基础(面向对象与面向过程区别,虚函数) 2 树(三种遍历的无递归实现) 3 图(最短路径问题) 4 各种排序、查找算法,效率问题 5 链表环检查 6 COM 7 DotNet Reflection 8 XML 9 进程与线程(区别,各自好处) 10 设计模式 11 测试(冰箱、电梯) 12 状态机 13 英文自我介绍,简历介绍 |
|
[如获至宝]
从ASP过渡到ASP.net遗留的二十大积习
by SingleSword posted on 2005-8-17 10:27:31 Weather: 大雪 |
前几天在google上搜东西,找到这样一篇文章,很不错的样子。
在技术更新的进程中, 仍然有一些人死抱着已经过了气的东西不放. 也有一些人虽然进入到新的世界, 但仍摆脱不了陈旧的习惯. 我没有用”陋习”这个词, 因为我对这个词也非常反感.
新技术应该有新技术的做法, 进入ASP.NET的世界, 就应该把以往的习惯改正, 全新的进入新的世界.
以下列举的都是错误的做法, 请不要误以为是推荐的做法而进行推广:
1. 使用server side include给ASPX引入共同的页面构图. 在ASP.NET的机制下, 应使用ASCX(web user control)来实现. ASCX提供了更多可控制接口. 并且更重要的是, ASCX是一个类. 一个实实在在的类. 可以全面控制它.
2.不使用web.config web.config提供了非常丰富的配置管理接口. 是一个应用程序最核心的部分. 但是很多人的web.config往往是空的. 或者就从来没有修改过.
3.使用Response.Write向前端输出消息 ASP.NET平台下的Response和ASP的Response有很大的不同. 虽然表示同一含义, 但用法上已经大不相同. Response.Write的内容只会输出到页的最前端. 向前端输出消息的正确方法是使用PlaceHolder.
4.使用一系列session管理用户连接状态 这种方法在ASP里被滥用. 在ASP.NET环境下, 正确的做法应该是设计一个类. 结构化地保存数据. 将对session或者cookie的访问封装起来.
5.使用session验证身份 这几乎是通病. ASP.NET提供了一组用于用户身份验证的API. 类型是forms验证或者windows验证. 这一点quick start有一节讲解得很清楚. 可以绝大部分人还是依靠给session赋值来保持用户身份验证状态.
6.使用Response.Redirect重定向页 这一点在必要的时候可以使用. 但不可滥用. 事实证明滥用重定向将导致逻辑上的严重混乱. 这是在以页为程序单元的时候的做法. 使用front controller模式将使用户的操作逻辑集中起来]
7.使用太多ASPX页 ASP环境下的程序单元只有*.asp页, ASP.NET可不是这样, 还有后端的类库, ASCX等等. 应将业务逻辑分别集中在不同的单元, 而不应该一项操作使用一个ASPX. 更多时候ASPX将做为ASCX或者custom control的容器而管理页内逻辑. ASPX重用ASCX的同时, ASPX也做为统一的页构图重用.
8.在多个逻辑单元之间复制代码并修改相应逻辑 重用. 重用. 重用. 处理此类问题的原则是不出现任何相同或相似的过程. 如果你用上面的方法, 一旦出现重大逻辑更改, 带来的结果将是灾难性的.
9.害怕使用DataSet. 很多人被DataSet吓坏了. 认为”肯定”影响性能. 但连最初的尝试都不敢. 他们总认为他们的产品一定重大, 设计上应该”慎重”. 他们往往使用ArrayList或者设计低级的类来保存集合数据. 进行艰难的数据倒入工作.
10.对“性能”过多注意. 对ASP.NET ViewState的机制特别不满. 或者总是挖空心思迫害人家. 反倒把自己弄得很累. 如果在对付ViewState的同时多注意少连几次数据库也许更文明些.
11.应用程序根目录很乱. ASP.NET是开发项目. 不是网站. 应该把不同的资源分类放置. 例如把所有静态资源(样式表, 脚本, 图像)组织到一起. 甚至可以写一组API来管理他们. ASPX应该放在一起. ASCX应该放在一起. .*.cs呢? 应该把他们放到另外一个project里.
12.不厌其烦的写访问数据库的过程 应该把这工作交给DataAccess Application Block. 你自己还要开关connection, 何苦呢.
13.自己写的东西最靠得住. 事实往往正好相反. 多注意使用人家写好的产品. 又不收你钱, 何苦那么爱面子呢.
14. 胡乱命名ASPX文件名 这是最让人痛苦的了. ASPX文件名不仅需要容易识别. 还应该遵循一定规则. 因为behind每个ASPX都会有一个同名的类, 想象一下, 多难受. 另外大部分人不知道管理自己的项目的name space. 让人好像看到一本帐一样.
15.从来不作继承或派生 一些具有相同行为的类, 应该从公共的基类派生出来. 实际意义上, 我们的ASPX应该有一个基类PageBase. 因为总有一些公共的特性需要抽象出来.
16.零property 他们的类(ASPX所对应)里只有private method. 不公开自己的任何秘密. 可以这一定是JAVA的遗老干的事.
17. 零ASCX 不用说, 他还没学会ASP.NET
18.使用DreamWeaver“画“ASPX 这批人是美工. 甚至有一些人在非常陶醉地讨论如何更好地“整合“ DreamWeaver和Visual Studio.
19.只熟悉System.Web.UI.WebControl和System.Data.SqlClient应该还有一些值得熟悉的类库.
20.零注释 这些都是心里很明白的快手. 一任IDE生成的缺省注释横在那里不管.
21.零事件 对“事件驱动“一无所知. 只知道在Page_Load()里写过程. 或者双击一个按钮写Xxx_Clock()过程. 在他们的程序里看不到event和delegate.
|
|
[郁闷心情]
晕倒,又丢钱包。
by SingleSword posted on 2005-6-13 10:04:46 Weather: 晴 |
|
[如获至宝]
在smth上看到的,觉得有道理。
by SingleSword posted on 2005-6-1 12:48:54 Weather: 大雪 |
有人对毕业生提出十一项人生建议,来与毕业同学共勉之:
一、人生是不公平的,习惯接受吧。 二、这个世界并不在乎你的自尊,只在乎你做出来的成绩,然后再去强调你的感受。 三、你不会一离开学校就有百万年薪、你不会马上就是拥有公司配属手机的副总裁,二者你都必须靠努力赚来。 四、如果你觉得你的老板很凶,等你做了老板就知道,老板是没有工作任期保障的。 五、在快餐店打工并不可耻,你的祖父母对煎汉堡有不同的看法:机会。 六、如果你一事无成,不是你父母的错,所以不要对自己犯的错发牢骚,从错误中去学习。 七、在你出生前,你的父母并不像现在这般无趣,他们变成这样是因为忙着付你的开销、洗你的衣服、听你吹嘘你有多了不起。所以在你拯救被父母这代人破坏的热带雨林前,先整理一下自己的房间吧。 八、在学校里可能有赢家输家,在人生中却还言之过早。学校会不断给你机会找到正确答案,真实人生中却完全不是这么回事。 九、人生不是学期制,人生没有寒暑假,没有哪个雇主有兴趣帮你寻找自我。请用自己的时间来做这件事吧。 十、电视上演的并非真实人生。真实人生中每人都要离开咖啡馆去上班。 十一、对书呆子好一点,你未来很可能就为其中一个工作。 |
|
[如获至宝]
Delphi里调用WebService时,阻塞现象的解决
by SingleSword posted on 2005-3-30 10:05:43 Weather: 晴 |
把调用放在线程里,发现只有Synchronize才能调用,但是这样又把主线程 给阻塞了,经研究发现,不用Synchronize,手工裸调COM的初始化就OK,如下:
CoInitialize(nil); FDetail := GetSearchSoap.GetEntDetail(FCID); CoUnInitialize;
|
|
[莫名奇妙]
现在在北京鬼混了,哈哈哈。
by SingleSword posted on 2005-3-16 10:46:48 Weather: 晴 |
这边兄弟多,来了就喝酒,爽。
今晚回家买炒锅自己做饭吃。 |
|
[如获至宝]
码头语录
by SingleSword posted on 2004-12-29 12:34:06 Weather: 晴 |
学人类,首先要用得稳,无论对任何族,最快速度修个位置良好的圣塔,建筑的摆放看一下录像(欧洲选手的比较不错),再结合自己的实践。我的心得就是兵营贴着基地建中间就肯定能过一个兵或英雄;把商店收到里面。 mf要快,不能死兵,也不要让兵扣太多血,有好多细节技艺,看录像放慢点可以学到,例:开始带2,3个农民帮忙在对方英雄来前mf掉门口的海龟。你可以先让大法去吸引六七十血的伤害再放水,这样打完门口的海龟你的水还能有200多血,加上新来的步兵不用农民就能马上继续mf附近的四个怪 遇到附近有小精灵想爆你的水,你可以选一个步兵加大法去攻击那小精灵,但不要追他。你操作不行就让他爆,集中精力mf先,但不行也要多练练。 |
|
[如获至宝]
关于去对手家里骚扰的时间。
by SingleSword posted on 2004-12-13 10:05:15 Weather: 晴 |
今天偶像告诉我,在第一天晚上23:00,第二天下午2:00-3:00的时间
去对手家里,一透都会捞到便宜。
NE前期强,ORC中期强,UD后期强,所以一定要有针对性地来打。 |
|
[如获至宝]
提高操作其实并不难。
by SingleSword posted on 2004-11-16 0:06:59 Weather: 晴 |
想要提高操作,其实只要在打的时候努力地去做就行了。 很多时候操作不好,并不是做不到,而是懒得去做。 以后要摒除这种思想。 |
|
[如获至宝]
最近魔兽小有进步啊!
by SingleSword posted on 2004-10-25 13:13:16 Weather: 晴 |
对操作加深了一点点理解,有点进步。 用HUM再也不怕ORC了哦,哇哈哈哈哈哈!
最近转型ORC,发现ORC果然是奔放流啊!
嗯,以前不知道队型这个概念,现在终于明白了, 当要围对方英雄的时候,应该先alt+f打乱队型, 然后当对方英雄在部队中间时,按M键围上去, 一般按一次是不够的,要多按几次。
当自己的部队打不过对方时,尽量围杀对方的单位, 尽力做到零损失杀两个单位赚够350块钱后回城。 |
| |