2012年12月26日星期三

IWebBrowserApp.Cpp


/*

本文取名为:IWebBrowserApp.Cpp

下载数据有很多种办法,如:
1.URLDownloadToFile或者URLDownloadToCacheFile
2.HttpOpenRequest
3.WinHttpReadData
4.IWinHttpRequest
5.脚本的"WinHttp.WinHttpRequest.5.1"
6.SOCKET,自己写http头。
7.其他接口,如本文的,就有可能。
8.驱动
9.其他。

类似的上传数据也和上面的大同小异

首先搭建服务器,并且成功。

其次,建立一个asp文件,用于处理接收到的数据,命名为data.asp,内容如下:

<%
Dim vntPostedData, lngCount

Response.AddHeader "Request-Method", Request.ServerVariables("REQUEST_METHOD")

lngCount = Request.TotalBytes
if (lngCount <> 0) then
vntPostedData = Request.BinaryRead(lngCount)
Response.BinaryWrite vntPostedData
end if
%>

以上代码摘自:Microsoft SDKs\Windows\v7.1\Samples\web\winhttp\winhttppostsample\data.asp。

并把此文件放到iis服务器中,例如:C:\inetpub\wwwroot\data.asp.
此文件不必放在浏览器中主动的打开,因为你主动的打开是看不到啥的。

运行下面的代码,既可以看到你发送的数据。

下面的代码修改自:
如何自动发送表单数据到 Internet Explorer
http://support.microsoft.com/kb/q167658
*/

#include <windows.h>
#define INITGUID
#include <initguid.h>
#include <exdisp.h>
#include <memory.h>

HRESULT GetPostData(LPVARIANT pvPostData);

void main()
{
    HRESULT hr;
    IWebBrowserApp* pWBApp = NULL; // Derived from IWebBrowser
    BSTR bstrURL = NULL, bstrHeaders = NULL;
    VARIANT vFlags = {0},
        vTargetFrameName = {0},
        vPostData = {0},
        vHeaders = {0};

    if (FAILED(hr = CoInitialize(NULL)))
    {
        return;
    }

    if (FAILED(hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER, IID_IWebBrowserApp, (LPVOID*)&pWBApp)))
    {
        goto Error;
    }

    bstrURL = SysAllocString(L"http://127.0.0.1/data.asp");//http://<server>/scripts/navpost.asp
    if (!bstrURL)
    {
        goto Error;
    }

    bstrHeaders = SysAllocString(L"Content-Type: application/x-www-form-urlencoded\r\n");
    if (!bstrHeaders)
    {
        goto Error;
    }

    V_VT(&vHeaders) = VT_BSTR;
    V_BSTR(&vHeaders) = bstrHeaders;

    hr = GetPostData(&vPostData);
    hr = pWBApp->Navigate(bstrURL, &vFlags, &vTargetFrameName, &vPostData, &vHeaders);
    pWBApp->put_Visible(VARIANT_TRUE);//显示。

Error:
    if (bstrURL) SysFreeString(bstrURL);
    if (bstrHeaders) SysFreeString(bstrHeaders);
    VariantClear(&vPostData);
    if (pWBApp) pWBApp->Release();
    CoUninitialize();
}

// Pack some data into a SAFEARRAY of BYTEs. Return in a VARIANT
HRESULT GetPostData(LPVARIANT pvPostData)
{
    HRESULT hr;
    LPSAFEARRAY psa;
    LPCTSTR cszPostData = "made by correy";//FName=Matt&Flavor=Mocha+Chip
    UINT cElems = lstrlen(cszPostData);
    LPSTR pPostData;

    if (!pvPostData)
    {
        return E_POINTER;
    }

    VariantInit(pvPostData);

    psa = SafeArrayCreateVector(VT_UI1, 0, cElems);
    if (!psa)
    {
        return E_OUTOFMEMORY;
    }

    hr = SafeArrayAccessData(psa, (LPVOID*)&pPostData);
    memcpy(pPostData, cszPostData, cElems);
    hr = SafeArrayUnaccessData(psa);

    V_VT(pvPostData) = VT_ARRAY | VT_UI1;
    V_ARRAY(pvPostData) = psa;
    return NOERROR;
}

2012年12月19日星期三

CDO.Message.vbs


'一直以为只有在服务端或者安装有iis等的电脑上才有CDO.Message组件,才可以发送邮件。
'其实有时候.send失败,原因好久没有查出。
'这次试验成功,特保存。

Const Email_From = "leguanyuan@163.com" '发件人邮箱
Const Password = "XXXXXXXX" '发件人邮箱密码
Const Email_To = "112426112@qq.com" '收件人邮箱

Set CDO = CreateObject("CDO.Message") '创建CDO.Message对象
CDO.Subject = "test" '邮件主题
CDO.From = Email_From '发件人地址
CDO.To = Email_To '收件人地址
CDO.TextBody = "Hello world!" '邮件正文
'cdo.AddAttachment = "C:\hello.txt" '邮件附件文件路径
Const schema = "http://schemas.microsoft.com/cdo/configuration/" '规定必须是这个,我也不知道为什么

With CDO.Configuration.Fields '用with关键字减少代码输入
.Item(schema & "sendusing") = 2 '使用网络上的SMTP服务器而不是本地的SMTP服务器
.Item(schema & "smtpserver") = "smtp.163.com" 'SMTP服务器地址
.Item(schema & "smtpauthenticate") = 1 '服务器认证方式
.Item(schema & "sendusername") = Email_From '发件人邮箱
.Item(schema & "sendpassword") = Password '发件人邮箱密码
.Item(schema & "smtpserverport") = 465 'SMTP服务器端口
.Item(schema & "smtpusessl") = True '是否使用SSL
.Item(schema & "smtpconnectiontimeout") = 60 '连接服务器的超时时间
.Update '更新设置
End With

CDO.Send '发送邮件

2012年12月12日星期三

Win32_Process.vbs


'在远程电脑运行远程电脑上的一个文件(程序)
'made at 2012.07.07
'email:kouleguan at hotmail dot com
'homepage:http://correy.webs.com

strComputer ="10.101.0.99"
strUserName="administrator"
strPassword="123456"

Set swbeml=createobject("wbemscripting.swbemlocator")
set rcimv2=swbeml.connectserver(strComputer,"root/cimv2",strUserName,strPassword)
Set Process=rcimv2.get("Win32_Process")
Process.create("secedit /export /cfg inf.inf") '不会显示界面。文件生成在系统目录。

2012年12月10日星期一

KeSetTimerEx.C


/*
时间很重要,在现实中如是,在计算机中亦是,如时钟中断。
时间怎能不会,特别是阴阳历转换。
此文展示几种用法,暂命名为KeSetTimerEx.C,
因为IoInitializeTimer需要一个设备对象。
KeSetTimerEx对dpc可有可无,使用更方便。

本文的不足之处,可能是定时器对象的删除等,
不然内存泄露,verifier.exe报错。

made by correy
made at 2012.12.10
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

PVOID g_pkThread;

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT pdoNextDeviceObj;

    KeWaitForSingleObject(g_pkThread, Executive, KernelMode, FALSE, NULL);
    ObDereferenceObject(g_pkThread);

    pdoNextDeviceObj = DriverObject->DeviceObject;//pdoGlobalDrvObj
    //IoDeleteSymbolicLink(&usSymlinkName);//本程序没有创建符号链接。

    while(pdoNextDeviceObj) // Delete all the device objects
    {
        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
        IoDeleteDevice(pdoThisDeviceObj);
    }
}

KSTART_ROUTINE ThreadStart;
VOID ThreadStart(__in PVOID  StartContext)
{
    KdPrint(("创建线程的完整规范示例用法,注意卸载的时候!\n"));
    PsTerminateSystemThread(STATUS_SUCCESS);
}

IO_TIMER_ROUTINE IoTimer;
VOID IoTimer(__in PDEVICE_OBJECT DeviceObject, __in_opt PVOID  Context)
{
    DbgPrint("i am in IoTimer!\n");
    KeSetEvent((PKEVENT)Context, 0, FALSE);
}

KDEFERRED_ROUTINE CustomDpc;
VOID CustomDpc(
               __in struct _KDPC  *Dpc,
               __in_opt PVOID  DeferredContext,
               __in_opt PVOID  SystemArgument1,
               __in_opt PVOID  SystemArgument2)
{
    DbgPrint("i am in CustomDpc!\n");
    KeSetEvent((PKEVENT)DeferredContext, IO_NO_INCREMENT, FALSE);//结束。
    //还可以再调用KeSetTimer,但是要注意次数,和参数。  特别注意时间。  
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    LARGE_INTEGER   li;
    HANDLE  ThreadHandle;
    UNICODE_STRING usDeviceName;
    PDEVICE_OBJECT pdoDeviceObj = 0;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    KEVENT  ke;
    KTIMER kt;
    BOOLEAN b;
    KDPC  dpc;
    int i;

    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = Unload;

    //////////////////////////////////////////////////////////////////////////

    KdPrint(("暂停5秒:KeStallExecutionProcessor\n"));
    KeStallExecutionProcessor(5000000);//5秒钟。

    //////////////////////////////////////////////////////////////////////////
    KdPrint(("暂停5秒:KeDelayExecutionThread\n"));
    li.QuadPart = (5 * (((-10) * 1000) * 1000)); //负数是暂停5秒钟。
    status = KeDelayExecutionThread(KernelMode, FALSE, &li);
    if (status != STATUS_SUCCESS)
    {
        KdPrint(("KeDelayExecutionThread return:%d\n", status));
        //return r;
    }
    //////////////////////////////////////////////////////////////////////////
    RtlInitUnicodeString(&usDeviceName, L"\\Device\\correy"); //必须创建设备。
    status = IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pdoDeviceObj);
    if(!NT_SUCCESS(status))
    {
        return status;
    }

    KeInitializeEvent(&ke, NotificationEvent, FALSE);

    IoInitializeTimer(pdoDeviceObj, IoTimer, &ke);//感觉和WorkItem差不多,只不过把方法改名为开始和结束。
    IoStartTimer(pdoDeviceObj);

    KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL);
    IoStopTimer(pdoDeviceObj);
    //////////////////////////////////////////////////////////////////////////
    KeInitializeTimerEx(&kt, SynchronizationTimer);

    li.QuadPart = (5 * (((-10) * 1000) * 1000));

    //第三个参数,如果是负数,会失败,并且蓝屏。并且不能大于#define MAXLONG     0x7fffffff  // winnt
    b = KeSetTimerEx(&kt, li, 5000000, 0);//其实有5个参数。如kmdkit里面的用法,ida里面也是的。
    if (b == 1)
    {
        KdPrint(("the timer object was already in the system timer queue\n"));
        //继续前进,千万不要退出。注意,注意,再注意。
    }

    for (i = 0; i < 3; i++)
    {
        KeWaitForSingleObject(&kt, Executive, KernelMode, FALSE, NULL);
        KdPrint(("KeSetTimer:5秒%d次\n", i+1));
        KeSetTimerEx(&kt, li, 5000000, 0);
    }

    b = KeCancelTimer(&kt);
    if (b == 0)
    {
        return b;
    }
    //////////////////////////////////////////////////////////////////////////
    KeResetEvent(&ke);
    KeInitializeTimerEx(&kt, SynchronizationTimer);
    KeInitializeDpc(&dpc, CustomDpc, &ke);//最后一个参数是传递用的。

    li.QuadPart = (5 * (((-10) * 1000) * 1000));

    KdPrint(("5秒后调用CustomDpc函数\n", i));

    //第三个参数,如果是负数,会失败,并且蓝屏。并且不能大于#define MAXLONG     0x7fffffff  // winnt
    b = KeSetTimerEx(&kt, li, 5000000, &dpc);//其实有5个参数。
    if (b == 1)
    {
        KdPrint(("the timer object was already in the system timer queue\n"));
        //继续前进,千万不要退出。注意,注意,再注意。
    }

    KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL);

    b = KeCancelTimer(&kt);
    if (b == 0)
    {
        return b;
    }

    KeClearEvent(&ke);
    KeCancelTimer(&kt);
    //////////////////////////////////////////////////////////////////////////
    status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadStart, NULL);
    if (status != STATUS_SUCCESS)
    {
        KdPrint(("PsCreateSystemThread return:%d\n", status));
        //return r;
    }
    else
    {
        ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &g_pkThread, NULL);
        ZwClose(ThreadHandle);
    }
    //////////////////////////////////////////////////////////////////////////

    return 0;
}

2012年12月8日星期六

工作线程两例

/*
工作线程或者劳务线程,很重要,比起一般的内核线程。
它的运行环境不一般,在system中,特别是IRQL。
适用于小的任务,很方便。

made by correy
made at 2012.12.08
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT pdoNextDeviceObj = DriverObject->DeviceObject;//pdoGlobalDrvObj
    //IoDeleteSymbolicLink(&usSymlinkName);//本程序没有创建符号链接。
   
    while(pdoNextDeviceObj) // Delete all the device objects
    {
        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
        IoDeleteDevice(pdoThisDeviceObj);
    }
}

IO_WORKITEM_ROUTINE WorkItem;
VOID WorkItem(__in PDEVICE_OBJECT  DeviceObject, __in_opt PVOID  Context)
{//如果不是同步的,有可能在DriverEntry函数运行结束后才运行到这里。
    DbgPrint("i am in WorkItem!\n");
    KeSetEvent((PKEVENT)Context, 0, FALSE);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING usDeviceName;
    PDEVICE_OBJECT pdoDeviceObj = 0;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PIO_WORKITEM g_piowi;
    KEVENT       g_ke;

    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = OnUnload;
   
    RtlInitUnicodeString(&usDeviceName, L"\\Device\\correy"); //必须创建设备,特别是Vista以前。
    status = IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pdoDeviceObj);
    if(!NT_SUCCESS(status))
    {
        return status;
    }
 
    g_piowi = IoAllocateWorkItem(pdoDeviceObj); //参数是设备对象的指针,不是驱动对象的指针。不然WorkItem退出的时候,蓝屏。
    if (g_piowi == 0)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
   
    //IoInitializeWorkItem和IoAllocateWorkItem的功能差不多。
    //If the caller will later pass the work item to IoQueueWorkItem, IoObject must point to a device object.
    //IoInitializeWorkItem(DriverObject, &g_piowi);//Versions: Available on Windows Vista and later versions of Windows.

    KeInitializeEvent(&g_ke, SynchronizationEvent, FALSE);//设置事件以便同步,也可以不同步。就多3行代码。
    IoQueueWorkItem(g_piowi, &WorkItem, DelayedWorkQueue, &g_ke);
    KeWaitForSingleObject(&g_ke, Executive,KernelMode, FALSE, NULL);

    if (g_piowi)
    {
        IoFreeWorkItem(g_piowi);
    }

    return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
其实这个办法跟简单,没有和设备关联,而且暂时没有被软件废弃。

made by correy
made at 2012.08.13
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntifs.h>

#define TAG 'tset' //本驱动在内存中的标志,即test.

typedef struct WorkItemContext{
    PWORK_QUEUE_ITEM Item;
    HANDLE Pid;
}WorkItemContext;

PVOID allocate(IN SIZE_T NumberOfBytes)
{
    PVOID p = NULL;

    //PAGED_CODE();
    if (KeGetCurrentIrql() > DISPATCH_LEVEL)
    {
        KdBreakPoint();//DbgBreakPoint()
    }

    /*
    Callers of ExAllocatePoolWithTag must be executing at IRQL <= DISPATCH_LEVEL.
    A caller executing at DISPATCH_LEVEL must specify a NonPagedXxx value for PoolType.
    A caller executing at IRQL <= APC_LEVEL can specify any POOL_TYPE value, but the IRQL and environment must also be considered for determining the page type.
    */

    p = ExAllocatePoolWithTag(NonPagedPool, NumberOfBytes, TAG);
    if (p == NULL ) {
        return p;
    }

    /*
    Warning  Memory that ExAllocatePoolWithTag allocates is uninitialized.
    A kernel-mode driver must first zero this memory if it is going to make it visible to user-mode software (to avoid leaking potentially privileged contents).
    */

    RtlZeroMemory(p, NumberOfBytes);

    return p;
}


VOID free(IN PVOID p)
{
    unsigned long r;

    /*
    Callers of ExFreePoolWithTag must be running at IRQL <= DISPATCH_LEVEL.
    A caller at DISPATCH_LEVEL must have specified a NonPagedXxx PoolType when the memory was allocated.
    Otherwise, the caller must be running at IRQL <= APC_LEVEL.
    */

    //PAGED_CODE();

    if (KeGetCurrentIrql() > DISPATCH_LEVEL)
    {
        KdBreakPoint();//DbgBreakPoint()
    }

    if (p) //防止多次释放导致的蓝屏。
    {      
        __try //防止传入非法的地址。
        {
            r = MmIsAddressValid(p);
            ExFreePoolWithTag(p, TAG);//KeGetCurrentIrql() > DISPATCH_LEVEL时依旧蓝屏。
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {          
            r = GetExceptionCode();//啥也不做。
        }

        p = NULL;
    }
}

VOID MY_PWORKER_THREAD_ROUTINE (IN PVOID Parameter)
{
    WorkItemContext * pwic = (WorkItemContext *)Parameter;

    //做一些事。


    free(pwic->Item);
    free(pwic);
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{  

}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    WorkItemContext * wic;

    KdBreakPoint();// == DbgBreakPoint()

    DriverObject->DriverUnload = Unload;  

    //之所以采用结构是因为传递的参数不是一个(实际应用的也不是一个),并且不是同步控制的。
    wic = (WorkItemContext *)allocate(sizeof(WorkItemContext));
    if (wic == NULL) {
        return status;
    }

    wic->Pid = 0;
    wic->Item = (PWORK_QUEUE_ITEM)allocate(sizeof(WORK_QUEUE_ITEM));
    if (wic->Item == NULL) {
        free(wic);
        return status;
    }

    ExInitializeWorkItem(wic->Item,MY_PWORKER_THREAD_ROUTINE,wic);
    ExQueueWorkItem(wic->Item, DelayedWorkQueue);
   
    return status;
}

2012年12月7日星期五

ExInterlockedInsertTailList.C

/*
链表一个重要的概念,
数据结构里面有,内核里面有双链表。

本文主要操作的是同步安全的双链表。
不用单链表的原因是,内核里面的结构大多是双链表。

应用层的有stl等。
那几个应用层的链表API不适用,还不如自己实现链表的结构和操作。

内核中的主要操作安全性的双链表的函数有:
KeInitializeSpinLock
InitializeListHead
ExInterlockedInsertTailList //插入尾,这是正常的思维。
ExInterlockedInsertHeadList //这个不常用,特殊的情况下使用。
ExInterlockedRemoveHeadList //带锁的双链表没有尾删除的。所以使用的用途第队列不是堆栈。
IsListEmpty //这个可以不用。

本文是简单的示例,要使用,还要进一步的加强。
链表怎能不会,光看别人的代码是不行的,必须自己体验:编码调试。
微软没有完整的例子,所以自己写。
made by correy
made at 2012.12.07
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

KSPIN_LOCK g_sl;
LIST_ENTRY g_le;

#define TAG 'tset' //test

typedef struct _dl{ //加不加下划线都可以。
    LIST_ENTRY le;
    int x;
}dl;//定义指针会出错。不知啥原因。*dl

VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { }

void InsertTail()
{
    int i = 0;

    for (i = 0; i < 9; i++)
    {
        dl * dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
        if (dl1 == NULL)
        {
            return;
        }

        dl1->x = i;
        ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl);//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
        DbgPrint("%08x\n",dl1->x);
    }
}

void Ergodic_chain_table()
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }
        DbgPrint("%08x\n",temp->x);
    } while (p != g_le.Flink);
}

void RemoveHead()
{
    PLIST_ENTRY temp;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            DbgPrint("%08x\n",dl2->x);
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = OnUnload;

    KeInitializeSpinLock(&g_sl);
    InitializeListHead(&g_le);

    InsertTail();//插入,形成一个双链表示例
    Ergodic_chain_table();//遍历示例。查询就是添加个比较的条件而已。
    RemoveHead();//从全部头删除示例

    return STATUS_SUCCESS;
}


//添加一些函数.
int InsertTail(HANDLE pid) //插入一个到尾部 HANDLE DWORD
{
    dl * dl1;

    dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
    if (dl1 == NULL)
    {
        return 0 /*false*/;
    }

    dl1->x = pid;

    if (ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl) == 0)//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
    { //第一次操作,链表为空,ExInterlockedInsertTailList返回值为0。
        return 1 /*false*/;
    }

    KdPrint(("成功插入:%d\n",pid));

    return 1 /*true*/;
}

int delete_node(HANDLE pid) //DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//
    dl * head = CONTAINING_RECORD(p, dl, le);

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        if (temp->x == pid)
        {
            //没有删除特定节点的函数,所以自己实现:
            /*
            1.替换链表的节点的指针,把本节点释放掉。
            * p = temp->le;
            ExFreePoolWithTag(temp, TAG);
            2.把第一个节点的值赋值给指定的节点,然后ExInterlockedRemoveHeadList删除第一个。
            3.把指定的节点的值赋值给0,这个值是没有用的。但这样做浪费内存。
            4.删除链表的特定的节点:
              遍历,从头删除,不是就添加到尾部,
                              是就直接删除,不再添加.
              不过要先判断一下存在不,以防使循环.
              还可以先添加在删除(看看允许重复添加不).
            */

            temp->x = head->x;//注意这个结构的一些操作最好加锁同步。
            ExInterlockedRemoveHeadList(&g_le, &g_sl);//IsListEmpty

            KdPrint(("成功删除:%d\n",pid));

            return 1;
        }      

    } while (p != g_le.Flink);

    KdPrint(("删除失败:%d\n",pid));
    return 0;
}

BOOLEAN find (HANDLE pid) //查询  DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            //KdPrint(("没有找到:%d\n",temp->x));//这个显示的频率太多.
            break;
        }

        if (temp->x == pid)
        {
            //KdPrint(("成功找到:%d\n",temp->x));//这个显示的频率太多.
            return 1;
        }
    } while (p != g_le.Flink);

    return 0;
}

int ListAll() //遍历示例。
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    KdPrint(("开始显示\n"));

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        KdPrint(("pid:%d\n",temp->x));

    } while (p != g_le.Flink);

    KdPrint(("显示结束\n\n"));

    return 0;
}

void RemoveAll() //从全部头删除示例
{
    PLIST_ENTRY temp;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

//以后添加单链表的操作,因为但链表的操作更多,只不过要加个同步的处理而已.

2012年12月5日星期三

SHFileOperation.Cpp


/*
删除文件夹有两种办法:
1.递归遍历加RemoveDirectory(移除空目录)。只读属性需要去掉。
2.SHFileOperation函数的FO_DELETE。
修改自:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200(v=vs.85).aspx等。

If you are writing a 32-bit application to list all the files in a directory and the application may be run on a 64-bit computer,
you should call the Wow64DisableWow64FsRedirectionfunction before calling FindFirstFile and call Wow64RevertWow64FsRedirection after the last call to FindNextFile.
*/

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")

#include "Shlwapi.h"
#pragma comment (lib,"Shlwapi.lib")

#include <locale.h>

void DisplayErrorBox(LPTSTR lpszFunction);

bool deldir(TCHAR * path)
{  
    // Check that the input path plus 3 is not longer than MAX_PATH.
    // Three characters are for the "\*" plus NULL appended below.
    size_t length_of_arg;
    StringCchLength(path, MAX_PATH, &length_of_arg);//argv[1]
    if (length_of_arg > (MAX_PATH - 3))  {
        _tprintf(TEXT("\nDirectory path is too long.\n"));
        return (-1);
    }

    // Prepare string for use with FindFile functions.  First, copy the string to a buffer, then append '\*' to the directory name.
    TCHAR szDir[MAX_PATH];
    StringCchCopy(szDir, MAX_PATH, path);//argv[1]
    StringCchCat(szDir, MAX_PATH, TEXT("\\*"));

    // Find the first file in the directory.
    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    hFind = FindFirstFile(szDir, &ffd);
    if (INVALID_HANDLE_VALUE == hFind) {
        DisplayErrorBox(TEXT("FindFirstFile"));
        return false;
    }

    // List all the files in the directory with some info about them.
    do
    {
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            //_tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);
            if (lstrcmpi(ffd.cFileName,L".") == 0 ||
                lstrcmpi(ffd.cFileName,L"..") == 0)
            {
                //这里不操作。
            }
            else
            {
                TCHAR sztemp[MAX_PATH] = {0};
                StringCchCopy(sztemp, MAX_PATH, path);//argv[1]
                PathAppend(sztemp, ffd.cFileName);
                deldir(sztemp);

                /*_tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);*/
            }
        }
        else
        {
            //LARGE_INTEGER filesize;//这几行显示信息用的,无实际用途。
            //filesize.LowPart = ffd.nFileSizeLow;
            //filesize.HighPart = ffd.nFileSizeHigh;
            //_tprintf(TEXT("  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);

            TCHAR sztemp[MAX_PATH] = {0};
            StringCchCopy(sztemp, MAX_PATH, path);//argv[1]
            PathAppend(sztemp, ffd.cFileName);
            bool b = DeleteFile(sztemp);
            if (b == 0)
            {
                int x = GetLastError();
                x = x;//查看x的值用的。
            }
        }
    } while (FindNextFile(hFind, &ffd) != 0);

    //dwError = GetLastError();
    //if (dwError != ERROR_NO_MORE_FILES) {
    //    DisplayErrorBox(TEXT("FindFirstFile"));
    //}

    FindClose(hFind);

    return RemoveDirectory(path);//里面有空文件夹依旧任务是空目录。返回0失败。
}

void DelDir2(TCHAR * dir)
{
    if (!PathFileExists(dir))
    {
        return;
    }

    TCHAR DelDir[MAX_PATH] = {0};
    lstrcpy(DelDir,dir);
    int len = lstrlen(dir);
    DelDir[len] = 0;
    DelDir[len+1] = 0;

    SHFILEOPSTRUCT FileOp;
    ZeroMemory((void*)&FileOp, sizeof(SHFILEOPSTRUCT));

    FileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
    FileOp.hNameMappings = NULL;
    FileOp.hwnd = NULL;
    FileOp.lpszProgressTitle = NULL;
    FileOp.pFrom = DelDir;
    FileOp.pTo = NULL;
    FileOp.wFunc = FO_DELETE;

    int err = SHFileOperation(&FileOp);
    if (0 != err)
    {
        //失败。
    }
}

int _tmain(int argc, TCHAR *argv[])
{
    setlocale(LC_CTYPE, ".936");

    TCHAR path[MAX_PATH] = L"e:\\test";

    bool b = deldir(path);

    DelDir2(L"e:\\test2");

    return 0;
}

void DisplayErrorBox(LPTSTR lpszFunction) //这个函数封装的还不错的,以后就拿来用吧!
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    DWORD dw = GetLastError();

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );

    // Display the error message and clean up
    LPVOID lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

2012年12月4日星期二

ReportEvent.Cpp


/*
日志,怎能不会?
特别是系统的,这些基本的功能。
有时它还是特有用的。
所以有此文。

参考:
http://msdn.microsoft.com/en-us/library/aa363680(v=vs.85).aspx等相关的内容。
http://www.aogosoft.com/downpage.asp?mode=viewtext&id=220
*/

#include <windows.h>

int main()
{
    HANDLE hEventLog = RegisterEventSource(NULL, L"来源");
    if (NULL == hEventLog) {
        return 1;
    }

    CONST LPWSTR pBadCommand = L"data";//这里不准用汉字,是不会显示汉字的,是以字节显示的字母的。以双0字节结尾。
    DWORD dwEventDataSize = ((DWORD)wcslen(pBadCommand) + 1) * sizeof(WCHAR);
    if (!ReportEvent(hEventLog,
        EVENTLOG_INFORMATION_TYPE, //类型(级别)是信息。
        (WORD)0x00000003L, //分类或者任务类别。
        (DWORD)0xC0020100L, //低16位是事件或者事件ID,
        NULL,//A pointer to the current user's security identifier. This parameter can be NULL if the security identifier is not required
        0, //The number of insert strings in the array pointed to by the lpStrings parameter. A value of zero indicates that no strings are present.
        dwEventDataSize, //数据的长度。
        NULL, //另一种情况使用,是数组用的,与上上个参数配合使用,有大小的限制。
        pBadCommand))//数据的内容。
    {
        return 1;
    }

    if (hEventLog) {
        DeregisterEventSource(hEventLog);
    }
}