Ring3下干净的强行删除文件
在某公司实习完,再次回到寝室。还是在学校好。
实习期间的给我的任务就是为项目添加一个强行删除的模块。
背景是硬盘上存储空间不够时,需要删掉老的文件,如果这时后,老的文件被打开了,没有关掉,就无法删除。所以叫我写一个这样的功能。
所谓干净,指的是释放掉这个被占用的句柄。强行删除的方法很多,用驱动直接发磁盘IRP。等等
查阅相关资料后。整理思路如下,如果有同学以后要写这样的功能,可以参考,
1.ZwQuerySystemInformation获取系统当前句柄列表.
2.遍历这个列表,跳过PID==4的 句柄(惹不起)。跳过不是文件的句柄
3. 根据PID判断,如果是自身进程打开的,直接取此句柄
- dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID
- 如果不是,DuplicateHandle相同权限的句柄到自身进程
- 4.根据句柄用NtQueryInformationFile获取文件路径。
这里必须用NtQueryInformationFile而不是ZwQueryInformationFile
MSDN上说的很清楚。
If the call to this function occurs in user mode, you should use the name "NtQueryInformationFile"
instead of "ZwQueryInformationFile".- 这个获取到的路径是不带盘符的,盘符要用GetFileInformationByHandle,通过比对VolumeSerialNumber单独处理.
- 注意:
NtQueryInformationFile是堵塞的,可能会一直卡在那里不返回,所以要放到单独的线程里执行并设置超时。
我一开始想偷懒,直接用ZwQueryObject,这样获取到的就是完整的设备格式路径,不用处理盘符。
在实际编写时会发现,虽然NtQueryInformationFile和ZwQueryObject都是堵塞的,- 在线程超时后,TerminateThread线程时,如果是ZwQueryObject就会导致内存泄露,句柄无法释放,
主线程退出后,发现任务管理器进程还在,CodeProject上有人提出过这个问题,不过他最后是用驱动解决的,
而我一开始就限制了,为了稳定必须在ring3下- 如果我用NtQueryInformationFile,然后超时时TerminateThread就没事。
- 5.比对输入的文件路径和获取到文件路径(要自己处理带盘符的完整DOS风格路径)
获取此时的PID和handle,- 6.打开指定PID的进程,创建远程线程closehandle,关闭掉指定的handle.
- 7.因为一个文件可能被多个句柄占用,所以第一次获取到之后不能自己返回,要继续,获取一个pid和handle就
用远程线程结束一次。一直到没有句柄占用此文件。- -----------------------------------------------------------------------------
无图无真相,我用千千静听做的测试。- 千千静听在播放D:\www\Music\the mass-era.mp3文件时,这个时候,普通删除是无法删除掉这个文件的,
- 会提示
- 运行demo程序。拖放文件到路径框
- 点击删除后,显示当前占用此文件的进程和句柄相关信息,随即关闭这个句柄,并成功删除掉了文件
- 在单曲循环模式下,此时千千静听会直接卡死,只能通过结束进程来推出。
- 其他模式下,会自动跳到下一曲。
- ---------------------------------------------------------------------------
- //提升自身到Debug权限
BOOL MyEnableDebugPriority(VOID)
{
HANDLE hTokenHandle=NULL;
TOKEN_PRIVILEGES TokenPrivileges;
BOOL bFlag=FALSE;- //打开自身进程令牌
bFlag=OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,&hTokenHandle);
if (!bFlag)
{
bFlag=FALSE;
}
else
{
//查询Debug权限
bFlag=LookupPrivilegeValueW(NULL,SE_DEBUG_NAME,&TokenPrivileges.Privileges[0].Luid);
if (!bFlag)
{
bFlag=FALSE;
}
else
{
TokenPrivileges.PrivilegeCount=1;
TokenPrivileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; //我是想获得权限
bFlag=AdjustTokenPrivileges(hTokenHandle,FALSE,&TokenPrivileges,0,(PTOKEN_PRIVILEGES)NULL,0); //提升权限
}
}- if (hTokenHandle!=NULL)
{
CloseHandle(hTokenHandle);
}- return bFlag;
}
- DWORD WINAPI MyQueryFileNameByHandleThreadFunc(LPVOID pParam)
{
FILE_INFO *pFileInfo=(FILE_INFO*)pParam;- WCHAR wcVolume[3]={0};
- NTSTATUS MyNtStatus;
IO_STATUS_BLOCK IoStatus;
UCHAR szBuff[0x1000];
RtlZeroMemory(szBuff,sizeof(szBuff));
FILE_NAME_INFORMATION *pFileNameInformation=(FILE_NAME_INFORMATION*)szBuff;- MyNtStatus=NtQueryInformationFile(pFileInfo->hFileHandle,&IoStatus,pFileNameInformation,
sizeof(FILE_INFO)-sizeof(HANDLE)-sizeof(BOOL),FileNameInformationClass);- if(NT_SUCCESS(MyNtStatus))
{
if(pFileNameInformation->FileNameLength!=0)
{
pFileInfo->bFlag=TRUE;
pFileInfo->FileNameInfo.FileNameLength=pFileNameInformation->FileNameLength;
if (MyGetVolumeNameByHandle(pFileInfo->hFileHandle,wcVolume))// 得到盘符
{
RtlZeroMemory(pFileInfo->FileNameInfo.FileName,sizeof(pFileInfo->FileNameInfo.FileName));- pFileInfo->FileNameInfo.FileName[0]=wcVolume[0];
pFileInfo->FileNameInfo.FileName[1]=wcVolume[1];- wcsncpy(&pFileInfo->FileNameInfo.FileName[2],
pFileNameInformation->FileName,
pFileNameInformation->FileNameLength);- pFileInfo->FileNameInfo.FileName[2+pFileNameInformation->FileNameLength-1]=0;
}- }
}- return 0;
}- //获取当前操作系统中文件句柄 的object值
//这里必须用NtQuerySystemInformation
UCHAR MyGetOsFileHandleObject(VOID)
{
UCHAR ucResult=0;
DWORD dwSize=100;
DWORD dwNeedSize=0;
NTSTATUS MyNtStatus;
DWORD dwCurProcessId=GetCurrentProcessId();
DWORD dwIndex=0;- HANDLE hTempFile=CreateFileW(_T("C:\\boot.ini"),0,0,NULL,OPEN_EXISTING,0,0);
- SYSTEM_HANDLE_INFORMATION* pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwSize, MEM_COMMIT, PAGE_READWRITE );
- if (NULL==pSystemsHandleInformation)
{
return 0;
}- MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwSize,&dwNeedSize);
- if (STATUS_INFO_LENGTH_MISMATCH==MyNtStatus)
{
if (0 == dwNeedSize)
{
ucResult=0;
goto MyErrorExit;
}
else
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwNeedSize, MEM_COMMIT, PAGE_READWRITE );- if(NULL==pSystemsHandleInformation)
{
ucResult=0;
goto MyErrorExit;
}
}
}- MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwNeedSize,NULL);
- if (!NT_SUCCESS(MyNtStatus))
{
goto MyErrorExit;
}
for (dwIndex=0;dwIndex<pSystemsHandleInformation->Count;dwIndex++)
{
if( (dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID) &&
(hTempFile==(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber) )
{
ucResult=(UCHAR)pSystemsHandleInformation->Handles[dwIndex].HandleType; //得到句柄类型
OutputDebugStringW(_T("\n得到句柄类型\n"));
break;
}- }
- MyErrorExit:
- if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}- if (hTempFile!=INVALID_HANDLE_VALUE)
{
CloseHandle(hTempFile);
}- return ucResult;
}
- //遍历系统当前所有文件句柄,每得到一个,就查这个句柄对应的文件名
DWORD WINAPI MyLookupHandleThreadFunc(LPVOID pParam)
{
LOOKUP_INFO * pLockorInfo=(LOOKUP_INFO*)pParam;- DWORD dwSize=100;
DWORD dwNeedSize=0;
NTSTATUS MyNtStatus;
DWORD dwCurProcessId=GetCurrentProcessId();
DWORD dwIndex=0;
BOOL bRemoteFlag=FALSE;
HANDLE hRemoteProcess=NULL;
HANDLE hCurProcess=GetCurrentProcess();- BOOL bDupliFlag=FALSE;
- HANDLE hTureHandle=NULL;
- SYSTEM_HANDLE_INFORMATION* pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwSize, MEM_COMMIT, PAGE_READWRITE );
- if (NULL==pSystemsHandleInformation)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}- MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwSize,&dwNeedSize);
- if (STATUS_INFO_LENGTH_MISMATCH==MyNtStatus)
{
if (0 == dwNeedSize)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}- VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwNeedSize, MEM_COMMIT, PAGE_READWRITE );- if(NULL==pSystemsHandleInformation)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}- }
- MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwNeedSize,NULL);
- if (!NT_SUCCESS(MyNtStatus))
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}- for (dwIndex=0;dwIndex<pSystemsHandleInformation->Count;dwIndex++)
{
if(4==pSystemsHandleInformation->Handles[dwIndex].ProcessID) //system惹不起
{
continue;
}- //不是文件句柄的直接54
if (pLockorInfo->ucOSFileHandleType!=pSystemsHandleInformation->Handles[dwIndex].HandleType)
{
continue;
}- if (dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID)
{
bRemoteFlag=FALSE;
hTureHandle=(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber;
}
else
{
bRemoteFlag=TRUE;
hRemoteProcess=OpenProcess(PROCESS_DUP_HANDLE,FALSE,pSystemsHandleInformation->Handles[dwIndex].ProcessID);
if (hRemoteProcess!=NULL)
{- bDupliFlag=DuplicateHandle(hRemoteProcess,(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber,
hCurProcess,&hTureHandle,0,FALSE,DUPLICATE_SAME_ACCESS); //复制相同权限的handle
if (!bDupliFlag)
{
hTureHandle=NULL;
}
}- if (hRemoteProcess!=NULL)
{
CloseHandle(hRemoteProcess);
}
}- if (hTureHandle!=NULL)
{- //根据文件句柄获取文件路径
if (MyGetFileNameByHandle(hTureHandle,pLockorInfo->szFileName))
{- pLockorInfo->bFlag=TRUE;
pLockorInfo->dwLockProcessId=pSystemsHandleInformation->Handles[dwIndex].ProcessID;
pLockorInfo->wLockHandle=pSystemsHandleInformation->Handles[dwIndex].HandleNumber;- MyCloseRemoteHandle(pSystemsHandleInformation->Handles[dwIndex].ProcessID,
(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber);- }
- //每一次使用后,清理
if (bRemoteFlag)
{
CloseHandle(hTureHandle);
}
}- }
- if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}- return 0;
}- //根据文件句柄获取文件路径的线程
BOOL MyGetFileNameByHandle(__in HANDLE hFileHandle,__out WCHAR *szFileName)
{
BOOL bFindFlag=FALSE;
FILE_INFO FileInfo;
RtlZeroMemory(&FileInfo,sizeof(FileInfo));
FileInfo.bFlag=FALSE;
FileInfo.hFileHandle=hFileHandle;- HANDLE hQueryThread=CreateThread(NULL,0,MyQueryFileNameByHandleThreadFunc,&FileInfo,0,NULL);
- if (WAIT_TIMEOUT == WaitForSingleObject(hQueryThread,100))
{
TerminateThread(hQueryThread,2);
}- if (FileInfo.bFlag)
{
if (0 == wcsicmp(szFileName,FileInfo.FileNameInfo.FileName))
{
bFindFlag=TRUE;
}
}- if (hQueryThread!=NULL)
{
CloseHandle(hQueryThread);
}- return bFindFlag;
}- DWORD WINAPI MyQueryFileNameByHandleThreadFunc(LPVOID pParam)
{
FILE_INFO *pFileInfo=(FILE_INFO*)pParam;- WCHAR wcVolume[3]={0};
- NTSTATUS MyNtStatus;
IO_STATUS_BLOCK IoStatus;
UCHAR szBuff[0x1000];
RtlZeroMemory(szBuff,sizeof(szBuff));
FILE_NAME_INFORMATION *pFileNameInformation=(FILE_NAME_INFORMATION*)szBuff;- MyNtStatus=NtQueryInformationFile(pFileInfo->hFileHandle,&IoStatus,pFileNameInformation,
sizeof(FILE_INFO)-sizeof(HANDLE)-sizeof(BOOL),FileNameInformationClass);- if(NT_SUCCESS(MyNtStatus))
{
if(pFileNameInformation->FileNameLength!=0)
{
pFileInfo->bFlag=TRUE;
pFileInfo->FileNameInfo.FileNameLength=pFileNameInformation->FileNameLength;
if (MyGetVolumeNameByHandle(pFileInfo->hFileHandle,wcVolume))// 得到盘符
{
RtlZeroMemory(pFileInfo->FileNameInfo.FileName,sizeof(pFileInfo->FileNameInfo.FileName));- pFileInfo->FileNameInfo.FileName[0]=wcVolume[0];
pFileInfo->FileNameInfo.FileName[1]=wcVolume[1];- wcsncpy(&pFileInfo->FileNameInfo.FileName[2],
pFileNameInformation->FileName,
pFileNameInformation->FileNameLength);- pFileInfo->FileNameInfo.FileName[2+pFileNameInformation->FileNameLength-1]=0;
}- }
}- return 0;
}- void GetOSVolumeSerialInfo(void)
{
RtlZeroMemory(&VolumeInfo,sizeof(VolumeInfo));- WCHAR szVolumeName[5]= {0};
WCHAR Drive='A';
DWORD dwDiskMask = GetLogicalDrives();
int nIndex=0;
for (nIndex=0; nIndex<26; nIndex++)
{
if( ( (1<<nIndex) & dwDiskMask )!=0)
{
Drive = nIndex + 'A';
wsprintfW(szVolumeName,_T("%c:\\"),Drive);
wsprintfW(VolumeInfo[nIndex].szVolumeName,_T("%c:"),Drive);
GetVolumeInformation(szVolumeName,NULL,0,&VolumeInfo[nIndex].dwVolumeSerial,0,0,0,0);
}
}
}void GetOSVolumeSerialInfo(void)
{
RtlZeroMemory(&VolumeInfo,sizeof(VolumeInfo));- WCHAR szVolumeName[5]= {0};
WCHAR Drive='A';
DWORD dwDiskMask = GetLogicalDrives();
int nIndex=0;
for (nIndex=0; nIndex<26; nIndex++)
{
if( ( (1<<nIndex) & dwDiskMask )!=0)
{
Drive = nIndex + 'A';
wsprintfW(szVolumeName,_T("%c:\\"),Drive);
wsprintfW(VolumeInfo[nIndex].szVolumeName,_T("%c:"),Drive);
GetVolumeInformation(szVolumeName,NULL,0,&VolumeInfo[nIndex].dwVolumeSerial,0,0,0,0);
}
}
}- BOOL MyGetVolumeNameByHandle(__in HANDLE hFile,__out WCHAR *szVolume)
{
DWORD dwIndex=0;
BY_HANDLE_FILE_INFORMATION stHandleFileInfo;
RtlZeroMemory(&stHandleFileInfo,sizeof(stHandleFileInfo));- GetFileInformationByHandle(hFile,&stHandleFileInfo);
for(dwIndex=0; dwIndex<26; dwIndex++)
{
if (stHandleFileInfo.dwVolumeSerialNumber!=0)
{
if (stHandleFileInfo.dwVolumeSerialNumber==VolumeInfo[dwIndex].dwVolumeSerial)
{
wcscpy(szVolume,VolumeInfo[dwIndex].szVolumeName);
return TRUE;
}
}
}
return FALSE;
}- //结束pid=dwProcessId中的hRemoteHandle句柄
BOOL MyCloseRemoteHandle(__in DWORD dwProcessId,__in HANDLE hRemoteHandle)
{
HANDLE hExecutHandle=NULL;
BOOL bFlag=FALSE;
HANDLE hProcess=NULL;
HMODULE hKernel32Module=NULL;- hProcess=OpenProcess(
PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,
FALSE,dwProcessId);- if (NULL==hProcess)
{
bFlag=FALSE;
goto MyErrorExit;
}- hKernel32Module = LoadLibrary( _T("kernel32.dll") );
- hExecutHandle = CreateRemoteThread(hProcess,0,0,
(DWORD (__stdcall *)( void *))GetProcAddress(hKernel32Module,"CloseHandle"),
hRemoteHandle,0,NULL);- if (NULL==hExecutHandle)
{
bFlag=FALSE;
goto MyErrorExit;
}- if (WaitForSingleObject(hExecutHandle,2000)==WAIT_OBJECT_0)
{
bFlag=TRUE;
goto MyErrorExit;
}
else
{
bFlag=FALSE;
goto MyErrorExit;
}- MyErrorExit:
- if (hExecutHandle!=NULL)
{
CloseHandle(hExecutHandle);
}- if (hProcess !=NULL)
{
CloseHandle(hProcess);
}- if (hKernel32Module!=NULL)
{
FreeLibrary(hKernel32Module);
}
return bFlag;
}- //根据PID获取进程名
BOOL MyGetProcessNameByPID(DWORD dwProcessId,WCHAR *szProcessName)
{
BOOL bReturnFlag=FALSE;
PROCESSENTRY32* pProcessInfo=new PROCESSENTRY32;- pProcessInfo->dwSize=sizeof(PROCESSENTRY32);
- HANDLE MyHandProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
- BOOL bFlag=Process32First(MyHandProcessSnap,pProcessInfo);
- while (bFlag)
{
if (dwProcessId==pProcessInfo->th32ProcessID)
{
wcscpy(szProcessName,pProcessInfo->szExeFile);
bReturnFlag=TRUE;
break;
}
bFlag=Process32Next(MyHandProcessSnap,pProcessInfo);
}- if(pProcessInfo!=NULL)
{
delete pProcessInfo;
pProcessInfo=NULL;
}- if (MyHandProcessSnap!=NULL)
{
CloseHandle(MyHandProcessSnap);
}
return bReturnFlag;
}- //根据PID获取进程路径
BOOL MyGetProcessPathByPID(DWORD dwProcessId,WCHAR *szProcessPath)
{
HANDLE hModule;
MODULEENTRY32* pMoudleInfo=new MODULEENTRY32;
pMoudleInfo->dwSize=sizeof(MODULEENTRY32);
hModule=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwProcessId);
Module32First(hModule,pMoudleInfo);- wcscpy(szProcessPath,pMoudleInfo->szExePath);
- if(pMoudleInfo!=NULL)
{
delete pMoudleInfo;
pMoudleInfo=NULL;
}- if (hModule!=NULL)
{
CloseHandle(hModule);
}
return TRUE;
}- http://www.cnblogs.com/lzjsky/archive/2010/12/01/1892680.html
Ring3下干净的强行删除文件的更多相关文章
- Linux下的命令,删除文件夹下的所有文件,而不删除文件夹本身
Linux下的命令,删除文件夹下的所有文件,而不删除文件夹本身 rm -rf *
- linux下实现rm()函数删除文件或目录
转载请注明原创:http://www.cnblogs.com/StartoverX/p/4600866.html 在linux下有两个函数可以用来删除文件: #include <unistd.h ...
- Win强制删除文件windows批处理强行删除文件
一般情况下选中文件或文件夹可以直接删除文件,但是有些情况下例如:文件非常规命名.找不到文件位置等就无法直接删除. 针对这种情况可以用 bat批处理文件 删除,一下就是该方法的步骤 新建一个文件:*** ...
- [C++]linux下实现rm()函数删除文件或目录
转载请注明原创:http://www.cnblogs.com/StartoverX/p/4600866.html 在linux下有两个函数可以用来删除文件: #include <unistd.h ...
- 怎样用CMD命令强行删除文件?
如果你要删除的整个文件夹以及文件夹里面的所有内容的话rd/s/q 盘符:\某个文件夹 (这样整个文件夹所有的文件和文件夹都删除了)比如我想删除D盘的123文件夹以及123文件夹里面所有的内容rd/ ...
- java强行删除文件(针对进程正在使用的文件的删除)
boolean result = f.delete(); if(!result) { System.gc(); f.delete; }
- linux下删除文件夹的命令
使用rm -rf 目录名字 命令即可 -r 就是向下递归,不管有多少级目录,一并删除-f 就是直接强行删除,不作任何提示的意思 eg 删除文件夹实例:rm -rf /var/log/httpd/acc ...
- linux下如何删除文件夹
直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就是向下递归,不管有多少级目录,一并删除-f 就是直接强行删除,不作任何提示的意思删除文件夹实例: rm -rf /var/l ...
- linux下如何删除文件夹?
直接rm就可以了,不过要加两个参数-rf 即:rm -rf 目录名字-r 就是向下递归,不管有多少级目录,一并删除:-f 就是直接强行删除,不作任何提示的意思. 例如:删除文件夹实例: rm -rf ...
随机推荐
- jQuery 随滚动条滚动效果 (固定版)
//侧栏随动 var rollStart = $('.feed-mail'), //滚动到此区块的时候开始随动 rollSet = $('.search,.weibo,.group,.feed-mai ...
- js数组的操作<转>
转自 http://blog.csdn.net/xcxinghai/article/details/13502583 PS(个人理解): 1) 数组项的数据类型可以是混合多样的,同时可以含string ...
- windows程序设计读书笔记4——字符显示3
在之前的一章里我们使用InvalidateRect函数,生成窗口重绘消息进行重绘,但是并没有在处理滚动条消息时直接绘制,这样的代码效率并不高. 这里作者使用了UpdateWindow函数,直接进行窗口 ...
- java中等于和equals的区别
面试的时候没答上,很受打击,特写在这里. ==是判断两个变量或实例是不是指向同一个内存空间equals是判断两个变量或实例所指向的内存空间的值是不是相同 除了String和封装器,equals()和“ ...
- DenyHosts 安装及配置详解
DenyHosts是Python语言写的一个程序,它会分析sshd的日志文件(/var/log/secure),当发现重 复的攻击时就会记录IP到/etc/hosts.deny文件,从而达到自动屏IP ...
- Jquery remove()和empty()
要用到移除指定元素的时候,发现empty()与remove([expr])都可以用来实现.可仔细观察效果的话就可以发现.empty()是只移除了 指定元素中的所有子节点,拿$("p" ...
- Struts2 + Spring + hibernate 框架搭成实例
1.准备Jar包: struts2.hibernate.spring所需jar包 struts-core-2.x.x.jar ----struts核心包 xwork-core-2.x.x.jar ...
- Linux是什么
计算机主要以二进制为单位,而目前常用的磁盘容量单位为B,其单位换算为1B=8bit,其他的以1024为其倍数,如1GB=1024MB等. 操作系统(Operation System)主要用于管理与驱动 ...
- C# base和this[转]
new关键字引起了大家的不少关注,尤其感谢Anders Liu的补充,让我感觉博客园赋予的交流平台真的无所不在.所以,我们就有必要继续这个话题,把我认为最值得关注的关键字开展下去,本文的重点是访问关键 ...
- js实现网页打印分页打印
web打印思路:html页面本身带有打印功能window.print() 但是在打印时又不能word模板的要求来打印不能满足打印需求.同时我们打印的数据有时候是动态变化的需要按模板来打印我的处理方式是 ...