开发一个windows监控服务

1 PE和哈希值 1
1.1PE 1
1.2 哈希值、md5、sha1、crc 2
2 遍历文件夹 3
3 匹配pe文件代码 7
4 技巧 13
5 c++托管类 13
6 监控 13

1 PE和哈希值

1.1PE

PE(Portable Executable)格式,是微软Win32环境可移植可执行文件(如exe、dll、vxd、sys和vdm等)的标准文件格式。PE格式衍生于早期建立在VAX(R)VMS(R)上的COFF(Common Object File Format)文件格式。
那么如何判断一个文件是否为PE格式的文件?
1、首先检验文件头部第一个字的值是否等于 IMAGE_DOS_SIGNATURE,是则 DOS MZ header 有效。
2、一旦证明文件的 DOS header 有效后,就可用e_lfanew来定位 PE header 了。
3、比较 PE header 的第一个字的值是否等于IMAGE_NT_HEADER。如果前后两个值都匹配,那我们就认为该文件是一个有效的PE文件。
上面的是百度的结果
翻译通俗点
1、查找MZ头是否为0X4D5A
2、如果上面条件符合 则用e_lfanew指针定位pe头,e_lfanew一般位于0X3C
3、如果上面条件符合 则判断pe头是否为0x4550
都符合 则是有效PE文件

1.2 哈希值、md5、sha1、crc

哈希值就是文件的身份证,不过比身份证还严格。他是根据文件大小,时间,类型,创作着,机器等计算出来的,很容易就会发生变化,谁也不能预料下一个号码是多少,也没有更改他的软件。

经常有人问,说CRC、MD5、SHA1都是计算一个校验值的,到底有何区别
相同点:
CRC、MD5、SHA1都是通过对数据进行计算,来生成一个校验值,该校验值用来校验数据的完整性。

不同点:
1. 算法不同。CRC采用多项式除法,MD5和SHA1使用的是替换、轮转等方法;
2. 校验值的长度不同。CRC校验位的长度跟其多项式有关系,一般为16位或32位;MD5是16个字节(128位);SHA1是20个字节(160位);
3. 校验值的称呼不同。CRC一般叫做CRC值;MD5和SHA1一般叫做哈希值(Hash)或散列值;
4. 安全性不同。这里的安全性是指检错的能力,即数据的错误能通过校验位检测出来。CRC的安全性跟多项式有很大关系,相对于MD5和SHA1要弱很多;MD5的安全性很高,不过大概在04年的时候被山东大学的王小云破解了;SHA1的安全性最高。
5. 效率不同,CRC的计算效率很高;MD5和SHA1比较慢。
6. 用途不同。CRC一般用作通信数据的校验;MD5和SHA1用于安全(Security)领域,比如文件校验、数字签名等。

以下是我从其他地方找的总结:

MD5可靠性
首先是不可逆
其次,这个码具有高度的离散性,也就是说,原信息的一点点变化就会导致MD5的巨大变化,
最后由于这个码有128位那么长,所以任意信息之间具有相同MD5码的可能性非常之低,通常被认为是不可能的。

crc比较短,md5比较长
所以md5相对来说冲突的可能性要小很多
如果要求不高,是防范传输误码之类的用crc就可以了,crc效率要高很多
如果要防范人为恶意破坏,需要用md5,慢就慢点,图个可靠性加强

2 遍历文件夹

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
#include <io.h>
#include <windows.h>  
#include <string>
#include <vector>
#include <iomanip>

#define MY_NOT_CHECK  1;
#define MY_CHECKED  0;
using namespace std;

int main(){
    string path("c:\\Windows\\system32"), exd("exe");
    vector<WIN32_FIND_DATA> files;
    void getFiles(string path, string exd, vector<WIN32_FIND_DATA>& files);

    getFiles(path, exd, files);

    sort(files);

    show(files);
}

/*遍历文件夹,得到所有exe文件*/
void getFiles(string path, string exd, vector<WIN32_FIND_DATA>& files)
{
    /************************************************************************/
    /*  获取文件夹下所有文件名
    输入:
    path    :    文件夹路径
    exd        :   所要获取的文件名后缀,如jpg、png等;
    文件名, exd = ""
    输出:
    files    :    获取的文件名列表
    */
    /************************************************************************/
    BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege);

    //文件句柄
    HANDLE  hFile = INVALID_HANDLE_VALUE,hExe = INVALID_HANDLE_VALUE;
    //文件信息
    WIN32_FIND_DATA fileinfo,exeinfo;
    string pathName, exdName = "\\*";
    PVOID OldValue = NULL;

    // 关闭系统重定向
    if (Wow64DisableWow64FsRedirection(&OldValue))
    {
        // 查找指定路径
        hFile = FindFirstFile(pathName.assign(path).append(exdName).c_str(), &fileinfo);

        if (FALSE == Wow64RevertWow64FsRedirection(OldValue))
        {
            return;
        }
    }


    // 查找指定路径
    // hFile = FindFirstFile(pathName.assign(path).append(exdName).c_str(), &fileinfo);

    // 是否查找失败
    if (hFile == INVALID_HANDLE_VALUE)
    {
        // 是否因为权限不足,若不足,则提升权限
        if (GetLastError() == 5)
        {
            HANDLE hToken;
            BOOL bRet = OpenProcessToken(
                GetCurrentProcess(),    // 进程句柄(当前进程)
                TOKEN_ALL_ACCESS,    // 全权访问令牌
                &hToken    // 返回的参数 进程令牌句柄 (就是AdjustTokenPrivileges的第一个参数)
                ); // 获取进程的令牌句柄
            if (bRet != TRUE)
            {
                cout << "获取令牌句柄失败!" << endl;
                return;
            }
            BOOL set = SetPrivilege(hToken, SE_DEBUG_NAME, TRUE);
            if (!set || GetLastError() != ERROR_SUCCESS) {
                // 设置权限失败
                cout << "提升权限失败 error:" << GetLastError() << endl;
                cout << "此文件夹缺少权限访问:    " << pathName.assign(path).append("\\").c_str() << endl;
                return;
            }
            // 权限设置成功,继续执行
            hFile = FindFirstFile(pathName.assign(path).append(exdName).c_str(), &fileinfo);
            cout << "权限设置完成" << endl;
            cout << GetLastError()<<endl;
        }
        else
        {
            // 不是权限问题
            cout << "FindFirstFile failed " << GetLastError() << endl;
            system("pause");
            return;
        }
    }

    int flag = MY_NOT_CHECK;
    int lastError = 0;

    // 遍历
    do
    {
        //如果是文件夹,迭代之
        if ((fileinfo.dwFileAttributes &  FILE_ATTRIBUTE_DIRECTORY))
        {
            if (strcmp(fileinfo.cFileName, ".") != 0 && strcmp(fileinfo.cFileName, "..") != 0)
                getFiles(pathName.assign(path).append("\\").append(fileinfo.cFileName), exd, files);
        }
        else
        {
            //如果不是文件夹
            /*
            if (strcmp(fileinfo.cFileName, ".") != 0 && strcmp(fileinfo.cFileName, "..") != 0)
            {
                for (int i = 0; fileinfo.cFileName[i + 3] != '\0'; i++)
                {
                    // 判断是否exe
                    if (fileinfo.cFileName[i] == '.'
                        && (fileinfo.cFileName[i + 1] == 'e' || fileinfo.cFileName[i + 1] == 'E')
                        && (fileinfo.cFileName[i + 2] == 'x' || fileinfo.cFileName[i + 2] == 'X')
                        && (fileinfo.cFileName[i + 1] == 'e' || fileinfo.cFileName[i + 1] == 'E')
                        && fileinfo.cFileName[i + 4] == '\0')
                    {
                        files.push_back(fileinfo);
                        break;
                    }
                }
            }
            */
            // 如果当前目录还未查找过,查找当前目录的exe文件
            if (flag) 
            {
                // 关闭系统重定向
                if (Wow64DisableWow64FsRedirection(&OldValue))
                {
                    // 查找指定路径
                    hExe = FindFirstFile(pathName.assign(path).append("\\*." + exd).c_str(), &exeinfo);

                    if (FALSE == Wow64RevertWow64FsRedirection(OldValue))
                    {
                        return;
                    }
                }
                // hExe = FindFirstFile(pathName.assign(path).append("\\*.exe").c_str(), &exeinfo);
                if (hExe == INVALID_HANDLE_VALUE)
                {
                    lastError = GetLastError();
                    if (lastError == 2)
                    {
                        //cout << setiosflags(ios::left) << setw(50) << path << " 此目录下没有exe " << endl;
                    }
                    else
                    {
                        cout << " 查找exe失败 " << lastError << endl;
                        return;
                    }
                }
                // 遍历所有本文件夹下的exe文件
                if (lastError != 2)
                {
                    do
                    {
                        files.push_back(exeinfo);
                    } while (FindNextFile(hExe, &exeinfo));
                    // 查找完成,此目录已不用遍历,跳出
                    flag = MY_CHECKED;
                    FindClose(hExe);
                }
            }
        }
    } while (FindNextFile(hFile, &fileinfo));
    FindClose(hFile);
    return;
}

3 匹配pe文件代码

#include <stdio.h>  
#include "assert.h"  
#include <windows.h>  
#include "TCHAR.H"  

#ifdef UNICODE  
#define IsPEFile  IsPEFileW  
#define IsDigiSig IsDigiSigW  
#else  
#define IsPEFile  IsPEFileA  
#define IsDigiSig IsDigiSigA  
#endif // !UNICODE  

//获得DOS头  
LPVOID GetDosHeader(LPVOID lpFile)  
{  
    assert(lpFile != NULL);  
    PIMAGE_DOS_HEADER pDosHeader = NULL;  
    if (lpFile != NULL)  
        pDosHeader = (PIMAGE_DOS_HEADER)lpFile;  

    return (LPVOID)pDosHeader;  
}  

//获得NT头  
LPVOID GetNtHeader(LPVOID lpFile,BOOL& bX64)  
{  
    assert(lpFile != NULL);  
    bX64 = FALSE;  
    PIMAGE_NT_HEADERS32 pNtHeader32 = NULL;  
    PIMAGE_NT_HEADERS64 pHeaders64 = NULL;  

    PIMAGE_DOS_HEADER pDosHeader = NULL;  
    if (lpFile != NULL)  
        pDosHeader = (PIMAGE_DOS_HEADER)GetDosHeader(lpFile);  
    //判断是否合法  
    if (pDosHeader->e_magic !=IMAGE_DOS_SIGNATURE)  
        return NULL;  

    pNtHeader32 = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);  
    //判断是不是正常的PE文件  
    if (pNtHeader32->Signature != IMAGE_NT_SIGNATURE)  
        return NULL;  

    if (pNtHeader32->FileHeader.Machine==IMAGE_FILE_MACHINE_AMD64) //64bit  
    {  
        bX64 = TRUE;  
        pHeaders64 = (PIMAGE_NT_HEADERS64)((DWORD)pDosHeader + pDosHeader->e_lfanew);  
        return pHeaders64;  
    }  

    return pNtHeader32;  
}  

//获得可选头  
LPVOID GetOptionHeader(LPVOID lpFile,BOOL& bX64)  
{  
    assert(lpFile != NULL);  
    bX64 = FALSE;  
    LPVOID pOptionHeader = NULL;  
    BOOL bX64Nt = FALSE;  

    LPVOID pNtHeader = (LPVOID)GetNtHeader(lpFile,bX64Nt);  
    if (pNtHeader == NULL)  
        return NULL;  

    if (bX64Nt) //64bit  
    {  
        bX64 = TRUE;          
        pOptionHeader = (LPVOID) PIMAGE_OPTIONAL_HEADER64((DWORD)pNtHeader +sizeof( IMAGE_FILE_HEADER )+ sizeof(DWORD)) ;  
    }else  
    {  
        pOptionHeader = (LPVOID) PIMAGE_OPTIONAL_HEADER32((DWORD)pNtHeader + sizeof( IMAGE_FILE_HEADER )+ sizeof(DWORD));  
    }     
    return pOptionHeader;  
}  

/* 
*  获取字段 
*/  
BOOL IsDigiSigEX(HANDLE hFile)  
{  
    if (hFile == INVALID_HANDLE_VALUE)  //文件对象  
        return FALSE;  
    HANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0, 0, NULL);  
    if (hFileMapping == NULL)    
    {  
        CloseHandle(hFile);  
        return FALSE;  
    }  
    LPVOID lpFile = MapViewOfFile(hFileMapping,FILE_MAP_READ,0, 0, 0);  
    if (lpFile==NULL)  //文件视图对象  
    {  
        CloseHandle(hFileMapping);  
        CloseHandle(hFile);  
        return FALSE;  
    }  

    IMAGE_DATA_DIRECTORY secData = { 0 };  
    LPVOID pOptionHeader = NULL;  
    BOOL bX64Opheader = FALSE;  

    pOptionHeader     = (LPVOID)GetOptionHeader( lpFile,bX64Opheader );  
    if(pOptionHeader != NULL && bX64Opheader)  
    {  
        secData = ((PIMAGE_OPTIONAL_HEADER64)pOptionHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];  
    }  
    else if(pOptionHeader != NULL)  
    {  
        secData = ((PIMAGE_OPTIONAL_HEADER32)pOptionHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];  
    }  

    UnmapViewOfFile(lpFile);  
    CloseHandle(hFileMapping);  
    CloseHandle(hFile);  
    if ( ( secData.VirtualAddress != 0 ) && ( secData.Size != 0 ) )  
        return TRUE;  
    return FALSE;  
}  
//A版函数  
BOOL IsDigiSigA(LPCSTR pPath)  
{  
    HANDLE hFile = CreateFileA(pPath,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);  
    return IsDigiSigEX(hFile);  
}  
//W版函数  
BOOL IsDigiSigW(LPCWSTR pPath)  
{  
    HANDLE hFile = CreateFileW(pPath,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);  
    return IsDigiSigEX(hFile);  
}  

//实际判断PE文件操作  
BOOL IsPEFileEX(HANDLE hFile,BOOL &bIsSucceed)  
{  
    if (hFile == INVALID_HANDLE_VALUE)  //文件对象  
        return FALSE;  
    HANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0, 0, NULL);  
    if (hFileMapping == NULL)    
    {  
        CloseHandle(hFile);  
        return FALSE;  
    }  
    LPVOID lpFile = MapViewOfFile(hFileMapping,FILE_MAP_READ,0, 0, 0);  
    if (lpFile==NULL)  //文件视图对象  
    {  
        CloseHandle(hFileMapping);  
        CloseHandle(hFile);  
        return FALSE;  
    }  

    PIMAGE_DOS_HEADER pDosHeader=NULL;  
    PIMAGE_NT_HEADERS32 pNtHeader32 = NULL;  
    //取得Dos头部  
    pDosHeader = (PIMAGE_DOS_HEADER)lpFile;  
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)  
    {  
        UnmapViewOfFile(lpFile);  
        CloseHandle(hFileMapping);  
        CloseHandle(hFile);  
        return TRUE;  
    }  

    //获取NT头  
    pNtHeader32 = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);  
    //判断是不是PE文件  
    if (pNtHeader32->Signature != IMAGE_NT_SIGNATURE)  
    {  
        UnmapViewOfFile(lpFile);  
        CloseHandle(hFileMapping);  
        CloseHandle(hFile);  
        return TRUE;  
    }  

    UnmapViewOfFile(lpFile);  
    CloseHandle(hFileMapping);  
    CloseHandle(hFile);  

    bIsSucceed = TRUE;  
    return TRUE;  
}  

/* 
*  函数执行成功返回true,失败返回false,A版 
*  第二个参数为true表示是PE文件,false表示非PE文件 
*/  
BOOL IsPEFileA(LPCSTR pPath,BOOL &bIsSucceed)  
{  
    bIsSucceed = FALSE;  
    HANDLE hFile = CreateFileA(pPath,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);    
    return IsPEFileEX(hFile,bIsSucceed);  
}  
//W版  
BOOL IsPEFileW(LPCWSTR pPath,BOOL &bIsSucceed)  
{  
    bIsSucceed = FALSE;  
    HANDLE hFile = CreateFileW(pPath,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);    
    return IsPEFileEX(hFile,bIsSucceed);  
}  

int main()  
{  
    char *test = "D:\\1.txt";  
    //WCHAR *test = _T("D:\\tes.exe");  

    BOOL bIsSucceed = FALSE;  
    printf("%d\n",IsPEFile(test,bIsSucceed));  //实现的第一个函数  
    printf("%d\n",bIsSucceed);  
    printf("%d",IsDigiSig(test));  //实现的第二个函数,参数文件句柄  

    getchar();  
    return 0;  
}  

4 技巧

4.1 System命名空间:项目-属性-常规-公共语言运行库支持;
4.2 运行环境:Debug-最后一个(properties)-general-Common Language Runtime Support–选择 Common Language Runtime Support(/clr),(注意不要选择为 Common Language Runtime Support, Old Syntax (/clr:oldSyntax),这是旧语法,两个有好多不同);

5 c++托管类

https://blogs.msdn.microsoft.com/oliverlu/2004/12/28/ccli1/

6 监控

FindFirstChangeNotification
FileSystemWatcher
ReadDirectoryChangesW(文件大会漏掉,)
客户端监控被监控目录(含所有子目录)下的变化,我们可以采用ReadDirectoryChangesW 函数 ,该函数实现对指定的目录进行监控,并且返回详细的文件变化信息。
函数原型:
BOOL WINAPI ReadDirectoryChangesW(
__in HANDLE hDirectory;
__out LPVOID lpBuffer;
__in DWORD nBufferLength;
__in BOOL bWatchSubtree; // 监视目录. 一般选择 TRUE
__in DWORD dwNotifyFilter; // 对文件过滤的方式和标准
__out_opt LPDWORD lpBytesReturned;// 将接收的字节数转入lpBuffer参数
__inout_opt LPOVERLAPPED lpOverlapped; // 一般选择 NULL
__in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine;
// 一般选择 NULL
);
1.首先该函数使用CreateFile打开目录,打开目录的时候一定要包含FILE_LIST_DIRECTORY参数,它规定了一种必需的访问权限,并返回目录的句柄。
2.lpBuffer,这个缓冲区定义的是FILE_NOTIFY_INFORMATION结构,它存储了文件或目录变化的数据。
3.dwNotifyFilter,对监控文件变化方式的过滤,可以采用以下的一种或几种的组合:
a) FILE_NOTIFY_CHANGE_FILE_NAME:任何文件名改变,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
b) FILE_NOTIFY_CHANGE_DIR_NAME:任何目录名称改变 都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
c) FILE_NOTIFY_CHANGE_ATTRIBUTES:任何属性变化,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
d) FILE_NOTIFY_CHANGE_SIZE:任何文件大小的变化,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
e) FILE_NOTIFY_CHANGE_LAST_WRITE: 任何改变过去修改时间的文件 ,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
f) FILE_NOTIFY_CHANGE_LAST_ACCESS:任何改变文件最近访问时间,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
g) FILE_NOTIFY_CHANGE_CREATION:任何改变文件的创建时间的,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
h) FILE_NOTIFY_CHANGE_SECURITY: 任何安全描述符被改变的,都会查看所在目录或子目录的变更,并将结果通知给等待操作返回。
完全满足我们要求监控的条目。
4.如果函数失败,返回值是零,否则是非零:
ReadDirectoryChangesW 返回类型:
Value Meaning
FILE_ACTION_ADDED
0x00000001 The file was added to the directory.
FILE_ACTION_REMOVED
0x00000002 The file was removed from the directory.
FILE_ACTION_MODIFIED
0x00000003 The file was modified. This can be a change in the time stamp or attributes.
FILE_ACTION_RENAMED_OLD_NAME
0x00000004 The file was renamed and this is the old name.
FILE_ACTION_RENAMED_NEW_NAME
0x00000005 The file was renamed and this is the new name.
根据他不同的返回值,与服务器端进行通信做出不同的同步操作。
5. 该函数具体的做法是:首先使用CreateFile获取要监控目录的句柄;然后在一个判断循环里面调用ReadDirectoryChangesW,并且把自己分配的用来存放目录变化通知的内存首地址、内存长度、目录句柄传给该函数。用户代码在该函数的调用中进行同步等待。当目录中有文件发生改变,控制函数把目录变化通知存放在指定的内存区域内,并把发生改变的文件名、文件所在目录和改变通知处理。

void WINAPI CheckAddedFile( LPDIRECTORY_INFO lpdi, PFILE_NOTIFY_INFORMATION lpfni) {
    TCHAR      szFullPathName[MAX_PATH];
    TCHAR      szFileName[MAX_PATH];

    memcpy( szFileName, lpfni->FileName ,lpfni->FileNameLength);
    szFileName[lpfni->FileNameLength/sizeof(TCHAR)]=0;
    lstrcpy( szFullPathName, lpdi->lpszDirName );
    lstrcat( szFullPathName, L"\\" );
    lstrcat( szFullPathName, szFileName );
    wprintf( L"%s\n", szFullPathName );
    wprintf( L"%s added\n",szFileName);//Zz renamed\n",szFileName);
}
/**********************************************************************
   HandleDirectoryChanges()
   Purpose:
      This function receives notification of directory changes and
      calls CheckChangedFile() to display the actual changes. After
      notification and processing, this function calls
      ReadDirectoryChangesW to reestablish the watch.
   Parameters:
      HANDLE hCompPort - Handle for completion port
   Return Value:
      None
   Comments:
********************************************************************/
void WINAPI HandleDirectoryChange( DWORD dwCompletionPort ) {
    DWORD numBytes;
    DWORD cbOffset;
    LPDIRECTORY_INFO di;
    LPOVERLAPPED lpOverlapped;
    PFILE_NOTIFY_INFORMATION fni;
    BOOL r;

    do {
        // Retrieve the directory info for this directory
        // through the completion key
        GetQueuedCompletionStatus( (HANDLE) dwCompletionPort,
                                   &numBytes,
                                   (LPDWORD) &di,
                                   &lpOverlapped,
                                   INFINITE);
        if ( di ) {
            fni = (PFILE_NOTIFY_INFORMATION)di->lpBuffer;
            do {
                cbOffset = fni->NextEntryOffset;

//              if( fni->Action == FILE_ACTION_MODIFIED )
//                  CheckChangedFile( di, fni );
                if( fni->Action == FILE_ACTION_ADDED) //Zz FILE_ACTION_RENAMED_NEW_NAME)
                    CheckAddedFile( di, fni );

                fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE) fni + cbOffset);

            } while( cbOffset );

            // Reissue the watch command
            r=ReadDirectoryChangesW( di->hDir,
                                   di->lpBuffer,
                                   MAX_BUFFER,
                                   FALSE,
                                   FILE_NOTIFY_CHANGE_FILE_NAME,//|FILE_NOTIFY_CHANGE_LAST_WRITE,
                                   &di->dwBufLength,
                                   &di->Overlapped,
                                   NULL);
            if (0==r) {
                wprintf( L"ReadDirectoryChangesW error! GetLastError()==%d\n",GetLastError());
                no_loop=1;break;//
            }
        } else {
            no_loop=1;
        }
    } while( di );
}

PI函数GetModuleFileName():获得应用程序目录相对路径

MFC函数GetModuleFileName():获得应用程序目录绝对路径

采用.\\也能获得应用程序当前目录

当前目录不一定等于应用程序执行文件的所在目录,一个应用程序被启动时,当前目录是可以被任意设置的。

GetModuleFileName()得到模块的完整路径名,例如,你载入c:\windows\system32\a.dll,得到模块句柄h,则你可以用GetModuleFileName()得到h模块的完整路径名。

.\\一般用在包含头文件的语句中。另一个是程序编译后起作用的,例如,打开自定义的配置文件等。

注:直接用LoadLibrary()或AfxLoadLibrary()载入dll,该函数返回值就是handle;如果你隐式载入dll, 用GetModuleHandle("dll文件名")也可以得到handle;

在开发工程中,往往需要知道当前程序本身所在目录。
一种方法是在程序安装的时候利用安装程序把文件路径写入注册表。在较大的程序中,这种方法比较常用
另一种,就是在程序得到路径。这样,程序随便移动到哪里,都可以得到正确的路径。这也是这里介绍的方法。

/*得到帮助文件的路径*/

    CString strFullName = AfxGetApp()->m_pszHelpFilePath; //得到的是:X:\XXXX\XXX.hlp

                                                                                    //AfxGetApp()->m_pszAppName 得到应用程序名称

                                                                                   //AfxGetApp()->m_pszExeName 得到程序文件名,不包括扩展名
             /*得到解析路径*/

      char drive[_MAX_DRIVE];
      char dir[_MAX_DIR];

      _splitpath(strAppName, drive, dir, NULL,NULL);
      CString strPath;
      strPath.Format("%s%s", drive, dir);

       //得到当前运行程序所在目录,strPath即为得到的当前运行程序所目录

/*得到全路径*/

     TCHAR exeFullPath[MAX_PATH]; // MAX_PATH
    GetModuleFileName(NULL,exeFullPath,MAX_PATH);//得到程序模块名称,全路径,也就是当前运行程序的全路径。利用方法一的解析路径的方法,即可得到程序所在路径。



GetModuleFileName函数原型
DWORD GetModuleFileName(
HMODULE hModule, // handle to module。将要得到的模块的句柄。如果是当前模块,NULL
LPTSTR lpFilename, // path buffer 得到的文件名。
DWORD nSize // size of buffer 一般MAX_PATH就可以了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值