在程序中经常需要删除某一个指定文件,但有些文件一直会被资源管理器占用,所以总是删除失败.如果要强行用程序删除除了360那种暴力删除还有一种比较容易想到的就是结束资源管理器并删除文件,然后在把资源管理器起来.
哈,总算引到这上面来了.
结束进程,经常使用TerminateProcess函数,创建进程使用CreateProcess.
但就是这两个常见的函数也有一些鲜为人知的”秘密”(姑且这样叫).
首先讨论TerminateProcess:
BOOL WINAPI TerminateProcess(
__in HANDLE hProcess,
__in UINT uExitCode //进程退出码
);
需要注意的几点:
■ TerminateProcess函数是异步的.这表明使用它之后需要WaitForSingleObject.
■ 如果想知道进程退出码,可以查看uExitCode的返回值,但是如果想结束Explorer.exe进程时不传1,Explorer.exe就无法结束(结束后马上会调起来).这个是很奇怪的现象,毕竟很少地方会提及这一点.
然后是CreateProcess这个函数:
BOOL WINAPI CreateProcess(
__in LPCTSTR lpApplicationName,
__in_out LPTSTR lpCommandLine,
__in LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in LPVOID lpEnvironment,
__in LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,//结构必须清零
__out LPPROCESS_INFORMATION lpProcessInformation
);
需要注意的几点:
■ lpStartupInfo结构如果在传递前不清零,那么CreateProcess可能会不成功.
■ 进程创建后记得CloseHandle创建进程和其主线程句柄.否则将引起内存泄漏.
■ 对Explorer.exe而言,如果只是简单的将其赋值给lpCommandLine,那么xp没有问题,win7旗舰版(32bit)就会出现资源管理器异常(可以打开我的电脑查看),win7旗舰版(64bit)就无法调起来,它打开的是我的文档.CreateProcess本来可以按照特定目录去查找进程的路径(先主进程所在目录,然后当前目录,然后系统目录....),为什么它会”找不到”?(也不能这样讲,毕竟系统已经为我们启动了一个类Explorer.exe进程.
至于win7家庭版有什么现象我暂时不得而知,因为手上没有家庭版win7系统.
上图是win7(32bit)旗舰版出现的情况.
贴代码:
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS,0 );
TCHAR chProcessName[MAX_PATH] = TEXT("EXPLORER.EXE");
PROCESSENTRY32 proceList;
proceList.dwSize = sizeof( PROCESSENTRY32 );
BOOL ret_Value = Process32First( hSnapshot,&proceList );
while ( ret_Value )
{
if ( _tcsicmp( chProcessName,proceList.szExeFile ) == 0 )//_tcsicmp
{
break;
}
ret_Value = Process32Next( hSnapshot,&proceList );
}
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS,FALSE,proceList.th32ProcessID );
TerminateProcess( hProcess,1 );
WaitForSingleObject( hProcess,INFINITE );
CloseHandle(hProcess);
CloseHandle(hSnapshot);
STARTUPINFO stup = {0};
stup.cb = sizeof( STARTUPINFO );
PROCESS_INFORMATION proInfo;
TCHAR chProcessPath[MAX_PATH] = {0};
//1. GetSystemDirectory( chProcessPath,MAX_PATH );
//2. GetWindowsDirectory( chProcessPath,MAX_PATH );
_tcscat( chProcessPath,TEXT("\\") );
_tcscat( chProcessPath,chProcessName );
//3. CreateProcess( NULL,chProcessPath,NULL,NULL,FALSE,0,NULL,NULL,&stup,&proInfo );
//4. CreateProcess( NULL,chProcessName,NULL,NULL,FALSE,0,NULL,NULL,&stup,&proInfo );
DWORD dwErrorCode = GetLastError();
CloseHandle( proInfo.hThread );
CloseHandle( proInfo.hProcess );
大家需要注意我注释的几行.仔细体会这几行的意义.
项目中需要显示很多影视的信息,类似图片墙那种结构,每个影视信息对应一个Cell。考虑到效率的问题,这种Cell必须能够复用。刚开始考虑使用NSTableView,但是当拉伸窗体时,需要动态的拉伸添加和删除列,非常的费劲。最后看苹果官方关于NSTableView的例子时,发现了NSCollectionView这个控件,查询NSCollectionView这种控件的用法时,发现了BCCollectionView这种控件。 据说当展示大量的数据时,BCCollectionView比苹果官方的NSCollectionView效率高很多。
下面介绍这个控件的使用方式:
1. 创建BCCollectionView
BCCollectionView *collectionView = [[BCCollectionView alloc] initWithFrame:frame]; collectionView.delegate = self; NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:frame]; [scrollview setHasVerticalScroller:YES]; [scrollview setAutohidesScrollers:YES]; [scrollview setDocumentView:collectionView]; [self addSubview:scrollview positioned:NSWindowAbove relativeTo:nil];
2. 加载数据
NSArray *dataSource = [[[NSArray alloc] initWithObjects:@"data1", @"data2", @"data3", @"data3", nil] autorelease];
[collectionView reloadDataWithItems:dataSource emptyCaches:YES]; 定义数据源,然后调用函数reloadDataWithItems加载数据。3. 实现回调
当调用BCCollectionView的函数reloadDataWithItems后,BCCollectionViewDelegate中定义的回调会被调用。
下面一次说明常用的每个回调用法:
3.1 返回每个Cell的大小
- (NSSize)cellSizeForCollectionView:(BCCollectionView *)collectionView
{
return NSMakeSize(158, 140);
}3.2 创建一个Cell,可以在这个回调中对Cell进行初始化
- (NSViewController *)reusableViewControllerForCollectionView:(BCCollectionView *)collectionView
{
CellViewController *viewController = [[[CellViewController alloc] init] autorelease];
// 这里可以对viewController进行一个初始化
return viewController;
}3.3 当Cell将来显示出来时,设置数据
- (void)collectionView:(BCCollectionView *)collectionView willShowViewController(NSViewController *)viewController forItem:(id)anItem
{
CellViewController *cellViewController = (CellViewController *)viewController;
// cellViewController将会显示出来,这里需要对cellViewController设置要显示出来的数据。
} 这里的viewController是将要显示出来的Cell, anItem是dataSource里面的一项。
3.4 当一个Cell不可见时,释放其里面的资源
- (void)collectionView:(BCCollectionView *)collectionView viewControllerBecameInvisible:(NSViewController *)viewController{
CellViewController *cell = (CellViewController*)viewController;
// 这里可以释放cell里面的一些资源
}
3.5 实现一个Cell的点击事件
- (void)collectionView:(BCCollectionView *)collectionView didClickItem:(id)anItem withViewController:(NSViewController *)viewController {
// 这里可以实现针对点击时间的一些处理
}
3.6 另外两个用到的回调,可以自己试试效果
- (BOOL)collectionViewShouldDrawSelections:(BCCollectionView *)collectionView {
return NO;
}
- (BOOL)collectionViewShouldDrawHover:(BCCollectionView *)collectionView {
return NO;
} 文中出现的CellViewController是自己实现的Cell。opengl红宝书买了一年了,一直想好好学学,总是感觉没时间,决定最近抽时间高下。
//
// main.c
// TestSwap
//
// Created by 磊 王 on 12-10-18.
// Copyright (c) 2012年. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <GLUT/glut.h>
static GLfloat spin = 0.0;
void init(void)
{
// 设置清除窗口颜色为黑色
glClearColor(0.0, 0.0, 0.0, 0.0);
// 恒定着色模式
glShadeModel(GL_FLAT);
}
void display(void)
{
// 清除窗口
glClear(GL_COLOR_BUFFER_BIT);
// 保存当前矩阵
glPushMatrix();
// 旋转函数,spin是旋转角度,后面三位参数是旋转向量,右手法则确定方向
glRotatef(spin, 0.0, 0.0, 1.0);
// 颜色
glColor3f(1.0, 0.0, 0.0);
// 绘制矩形
glRectf(-25.0, -25.0, 25.0, 25.0);
// 恢复矩阵
glPopMatrix();
// 交换缓冲区
glutSwapBuffers();
}
void spinDisplay(void)
{
spin = spin + .1;
if (spin > 360.0) {
spin -= 360.0;
}
// 通知glutMainLoop重绘
glutPostRedisplay();
}
void reshape(int w, int h)
{
// 设置视口
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h) {
glOrtho(-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w, 50.0*(GLfloat)h/(GLfloat)w, 0.1, -1.0);
}else {
glOrtho(-50.0*(GLfloat)w/(GLfloat)h, 50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, 0.1, -1.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
glutIdleFunc(spinDisplay);
}
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) {
glutIdleFunc(NULL);
}
break;
default:
break;
}
}
int main(int argc, const char * argv[])
{
// 初始化GLUT,处理命令行参数
glutInit(&argc, argv);
// 显示模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
// 窗口大小
glutInitWindowSize(250, 250);
// 创建名为animation的窗口
glutCreateWindow("animation");
init();
// 注册显示回调函数
glutDisplayFunc(display);
// 注册重绘函数,当窗口大小内容发生变化时回调包括窗口刚创建时
glutReshapeFunc(reshape);
// 注册鼠标事件处理函数
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
前面四个参数没什么说的,就是一个矩形大小,确定视景大小的,最后的near和far比较有意思。
我通过改动这两个参数发现,同为正和同为负都看不到图形,一正一负可以看见一个正方形。由于我画的是一个xy平面的正方形,Z坐标为0,在Z轴上没有深度。
一正一负的参数说明所画正方形在视景体内部,同为正和同位负时则在视景体外部,此时就看不到所画的物体。
我的理解是near和far就是确定视口位置和视口方向及视景体深度,比如near和far分别为 1,-1,那么视口在Z轴的1位置,向屏幕里面方向,视景体深度为2,所画物体在视景体内部则能被看到,否则看不到。
知之为知之,不知谷歌之