windows API函数之文件类函数(三)

3.51 函数名:ReadFileEx


(1)函数的概述
ReadFileEx 是一个Windows API函数,用于异步地读取文件或I/O设备。与ReadFile函数不同,ReadFileEx不会阻塞调用线程等待操作完成,而是允许线程继续执行其他任务,同时I/O操作在后台进行。

(2)函数所在的动态链接库
ReadFileEx函数位于Kernel32.dll动态链接库中。

(3)函数的原型

BOOL ReadFileEx(  
  HANDLE       hFile,  
  LPVOID       lpBuffer,  
  DWORD        nNumberOfBytesToRead,  
  LPOVERLAPPED lpOverlapped,  
  LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  
);


(4)各参数及返回值的详细解释

  • hFile:一个打开文件的句柄。
  • lpBuffer:指向一个缓冲区,该缓冲区用于接收从文件中读取的数据。
  • nNumberOfBytesToRead:要读取的字节数。
  • lpOverlapped:指向一个OVERLAPPED结构的指针,该结构用于指定一个事件对象句柄,该句柄用于信号I/O操作的完成。如果此参数为NULL,则操作是同步的。
  • lpCompletionRoutine:一个指向完成例程的指针,当异步I/O操作完成时,系统将调用此例程。如果此参数为NULL,则可以使用lpOverlapped参数中的事件对象来等待操作完成。
  • 返回值:如果函数成功,则返回值为非零。如果函数失败,则返回值为零。要获取扩展的错误信息,请调用GetLastError。

(5)函数的详细作用
ReadFileEx函数用于异步地读取文件或I/O设备的数据。它允许调用线程在数据读取完成之前继续执行其他任务。当数据读取完成时,系统可以通过调用指定的完成例程或设置OVERLAPPED结构中的事件对象来通知应用程序。

(6)函数的C++示例


#include <windows.h>  
#include <iostream>  
  
VOID CALLBACK ReadCompletionRoutine(  
  DWORD dwErrorCode,  
  DWORD dwNumberOfBytesTransfered,  
  LPOVERLAPPED lpOverlapped  
) {  
    // 处理读取完成后的逻辑  
    std::cout << "Read completed with " << dwNumberOfBytesTransfered << " bytes." << std::endl;  
}  
  
int main() {  
    HANDLE hFile = CreateFile(  
        "example.txt",  
        GENERIC_READ,  
        FILE_SHARE_READ,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        // 错误处理  
        return 1;  
    }  
  
    char buffer[1024];  
    OVERLAPPED overlapped = { 0 };  
    overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  
  
    if (!ReadFileEx(hFile, buffer, sizeof(buffer), &overlapped, ReadCompletionRoutine)) {  
        // 错误处理  
        CloseHandle(hFile);  
        CloseHandle(overlapped.hEvent);  
        return 1;  
    }  
  
    // 在这里,主线程可以继续执行其他任务,直到读取完成  
    // ...  
  
    // 等待读取完成(如果需要同步等待)  
    WaitForSingleObject(overlapped.hEvent, INFINITE);  
  
    CloseHandle(hFile);  
    CloseHandle(overlapped.hEvent);  
    return 0;  
}


(7)使用时的注意事项

  1. 在调用ReadFileEx之前,请确保文件句柄是通过CreateFile函数以FILE_FLAG_OVERLAPPED标志打开的。
  2. 如果lpOverlapped参数为NULL,则ReadFileEx将同步执行,这与ReadFile的行为相同。
  3. 如果使用完成例程(lpCompletionRoutine),请确保在完成例程中正确处理所有可能的错误情况。
  4. 如果使用事件对象(lpOverlapped->hEvent)来等待操作完成,请确保在不再需要时关闭该事件对象句柄。
  5. 在多线程环境中使用ReadFileEx时,请确保适当地同步对共享资源的访问。

3.52 函数名:RemoveDirectory


(1)函数的概述
RemoveDirectory 是一个Windows API函数,用于删除一个空目录(文件夹)。注意,该函数只能删除空的目录,如果目录非空(即包含文件或其他目录),则调用将失败。

(2)函数所在的动态链接库
RemoveDirectory函数位于Kernel32.dll动态链接库中。

(3)函数的原型

BOOL RemoveDirectory(  
  LPCTSTR lpPathName  
);


(4)各参数及返回值的详细解释

  • lpPathName:一个指向要删除的目录的字符串的指针。该字符串可以是长文件名或短文件名。
  • 返回值:如果函数成功,返回值为非零。如果函数失败,返回值为零。要获取扩展的错误信息,可以调用GetLastError函数。

(5)函数的详细作用
RemoveDirectory函数的作用是删除指定的空目录。在尝试删除目录之前,请确保该目录是空的,否则函数将失败并返回一个错误代码。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* directoryPath = "C:\\Example\\EmptyDirectory"; // 替换为实际的空目录路径  
  
    if (RemoveDirectory(directoryPath)) {  
        std::cout << "Directory successfully removed." << std::endl;  
    } else {  
        std::cout << "Failed to remove directory. Error: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


(7)使用时的注意事项

  1. 目录必须为空:在调用RemoveDirectory之前,请确保要删除的目录是空的。如果目录包含文件或其他目录,函数将失败。
  2. 权限问题:确保你有足够的权限来删除指定的目录。
  3. 路径格式:确保提供的路径格式正确,包括使用正确的目录分隔符(在Windows上通常是反斜杠\,但在字符串中需要使用双反斜杠\\或前导L来表示宽字符字符串)。
  4. 错误处理:检查函数的返回值以确认操作是否成功,并在必要时调用GetLastError以获取更详细的错误信息。
  5. 不要递归删除:RemoveDirectory只删除空目录。如果你需要递归地删除目录及其内容,你需要自己实现这个功能(例如,通过递归地遍历目录树并删除每个文件和子目录)。
  6. 线程安全:虽然RemoveDirectory函数本身是线程安全的,但在多线程环境中使用它时,仍然需要确保对共享资源的正确同步和访问。

3.53 函数名:SearchPath


(1)函数的概述
SearchPath 是一个Windows API函数,用于在给定的搜索路径列表中查找指定的文件。它会在指定的目录和系统的PATH环境变量中搜索文件,并返回找到的第一个文件的完整路径。

(2)函数所在的动态链接库
SearchPath 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

DWORD SearchPath(  
  LPCTSTR lpPath,  
  LPCTSTR lpFileName,  
  LPCTSTR lpExtension,  
  DWORD   nBufferLength,  
  LPTSTR  lpBuffer,  
  LPTSTR  *lpFilePart  
);


(4)各参数及返回值的详细解释

  • lpPath:一个以分号分隔的目录列表,用于搜索文件。如果此参数为NULL,则函数只在系统的PATH环境变量中搜索。
  • lpFileName:要搜索的文件的名称(不包括路径)。
  • lpExtension:要搜索的文件的扩展名(包括点)。如果此参数为NULL,则函数只搜索与lpFileName参数完全匹配的文件。
  • nBufferLength:lpBuffer缓冲区的大小(以TCHARs为单位)。如果缓冲区太小,则函数返回所需的大小。
  • lpBuffer:一个指向接收找到的文件的完整路径的缓冲区的指针。如果此参数为NULL,则函数返回所需的大小。
  • lpFilePart:一个指向接收lpBuffer中文件名的指针的指针。如果此参数为NULL,则不使用它。
  • 返回值:如果函数成功,返回值是存储在lpBuffer中的字符串的长度(不包括终止的null字符)。如果函数失败,返回值是0,可以通过调用GetLastError获取错误代码。

(5)函数的详细作用
SearchPath函数的主要作用是在给定的目录列表中(和/或系统的PATH环境变量)查找指定的文件,并返回找到的文件的完整路径。这在编写需要找到系统中某个文件的应用程序时非常有用。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* searchPath = "C:\\Program Files;C:\\Program Files (x86);"; // 示例搜索路径  
    const char* fileName = "notepad.exe"; // 要查找的文件名  
    const char* extension = NULL; // 不指定扩展名  
    char buffer[MAX_PATH]; // 存储结果的缓冲区  
    char* filePart; // 指向文件名的指针  
  
    DWORD length = SearchPath(searchPath, fileName, extension, MAX_PATH, buffer, &filePart);  
  
    if (length != 0) {  
        std::cout << "File found: " << buffer << std::endl;  
    } else {  
        std::cout << "File not found. Error: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


(7)使用时的注意事项

  1. 缓冲区大小:确保lpBuffer缓冲区足够大,以存储找到的文件的完整路径。如果缓冲区太小,SearchPath将返回所需的大小,但不会将路径存储在缓冲区中。
  2. 权限问题:SearchPath函数仅用于查找文件,不执行任何文件访问操作。但是,如果你的应用程序需要访问找到的文件,请确保你的应用程序具有适当的权限。
  3. 路径分隔符:在lpPath参数中,目录之间应使用分号(;)分隔。在构建此字符串时,请注意不要包含尾随的分号。
  4. 错误处理:始终检查SearchPath的返回值以确保操作成功。如果函数失败,请调用GetLastError以获取错误代码并进行适当的错误处理。
  5. 文件名和扩展名:如果指定了lpExtension参数,则搜索将同时考虑文件名和扩展名。如果只指定了lpFileName参数,则搜索将仅考虑文件名(不考虑扩展名)。
  6. 环境变量:如果lpPath为NULL,则SearchPath将仅搜索系统的PATH环境变量中列出的目录。确保你的应用程序知道它依赖的PATH环境变量的内容,因为不同的系统或用户配置可能会有所不同。

3.54 函数名:SetCurrentDirectory


(1)函数的概述
SetCurrentDirectory 是一个Windows API函数,用于设置调用线程的当前目录到指定的路径。这会影响由相对路径名指定的文件和目录。

(2)函数所在的动态链接库
SetCurrentDirectory 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL SetCurrentDirectory(  
  LPCTSTR lpPathName  
);

(4)各参数及返回值的详细解释

  • lpPathName:指向以null结尾的字符串的指针,该字符串指定新的当前目录。如果此参数为NULL或空字符串,则函数将当前目录设置为与调用进程的驱动器关联的根目录。
  • 返回值:如果函数成功,返回值为非零值。如果函数失败,返回值为零。要获取扩展的错误信息,可以调用 GetLastError 函数。

(5)函数的详细作用

SetCurrentDirectory 函数用于改变当前工作目录(CWD)为指定的路径。一旦改变了CWD,所有使用相对路径的后续文件操作(如打开文件、创建文件等)都会基于这个新的CWD进行。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    // 要设置的新目录路径  
    const char* newDirectory = "C:\\MyNewDirectory";  
  
    // 尝试设置当前目录  
    if (SetCurrentDirectory(newDirectory)) {  
        std::cout << "Current directory successfully set to " << newDirectory << std::endl;  
    } else {  
        std::cout << "Failed to set current directory. Error: " << GetLastError() << std::endl;  
    }  
  
    // 注意:在这里之后,所有使用相对路径的API调用都将基于C:\\MyNewDirectory  
  
    return 0;  
}

(7)使用时的注意事项

  1. 权限问题:确保你的应用程序有足够的权限来访问和改变指定的目录。
  2. 线程安全:SetCurrentDirectory 函数影响的是调用线程的当前目录,而不是整个进程的当前目录。在多线程环境中,每个线程可以有其自己的当前目录。
  3. 相对路径:在调用 SetCurrentDirectory 之后,任何使用相对路径的文件操作都将基于新的当前目录。这可能会影响你的应用程序中未明确指定完整路径的文件操作。
  4. 错误处理:始终检查函数的返回值以确认操作是否成功。如果函数失败,请调用 GetLastError 以获取详细的错误代码。
  5. 目录存在性:确保指定的目录存在,否则 SetCurrentDirectory 可能会失败。
  6. 恢复原始目录:如果你的应用程序需要临时改变当前目录,那么最好保存原始目录,并在操作完成后恢复它,以避免影响其他代码部分。

3.55 函数名:SetEndOfFile

(1)函数的概述
SetEndOfFile 是一个Windows API函数,用于将文件的指针(EOF,End Of File)移动到文件的当前位置,并截断文件,从而丢弃从当前位置到文件末尾的所有数据。如果文件当前大小小于指定位置,则函数将文件扩展到指定大小,但新增加的部分不填充任何数据(即文件新扩展的部分是未定义的)。

(2)函数所在的动态链接库
SetEndOfFile 函数位于 kernel32.dll 动态链接库中。

(3)函数的原型

BOOL SetEndOfFile(  
  HANDLE hFile  
);

(4)各参数及返回值的详细解释

  • hFile:一个打开文件的句柄。该句柄必须具有FILE_WRITE_DATA或FILE_WRITE_EA访问权限。
  • 返回值:如果函数成功,返回值为非零。如果函数失败,返回值为零。要获取扩展的错误信息,请调用GetLastError。

(5)函数的详细作用
SetEndOfFile 的主要作用是修改文件的大小。如果你将文件指针设置在一个位置,并调用SetEndOfFile,那么从当前位置到文件末尾的所有数据都将被删除,文件大小将被缩减到当前位置。如果你将文件指针设置在一个比文件当前大小更大的位置,然后调用SetEndOfFile,文件大小将被扩展到新的位置,但新增加的部分不包含任何有效数据。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFileA(  
        "test.txt",            // 文件名  
        GENERIC_WRITE,         // 打开以写入  
        0,                     // 不共享  
        NULL,                  // 默认安全  
        OPEN_ALWAYS,           // 如果存在则打开,否则创建  
        FILE_ATTRIBUTE_NORMAL,  // 常规文件  
        NULL                   // 不使用模板文件  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "Failed to open/create file: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 假设我们已经写入了一些数据到文件  
    // ...  
  
    // 现在,我们将文件大小设置为当前位置(例如,截断文件)  
    if (!SetEndOfFile(hFile)) {  
        std::cerr << "Failed to set end of file: " << GetLastError() << std::endl;  
        CloseHandle(hFile);  
        return 1;  
    }  
  
    CloseHandle(hFile);  
    return 0;  
}

(7)使用时的注意事项

  1. 在调用SetEndOfFile之前,应确保你有权修改文件。
  2. 如果你试图将文件大小扩展到非常大的值,可能会因为磁盘空间不足而失败。
  3. 在调用SetEndOfFile之后,文件的EOF位置(即文件大小)会改变,但文件的内容(特别是新扩展的部分)是未定义的。
  4. 使用完文件句柄后,应使用CloseHandle关闭它,以避免资源泄漏。
  5. 如果文件是以文本模式打开的,则SetEndOfFile可能会失败,因为文本模式可能会进行行结束符的转换。在这种情况下,最好以二进制模式打开文件。

3.56 函数名:SetFileAttributes

(1)函数的概述
SetFileAttributes 是一个Windows API函数,用于设置指定文件的属性。这些属性包括文件是否只读、隐藏、系统文件等。

(2)函数所在的动态链接库
SetFileAttributes 函数位于 kernel32.dll 动态链接库中。

(3)函数的原型

BOOL SetFileAttributes(  
  LPCTSTR lpFileName,  
  DWORD   dwFileAttributes  
);

(4)各参数及返回值的详细解释

  • lpFileName:指向要设置其属性的文件的名称的字符串的指针。可以是长文件名、短文件名或路径。
  • dwFileAttributes:指定文件的新属性的位掩码。可以是以下一个或多个值的组合:
  • FILE_ATTRIBUTE_ARCHIVE:标记文件或目录在上次备份后已更改。
  • FILE_ATTRIBUTE_COMPRESSED:文件或目录已压缩。
  • FILE_ATTRIBUTE_DIRECTORY:这是一个目录。
  • FILE_ATTRIBUTE_ENCRYPTED:文件或目录已加密。
  • FILE_ATTRIBUTE_HIDDEN:文件或目录是隐藏的。
  • FILE_ATTRIBUTE_NORMAL:文件或目录没有设置其他属性。
  • FILE_ATTRIBUTE_NOT_CONTENT_INDEXED:文件或目录的内容不应被索引。
  • FILE_ATTRIBUTE_OFFLINE:文件数据的内容不立即可用。
  • FILE_ATTRIBUTE_READONLY:文件是只读的。
  • FILE_ATTRIBUTE_REPARSE_POINT:文件或目录是一个重新分析点,或称为“挂载点”。
  • FILE_ATTRIBUTE_SPARSE_FILE:文件是稀疏文件。
  • FILE_ATTRIBUTE_SYSTEM:文件或目录是系统文件。
  • FILE_ATTRIBUTE_TEMPORARY:文件用于临时存储。
  • FILE_ATTRIBUTE_VIRTUAL:这是一个保留值,用于标记文件是虚拟的。
  • 返回值:如果函数成功,返回值是非零值。如果函数失败,返回值是零。要获取扩展的错误信息,请调用 GetLastError。

(5)函数的详细作用
SetFileAttributes 函数用于修改文件的属性。通过指定不同的属性标志,可以更改文件的只读状态、隐藏状态、系统文件状态等。这对于文件管理和安全性设置非常有用。

(6)函数的C++示例

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* fileName = "example.txt";  
    DWORD fileAttributes = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY;  
  
    if (SetFileAttributes(fileName, fileAttributes)) {  
        std::cout << "File attributes set successfully." << std::endl;  
    } else {  
        std::cerr << "Failed to set file attributes. Error: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}

(7)使用时的注意事项

  1. 确保对文件有足够的权限来更改其属性。
  2. 如果文件不存在,SetFileAttributes 可能会失败,尽管这取决于您尝试设置的属性。
  3. 某些属性(如 FILE_ATTRIBUTE_DIRECTORY)是只读的,不能通过 SetFileAttributes 更改。
  4. 在某些情况下,系统可能会阻止更改某些属性,例如,如果文件被另一个进程锁定或正在使用中。
  5. 如果文件或目录具有多个属性,并且您只想更改其中一个,则可能需要先获取当前属性,然后修改并重新设置它们。
  6. 使用 FILE_ATTRIBUTE_NORMAL 可以清除所有其他属性,将文件设置为仅具有默认属性。
  7. 如果文件在调用 SetFileAttributes 后被其他进程修改,则这些更改可能会覆盖您设置的属性。

3.57 函数名:SetFilePointer

(1)函数的概述
SetFilePointer 是一个Windows API函数,用于在打开的文件中设置文件指针的位置。文件指针用于指定从文件的开头或末尾开始的偏移量,从而允许应用程序读取、写入或操作文件的不同部分。

(2)函数所在的动态链接库
SetFilePointer 函数位于 kernel32.dll 动态链接库中。

(3)函数的原型

DWORD SetFilePointer(  
  HANDLE hFile,  
  LONG   lDistanceToMove,  
  PLONG  lpDistanceToMoveHigh,  
  DWORD  dwMoveMethod  
);


(4)各参数及返回值的详细解释

  • hFile:要设置文件指针的文件的句柄。
  • lDistanceToMove:文件指针移动的字节数。如果dwMoveMethod指定了从文件开始(FILE_BEGIN)或当前位置(FILE_CURRENT),则这是一个正数或负数。如果dwMoveMethod指定了从文件末尾(FILE_END),则这通常是一个负数。
  • lpDistanceToMoveHigh:指向一个变量的指针,该变量包含lDistanceToMove的高32位值(在64位系统中)。如果此参数为NULL,则函数仅使用lDistanceToMove的低32位。
  • dwMoveMethod:移动方法,可以是以下三个值之一:
  • FILE_BEGIN:从文件的开始处移动文件指针。
  • FILE_CURRENT:从当前位置移动文件指针。
  • FILE_END:从文件的结尾处移动文件指针。
  • 返回值:如果成功,SetFilePointer 返回文件指针的新位置(以字节为单位)。如果函数失败,返回值是INVALID_SET_FILE_POINTER。

(5)函数的详细作用
SetFilePointer 函数用于设置文件指针的位置,从而允许应用程序从文件的任何位置开始读取或写入数据。这对于处理大型文件或需要随机访问文件数据的应用程序特别有用。

(6)函数的C++示例


#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFileA(  
        "example.txt",  
        GENERIC_READ | GENERIC_WRITE,  
        0,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "Failed to open file: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 移动到文件的末尾  
    LONG highPart = 0;  
    DWORD position = SetFilePointer(hFile, 0, &highPart, FILE_END);  
    if (position == INVALID_SET_FILE_POINTER) {  
        std::cerr << "Failed to set file pointer: " << GetLastError() << std::endl;  
        CloseHandle(hFile);  
        return 1;  
    }  
  
    // 写入一些文本到文件末尾  
    const char* textToWrite = "Hello, World!\n";  
    DWORD bytesWritten = 0;  
    if (!WriteFile(hFile, textToWrite, strlen(textToWrite), &bytesWritten, NULL)) {  
        std::cerr << "Failed to write to file: " << GetLastError() << std::endl;  
    }  
  
    CloseHandle(hFile);  
    return 0;  
}

(7)使用时的注意事项

  1. 在调用SetFilePointer后,文件指针的位置不会自动保存。如果在调用后关闭并重新打开文件,文件指针将重置为文件的开始。
  2. 在多线程环境中,如果多个线程同时访问同一文件,应确保适当地同步对SetFilePointer的调用,以避免竞态条件。
  3. SetFilePointer可能因多种原因而失败,包括无效的句柄、无效的移动方法或无效的参数。在使用返回值之前,始终检查是否成功。
  4. 在64位系统中,如果文件大小超过LONG的最大值(即2GB),则可能需要使用lpDistanceToMoveHigh参数。否则,SetFilePointer可能无法正确设置超过2GB的文件指针位置。在这种情况下,应考虑使用SetFilePointerEx函数,它支持64位文件大小。

3.58 函数名:SetFileTime

(1)函数的概述
SetFileTime 是一个Windows API函数,用于设置文件的创建时间、最后访问时间和最后写入时间。这些时间戳通常用于文件系统元数据,以跟踪文件的更改和访问情况。

(2)函数所在的动态链接库
SetFileTime 函数位于 kernel32.dll 动态链接库中。

(3)函数的原型

BOOL SetFileTime(  
  HANDLE    hFile,  
  const FILETIME *lpCreationTime,  
  const FILETIME *lpLastAccessTime,  
  const FILETIME *lpLastWriteTime  
);

(4)各参数及返回值的详细解释

  • hFile:文件的句柄,指定要设置时间戳的文件。
  • lpCreationTime:指向FILETIME结构的指针,该结构包含新的创建时间。如果此参数为NULL,则不更改文件的创建时间。
  • lpLastAccessTime:指向FILETIME结构的指针,该结构包含新的最后访问时间。如果此参数为NULL,则不更改文件的最后访问时间。
  • lpLastWriteTime:指向FILETIME结构的指针,该结构包含新的最后写入时间。如果此参数为NULL,则不更改文件的最后写入时间。
  • 返回值:如果函数成功,则返回非零值。如果函数失败,则返回零。要获取扩展的错误信息,可以调用GetLastError函数。

(5)函数的详细作用
SetFileTime函数用于更改指定文件的三个时间戳:创建时间、最后访问时间和最后写入时间。这些时间戳存储在文件系统的元数据中,并可用于各种目的,如文件备份、版本控制或安全审计。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFileA(  
        "example.txt",  
        GENERIC_WRITE,  
        0,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "Failed to open file: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 设置新的时间戳  
    FILETIME currentTime;  
    GetSystemTimeAsFileTime(&currentTime); // 获取当前系统时间  
  
    if (!SetFileTime(hFile, NULL, &currentTime, &currentTime)) {  
        std::cerr << "Failed to set file time: " << GetLastError() << std::endl;  
    } else {  
        std::cout << "File time set successfully." << std::endl;  
    }  
  
    CloseHandle(hFile);  
    return 0;  
}

(7)使用时的注意事项

  1. 确保对文件有足够的权限来更改其时间戳。
  2. 如果文件不存在或句柄无效,则SetFileTime将失败。
  3. 在调用SetFileTime之前,应确保文件句柄是有效的,并且在调用后应使用CloseHandle关闭句柄。
  4. 时间戳的更改不会立即反映在某些文件系统或备份解决方案中,因为它们可能具有缓存机制或延迟更新。
  5. 如果你的应用程序需要跨平台工作,请注意SetFileTime是Windows特定的API,并且在其他操作系统上不可用。在跨平台应用程序中,可能需要使用其他方法或API来设置文件时间戳。

3.59 函数名:SetVolumeLabel

(1)函数的概述
SetVolumeLabel 是一个Windows API函数,用于设置卷(通常是一个磁盘分区或整个磁盘)的标签(也称为卷标)。卷标是一个用户定义的字符串,用于在Windows资源管理器等位置标识卷。

(2)函数所在的动态链接库
SetVolumeLabel 函数位于 kernel32.dll 动态链接库中。

(3)函数的原型

BOOL SetVolumeLabel(  
  LPCTSTR lpRootPathName,  
  LPCTSTR lpVolumeName  
);

(4)各参数及返回值的详细解释

  • lpRootPathName:指向一个字符串的指针,该字符串指定了卷的根目录路径。例如,对于C盘,这个值可以是"C:\\"。对于网络驱动器,它可能是一个UNC路径,如"\\server\share"。
  • lpVolumeName:指向一个字符串的指针,该字符串包含了新的卷标。这个字符串的长度必须小于或等于MAX_VOLUME_LABEL_LEN(通常是32个字符,包括一个终止的空字符)。
  • 返回值:如果函数成功,返回非零值。如果函数失败,返回零。要获取扩展的错误信息,可以调用GetLastError函数。

(5)函数的详细作用
SetVolumeLabel函数用于修改指定卷的标签。卷标是一个字符串,用于在Windows和其他操作系统中标识和区分不同的卷。修改卷标不会影响卷上的数据,但可能会影响一些依赖于卷标来识别卷的应用程序或脚本。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    // 设置C盘的卷标为"MyDataDrive"  
    const char* rootPath = "C:\\";  
    const char* newVolumeLabel = "MyDataDrive";  
  
    if (!SetVolumeLabel(rootPath, newVolumeLabel)) {  
        std::cerr << "Failed to set volume label: " << GetLastError() << std::endl;  
    } else {  
        std::cout << "Volume label set successfully." << std::endl;  
    }  
  
    return 0;  
}

(7)使用时的注意事项

  1. 调用SetVolumeLabel函数需要管理员权限,因为修改卷标可能会影响系统安全性或稳定性。
  2. 在修改卷标之前,请确保没有其他程序正在使用该卷,以防止数据损坏或丢失。
  3. 如果卷标包含特殊字符或空格,可能会导致在某些应用程序或环境中无法正确识别卷。
  4. 在网络环境中,修改网络共享或远程卷的卷标可能会影响其他用户或系统对该卷的访问。
  5. 调用SetVolumeLabel函数时,请确保lpRootPathName和lpVolumeName参数指向的字符串是有效的,并且lpVolumeName的长度不超过MAX_VOLUME_LABEL_LEN。
  6. 如果函数失败,请检查GetLastError返回的错误代码,以确定失败的原因。

3.60 函数名:UnlockFile


(1)函数的概述:
UnlockFile 函数用于解锁一个或多个在文件映射对象或文件中由 LockFile 或 LockFileEx 函数锁定的字节范围。它允许其他进程或线程访问这些字节范围。

(2)函数所在的动态链接库:
UnlockFile 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型:

BOOL UnlockFile(  
  HANDLE hFile,  
  DWORD  dwFileOffsetLow,  
  DWORD  dwFileOffsetHigh,  
  DWORD  nNumberOfBytesToUnlockLow,  
  DWORD  nNumberOfBytesToUnlockHigh  
);


(4)各参数及返回值的详细解释:

  • hFile:一个打开文件的句柄,该文件或文件的映射对象包含要解锁的字节范围。
  • dwFileOffsetLow:要解锁的字节范围的低32位偏移量。
  • dwFileOffsetHigh:要解锁的字节范围的高32位偏移量(对于大文件)。
  • nNumberOfBytesToUnlockLow:要解锁的字节范围的低32位大小。
  • nNumberOfBytesToUnlockHigh:要解锁的字节范围的高32位大小(对于大文件)。
  • 返回值:如果函数成功,则返回值为非零。如果函数失败,则返回值为零。要获取扩展的错误信息,请调用 GetLastError。

(5)函数的详细作用:
UnlockFile 函数用于释放之前由 LockFile 或 LockFileEx 锁定的文件或文件映射对象中的字节范围。当不再需要独占访问某个文件区域时,应该使用此函数来解锁它,以便其他进程或线程可以访问它。

(6)函数的C++示例

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFile(  
        "example.txt",  
        GENERIC_READ | GENERIC_WRITE,  
        0,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "CreateFile failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 假设我们之前已经锁定了某个区域...  
  
    // 现在解锁该区域  
    if (!UnlockFile(hFile, 0, 0, 1024, 0)) { // 解锁前1024个字节  
        std::cerr << "UnlockFile failed: " << GetLastError() << std::endl;  
    }  
  
    CloseHandle(hFile);  
    return 0;  
}


(7)使用时的注意事项:

  1. 在调用 UnlockFile 之前,必须确保文件或文件映射对象已经由 LockFile 或 LockFileEx 成功锁定。
  2. 如果多次锁定同一字节范围,则需要调用 UnlockFile 相同次数来完全解锁它。
  3. 在多线程环境中,必须确保对文件或文件映射对象的锁定和解锁操作是同步的,以防止竞态条件。
  4. 当不再需要文件句柄时,应使用 CloseHandle 函数关闭它。
  5. 如果应用程序在调用 UnlockFile 后立即关闭文件句柄,则可能会在其他进程尝试访问解锁的字节范围之前关闭文件,这可能会导致访问违规。因此,在关闭文件句柄之前,应确保没有其他进程需要访问该文件。

3.61 函数名:UnlockFileEx


(1)函数的概述
UnlockFileEx 函数用于解锁文件或文件映射对象中由 LockFileEx 函数锁定的字节范围。它提供了比 UnlockFile 更灵活的锁定机制,支持重叠锁定(Overlapped I/O)和文件区域的解锁。

(2)函数所在的动态链接库
UnlockFileEx 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL UnlockFileEx(  
  HANDLE hFile,  
  DWORD  dwReserved,  
  DWORD  nNumberOfBytesToUnlockLow,  
  DWORD  nNumberOfBytesToUnlockHigh,  
  LPOVERLAPPED lpOverlapped  
);


(4)各参数及返回值的详细解释

  • hFile:一个打开文件的句柄,该文件或文件的映射对象包含要解锁的字节范围。
  • dwReserved:保留,必须设置为零。
  • nNumberOfBytesToUnlockLow:要解锁的字节范围的低32位大小。
  • nNumberOfBytesToUnlockHigh:要解锁的字节范围的高32位大小(对于大文件)。
  • lpOverlapped:指向 OVERLAPPED 结构的指针,该结构包含文件位置信息,用于解锁由 LockFileEx 指定的重叠区域。如果文件或文件映射对象没有使用重叠锁定,则此参数必须为 NULL。
  • 返回值:如果函数成功,则返回值为非零。如果函数失败,则返回值为零。要获取扩展的错误信息,请调用 GetLastError。

(5)函数的详细作用
UnlockFileEx 函数用于释放之前由 LockFileEx 函数锁定的文件或文件映射对象中的字节范围。通过指定 lpOverlapped 参数,它可以解锁特定的重叠区域,这在多线程或异步 I/O 环境中特别有用。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFile(  
        "example.txt",  
        GENERIC_READ | GENERIC_WRITE,  
        0,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "CreateFile failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 假设我们之前已经使用 LockFileEx 锁定了某个区域...  
    // OVERLAPPED 结构用于指定锁定的区域(在此示例中未使用)  
    OVERLAPPED overlapped = {0};  
  
    // 现在解锁该区域  
    if (!UnlockFileEx(hFile, 0, 0, 1024, &overlapped)) { // 解锁前1024个字节  
        std::cerr << "UnlockFileEx failed: " << GetLastError() << std::endl;  
    }  
  
    CloseHandle(hFile);  
    return 0;  
}  

// 注意:上述示例中,overlapped 结构未用于指定解锁的具体区域,  
// 因为在这个简单的例子中,我们只是解锁了从文件开始的前1024个字节。  
// 在实际使用中,您可能需要使用 overlapped 结构来指定更复杂的锁定和解锁操作。
(7)使用时的注意事项

  1. 在调用 UnlockFileEx 之前,必须确保文件或文件映射对象已经由 LockFileEx 成功锁定。
  2. 如果多次使用 LockFileEx 锁定同一字节范围,则需要调用 UnlockFileEx 相同次数来完全解锁它。
  3. 如果使用 OVERLAPPED 结构进行重叠锁定,则必须确保 UnlockFileEx 中的 lpOverlapped 参数与 LockFileEx 中使用的参数相匹配,以正确解锁对应的区域。
  4. 在多线程环境中,必须确保对文件或文件映射对象的锁定和解锁操作是同步的,以防止竞态条件。
  5. 当不再需要文件句柄时,应使用 CloseHandle 函数关闭它。
  6. 在调用 UnlockFileEx 后,请确保没有其他线程或进程尝试访问已解锁但可能已被其他操作修改的文件区域,以避免数据不一致。

3.62 函数名:UnmapViewOfFile


(1)函数的概述
UnmapViewOfFile 函数用于取消映射一个文件映射对象的视图,即从进程的地址空间中删除该文件映射对象。这不会删除文件映射对象本身,也不会关闭文件句柄。它只是断开文件映射对象与进程的虚拟地址空间之间的关联。

(2)函数所在的动态链接库
UnmapViewOfFile 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL UnmapViewOfFile(  
  LPCVOID lpBaseAddress  
);


(4)各参数及返回值的详细解释

  • lpBaseAddress:指向文件映射对象在调用进程的地址空间中的起始地址的指针。这个地址是之前通过 MapViewOfFile 或 MapViewOfFileEx 函数返回的。
  • 返回值:
  • 如果函数成功,返回值为非零。
  • 如果函数失败,返回值为零。要获取扩展的错误信息,请调用 GetLastError。

(5)函数的详细作用
UnmapViewOfFile 函数用于取消映射文件映射对象在调用进程的地址空间中的视图。当进程不再需要访问文件映射对象的内存时,应调用此函数。这有助于减少进程占用的虚拟地址空间,并允许操作系统更有效地管理内存资源。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFile(  
        "example.txt",  
        GENERIC_READ,  
        FILE_SHARE_READ,  
        NULL,  
        OPEN_EXISTING,  
        FILE_ATTRIBUTE_NORMAL,  
        NULL  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "CreateFile failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    HANDLE hFileMap = CreateFileMapping(  
        hFile,  
        NULL,  
        PAGE_READONLY,  
        0,  
        0,  
        NULL  
    );  
  
    if (hFileMap == NULL) {  
        std::cerr << "CreateFileMapping failed: " << GetLastError() << std::endl;  
        CloseHandle(hFile);  
        return 1;  
    }  
  
    void* pFileBase = MapViewOfFile(  
        hFileMap,  
        FILE_MAP_READ,  
        0, 0, 0  
    );  
  
    if (pFileBase == NULL) {  
        std::cerr << "MapViewOfFile failed: " << GetLastError() << std::endl;  
        CloseHandle(hFileMap);  
        CloseHandle(hFile);  
        return 1;  
    }  
  
    // 在这里使用 pFileBase 指针访问文件内容  
  
    // ...  
  
    // 取消映射  
    if (!UnmapViewOfFile(pFileBase)) {  
        std::cerr << "UnmapViewOfFile failed: " << GetLastError() << std::endl;  
    }  
  
    // 关闭文件映射对象和文件句柄  
    CloseHandle(hFileMap);  
    CloseHandle(hFile);  
  
    return 0;  
}

(7)使用时的注意事项

  1. 在调用 UnmapViewOfFile 后,不应再尝试访问由 lpBaseAddress 参数指定的内存地址,因为这可能会导致访问违规错误。
  2. 在调用 UnmapViewOfFile 后,文件映射对象仍然存在,直到调用 CloseHandle 函数关闭文件映射对象句柄。
  3. 如果对同一个文件映射对象多次调用 MapViewOfFile 或 MapViewOfFileEx,则需要对每个视图分别调用 UnmapViewOfFile 来取消映射。
  4. 如果在调用 UnmapViewOfFile 后仍然需要访问文件映射对象的内容,可以重新调用 MapViewOfFile 或 MapViewOfFileEx 来映射一个新的视图。
  5. 在多线程环境中,应确保对文件映射对象的映射和取消映射操作是线程安全的,以避免竞态条件。

3.63 函数名:VerFindFile


(1)函数的概述
VerFindFile 是一个Windows API函数,它用于在给定的文件版本信息数据库(通常是一个.ver文件)中查找一个特定的文件名。这个文件版本信息数据库包含了程序或组件的不同版本的文件信息,通常用于版本检查或文件替换。

(2)函数所在的动态链接库
VerFindFile 函数位于 Version.dll 动态链接库中。

(3)函数的原型

DWORD VerFindFile(  
  DWORD uFlags,  
  LPCWSTR lpFileName,  
  LPCWSTR lpBlockName,  
  LPCWSTR lpMatchFileName,  
  PUINT puCurFileIndex,  
  LPWSTR *lplpBuffer,  
  PUINT puBufferSize  
);


(4)各参数及返回值的详细解释

  • uFlags:保留,必须设置为0。
  • lpFileName:指向一个字符串的指针,该字符串指定了包含版本信息的文件(通常是.ver文件)的路径。
  • lpBlockName:指向一个字符串的指针,该字符串指定了要搜索的块名。如果此参数为NULL,则搜索整个文件。
  • lpMatchFileName:指向一个字符串的指针,该字符串指定了要查找的文件名。
  • puCurFileIndex:指向一个无符号整数的指针,它接收指向找到的文件名的索引(如果找到)。如果未找到,则此值不变。
  • lplpBuffer:指向一个字符串指针的指针,它接收指向找到的文件的完整路径的缓冲区的指针。如果未找到,则此值不变。
  • puBufferSize:指向一个无符号整数的指针,它接收返回的缓冲区的大小(以字符为单位)。如果未找到,则此值不变。
  • 返回值:如果函数成功,返回值是ERROR_SUCCESS。如果函数失败,返回值是系统错误码。

(5)函数的详细作用
VerFindFile 函数用于在给定的版本信息数据库中查找一个特定的文件名。这通常用于确定与特定程序或组件相关联的文件的正确版本。如果找到匹配的文件名,函数将返回该文件的完整路径和索引,以及包含路径的缓冲区的大小。

(6)函数的C++示

#include <windows.h>  
#include <verrsrc.h> // 包含 VerFindFile 的声明  
#include <iostream>  
  
int main() {  
    UINT index = 0;  
    LPWSTR buffer = NULL;  
    UINT bufferSize = 0;  
  
    // 假设我们有一个.ver文件的路径  
    const wchar_t* verFilePath = L"C:\\path\\to\\your\\version.ver";  
    const wchar_t* blockName = NULL; // 搜索整个文件  
    const wchar_t* matchFileName = L"example.dll";  
  
    // 调用VerFindFile  
    DWORD result = VerFindFile(0, verFilePath, blockName, matchFileName, &index, &buffer, &bufferSize);  
  
    if (result == ERROR_SUCCESS) {  
        std::wcout << L"Found file: " << buffer << std::endl;  
        // 释放缓冲区  
        LocalFree((HLOCAL)buffer);  
    } else {  
        std::wcout << L"Failed to find file. Error: " << result << std::endl;  
    }  
  
    return 0;  
}

注意:在上面的示例中,我们假设buffer是动态分配的,并使用LocalFree释放它。然而,根据VerFindFile的文档,返回的缓冲区可能不是动态分配的,因此在使用前最好检查文档以确认如何适当地释放缓冲区。

(7)使用时的注意事项

  1. 确保.ver文件存在并且可访问。
  2. 如果lplpBuffer不为NULL,则函数可能会分配一个缓冲区来存储找到的文件的完整路径。在不再需要这个缓冲区时,应该释放它(尽管对于VerFindFile函数来说,这不是必需的,但最好检查文档以确认)。
  3. 如果lpBlockName不为NULL,确保指定的块名在.ver文件中存在。
  4. 如果函数失败,请检查返回值以获取错误代码,并使用FormatMessage或其他方法来获取错误的描述。
  5. 由于这个函数是Windows API的一部分,它可能不在所有Windows版本上都可用。在调用之前,最好检查目标平台的文档以确保兼容性。

3.64 函数名:VerInstallFile


(1)函数的概述
VerInstallFile 函数是Windows应用程序编程接口(API)中的一个函数,用于从版本信息数据库中安装一个文件。它通常用于在应用程序的安装过程中,根据版本信息数据库中的信息来复制和安装相应的文件。

(2)函数所在的动态链接库
VerInstallFile 函数位于 Version.dll 动态链接库中。

(3)函数的原型

BOOL VerInstallFile(  
  DWORD   uFlags,  
  LPCWSTR lpSrcFileName,  
  LPCWSTR lpDestFileName,  
  LPCWSTR lpDiskName,  
  DWORD   nBackupType,  
  LPVOID  lpReserved  
);


(4)各参数及返回值的详细解释

  • uFlags:此参数为保留参数,应设置为0。
  • lpSrcFileName:指向一个字符串的指针,该字符串指定了源文件(要安装的文件)的完整路径。
  • lpDestFileName:指向一个字符串的指针,该字符串指定了目标文件(安装到的位置)的完整路径。
  • lpDiskName:指向一个字符串的指针,该字符串指定了包含源文件所在的磁盘的名称或提示字符串。此参数通常用于安装程序中的磁盘提示对话框。
  • nBackupType:备份类型。这个值决定了当目标文件已存在时如何操作。它可以是以下值之一:
  • VER_BACKUP_NONE:不备份目标文件。
  • VER_BACKUP_RENAME:重命名目标文件(如果已存在)。
  • VER_BACKUP_IN_USE:如果目标文件正在使用,则不进行任何操作。
  • VER_BACKUP_ALWAYS:始终备份目标文件(如果已存在)。
  • lpReserved:保留参数,应设置为NULL。
  • 返回值:如果函数成功,返回值为非零(TRUE)。如果函数失败,返回值为零(FALSE)。要获取更多错误信息,可以调用 GetLastError 函数。

(5)函数的详细作用
VerInstallFile 函数的主要作用是从指定的源路径复制文件到目标路径。它通常用于在应用程序安装过程中,根据版本信息数据库中的信息来安装或更新文件。函数还可以处理目标文件已存在时的备份问题。

(6)函数的C++示

#include <windows.h>  
#include <version.h> // 包含 VerInstallFile 的声明  
#include <iostream>  
  
int main() {  
    // 假设源文件和目标文件的路径  
    const wchar_t* srcFileName = L"C:\\path\\to\\source\\file.dll";  
    const wchar_t* destFileName = L"C:\\path\\to\\destination\\file.dll";  
    const wchar_t* diskName = L"Source Disk"; // 可选,用于磁盘提示  
  
    // 调用 VerInstallFile 函数  
    BOOL result = VerInstallFile(0, srcFileName, destFileName, diskName, VER_BACKUP_NONE, NULL);  
  
    if (result) {  
        std::wcout << L"File installation succeeded." << std::endl;  
    } else {  
        std::wcout << L"File installation failed. Error: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}
  1. (7)使用时的注意事项
  2. 确保源文件存在并且可读。
  3. 确保目标目录存在,并且你有足够的权限向该目录写入文件。
  4. 如果目标文件已存在并且你选择了备份选项(如 VER_BACKUP_RENAME),确保有足够的磁盘空间来存储备份文件。
  5. 如果 lpDiskName 参数用于磁盘提示,确保它提供了一个有意义的字符串,以便在安装过程中提示用户插入正确的磁盘。
  6. 始终检查函数的返回值以处理可能的错误情况。
  7. 考虑到版本兼容性,确保你的应用程序或安装程序在目标操作系统上支持 VerInstallFile 函数。
  8. 由于 Version.dll 不是一个核心系统DLL,且在新版本的Windows中可能不被广泛使用,因此建议在使用此函数之前进行充分的测试和兼容性检查。

3.65 函数名:VerLanguageName


(1)函数的概述
VerLanguageName 函数是一个Windows API函数,它用于将语言代码标识符转换为对应的语言名称字符串。这个函数在处理多语言版本的软件时非常有用,因为它允许你将语言代码(通常是十六进制值)转换为更易于理解的语言名称。

(2)函数所在的动态链接库
VerLanguageName 函数位于 Version.dll 动态链接库中。

(3)函数的原型

DWORD VerLanguageNameA(  
  DWORD wLang,  
  LPSTR   lpBuffer,  
  DWORD   cchBuffer  
);  
  
DWORD VerLanguageNameW(  
  DWORD wLang,  
  LPWSTR  lpBuffer,  
  DWORD   cchBuffer  
);


注意:这里有两个版本,一个是针对ASCII字符串的VerLanguageNameA,另一个是针对Unicode字符串的VerLanguageNameW。在C++编程中,通常推荐使用宽字符(Unicode)版本。

(4)各参数及返回值的详细解释

  • wLang:要转换的语言代码标识符。这是一个16位的值,表示语言ID。
  • lpBuffer:指向一个缓冲区的指针,该缓冲区用于接收转换后的语言名称字符串。
  • cchBuffer:指定lpBuffer缓冲区的大小(以字符为单位)。对于ANSI版本,它是字节数;对于Unicode版本,它是宽字符数。
  • 返回值:如果函数成功,返回值是写入lpBuffer的字符数(不包括终止的空字符)。如果函数失败,返回值是0。要获取更详细的错误信息,可以调用GetLastError函数。

(5)函数的详细作用
VerLanguageName 函数的主要作用是将语言代码标识符转换为人类可读的字符串形式。例如,如果你有一个表示“英语(美国)”的语言代码(通常是0x409),你可以使用这个函数来获取字符串“ENGLISH_US”。

(6)函数的C++示例

cpp

#include <windows.h>  
#include <version.h> // 包含 VerLanguageNameW 的声明  
#include <iostream>  
  
int main() {  
    const DWORD langCode = 0x409; // 示例:英语(美国)  
    WCHAR buffer[256]; // 用于存储语言名称的缓冲区  
    DWORD length = VerLanguageNameW(langCode, buffer, _countof(buffer));  
  
    if (length > 0) {  
        std::wcout << L"Language Name: " << buffer << std::endl;  
    } else {  
        std::wcout << L"Failed to get language name. Error: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


(7)使用时的注意事项

  1. 确保lpBuffer缓冲区足够大,以容纳转换后的语言名称字符串和终止的空字符。
  2. 检查返回值以确保函数成功执行。如果函数失败,可以使用GetLastError函数来获取错误代码。
  3. 当处理多语言环境时,请确保你的应用程序或系统支持所需的语言代码。
  4. 由于Version.dll可能不是所有Windows版本的核心组件,因此在使用此函数之前,请确保目标操作系统支持它。如果不确定,请进行兼容性测试。
  5. 尽管VerLanguageName函数本身没有太多限制,但在处理用户界面元素(如菜单、对话框等)时,请始终考虑本地化和国际化问题,以确保你的应用程序能够适应不同的语言和地区设置。

3.66 函数名:VerQueryValue


(1)函数的概述
VerQueryValue 函数用于从指定的版本信息块(通常是从文件或资源的版本信息中获取的)中检索特定字段的值。这个函数常用于处理Windows PE结构(如EXE、DLL等)的版本信息,以获取诸如文件版本、产品名称、版权信息等元数据。

(2)函数所在的动态链接库
VerQueryValue 函数位于 Version.dll 动态链接库中。

(3)函数的原型

BOOL VerQueryValue(  
  LPCVOID pBlock,  
  LPCWSTR lpSubBlock,  
  LPVOID  *lplpBuffer,  
  PUINT   puLen  
);


(4)各参数及返回值的详细解释

  • pBlock:指向版本信息块的指针。这通常是通过调用如 GetFileVersionInfo 或 GetFileVersionInfoSize 等函数从文件或资源中获取的。
  • lpSubBlock:一个以\分隔的字符串,指定要检索的子块和键。例如,"\VarFileInfo\Translation" 可以用于检索翻译列表。
  • lplpBuffer:一个指向指针的指针,用于接收指向请求数据块的指针。如果此参数为NULL,则忽略。
  • puLen:指向一个无符号整数的指针,用于接收返回数据块的大小(以字节为单位)。如果此参数为NULL,则忽略。
  • 返回值:如果函数成功,返回值为非零(TRUE)。如果函数失败,返回值为零(FALSE)。要获取更多错误信息,可以调用 GetLastError 函数。

(5)函数的详细作用
VerQueryValue 函数允许你访问存储在文件或资源中的版本信息。这些信息通常用于显示给用户、用于软件兼容性检查或用于调试目的。你可以使用这个函数来检索诸如文件版本、产品名称、公司名称、版权信息等字段。

(6)函数的C++示

#include <windows.h>  
#include <version.h>  
#include <iostream>  
  
int main() {  
    const char* filePath = "C:\\path\\to\\your\\file.exe";  
    DWORD dummy;  
    UINT len;  
    VS_FIXEDFILEINFO* fileInfo = nullptr;  
    LPSTR buffer = nullptr;  
  
    // 获取版本信息大小  
    DWORD handle;  
    DWORD verInfoSize = GetFileVersionInfoSize(filePath, &handle);  
    if (verInfoSize == 0) {  
        std::cerr << "GetFileVersionInfoSize failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    // 分配内存以存储版本信息  
    buffer = new char[verInfoSize];  
    if (!GetFileVersionInfo(filePath, handle, verInfoSize, buffer)) {  
        std::cerr << "GetFileVersionInfo failed: " << GetLastError() << std::endl;  
        delete[] buffer;  
        return 1;  
    }  
  
    // 查询固定文件信息  
    if (!VerQueryValue(buffer, "\\", reinterpret_cast<LPVOID*>(&fileInfo), &len)) {  
        std::cerr << "VerQueryValue failed: " << GetLastError() << std::endl;  
        delete[] buffer;  
        return 1;  
    }  
  
    // 打印文件版本(仅示例)  
    std::cout << "File Version: "  
              << HIWORD(fileInfo->dwFileVersionMS) << "."  
              << LOWORD(fileInfo->dwFileVersionMS) << "."  
              << HIWORD(fileInfo->dwFileVersionLS) << "."  
              << LOWORD(fileInfo->dwFileVersionLS) << std::endl;  
  
    // 清理  
    delete[] buffer;  
    return 0;  
}


注意:此示例中仅检索了固定文件信息(VS_FIXEDFILEINFO),但VerQueryValue可以用于检索版本信息块中的任何其他数据。

(7)使用时的注意事项

  1. 确保为版本信息块分配了足够的内存。如果内存不足,函数将失败。
  2. 当你不再需要版本信息块时,记得释放分配的内存。
  3. 在调用VerQueryValue之前,确保你已经成功获取了版本信息的大小,并分配了相应的内存。
  4. 检查函数的返回值以确保成功。如果失败,使用GetLastError获取更多信息。
  5. 注意处理Unicode和ANSI字符串的兼容性。如果你在处理宽字符字符串,可能需要使用VerQueryValueW而不是VerQueryValue。
  6. 当处理来自不受信任来源的文件时,要小心处理版本信息。

3.67 函数名:WriteFile


(1)函数的概述
WriteFile 函数用于将数据写入一个文件。这个函数是Windows API中用于文件I/O操作的一部分,它允许你将数据从内存缓冲区写入到一个打开的文件中。

(2)函数所在的动态链接库
WriteFile 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL WriteFile(  
  HANDLE       hFile,  
  LPCVOID      lpBuffer,  
  DWORD        nNumberOfBytesToWrite,  
  LPDWORD      lpNumberOfBytesWritten,  
  LPOVERLAPPED lpOverlapped  
);


(4)各参数及返回值的详细解释

  • hFile:要写入数据的文件的句柄。这个句柄通常是通过CreateFile或_open等函数获得的。
  • lpBuffer:指向要写入文件的数据的指针。
  • nNumberOfBytesToWrite:要写入文件的字节数。
  • lpNumberOfBytesWritten:指向一个DWORD的指针,用于接收实际写入的字节数。如果此参数为NULL,则不返回写入的字节数。
  • lpOverlapped:指向一个OVERLAPPED结构的指针,用于异步写操作。对于同步写操作,此参数应设置为NULL。
  • 返回值:如果函数成功,返回值为非零(TRUE)。如果函数失败,返回值为零(FALSE)。要获取更多错误信息,可以调用GetLastError函数。

(5)函数的详细作用
WriteFile函数用于将数据从内存缓冲区写入到文件。这个函数可以用于同步或异步写操作,具体取决于hFile句柄的打开方式和lpOverlapped参数的设置。在同步模式下,函数会等待写操作完成才返回。在异步模式下,函数会立即返回,而写操作会在后台进行。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    HANDLE hFile = CreateFileA(  
        "example.txt",                // 文件名  
        GENERIC_WRITE,                // 打开文件以进行写入  
        0,                            // 不共享  
        NULL,                         // 默认安全  
        CREATE_ALWAYS,                // 如果文件不存在则创建,否则覆盖  
        FILE_ATTRIBUTE_NORMAL,         // 正常文件属性  
        NULL                          // 不使用模板文件  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "CreateFile failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    const char data[] = "Hello, World!";  
    DWORD bytesWritten;  
    if (!WriteFile(hFile, data, sizeof(data), &bytesWritten, NULL)) {  
        std::cerr << "WriteFile failed: " << GetLastError() << std::endl;  
        CloseHandle(hFile);  
        return 1;  
    }  
  
    std::cout << "Wrote " << bytesWritten << " bytes." << std::endl;  
  
    CloseHandle(hFile);  
    return 0;  
}


(7)使用时的注意事项

  1. 确保你有足够的权限来写入文件。
  2. 在调用WriteFile之前,确保文件已经被正确打开,并且具有写入权限。
  3. 如果WriteFile返回失败,并且错误代码是ERROR_NO_SYSTEM_RESOURCES或ERROR_OUTOFMEMORY,可能是因为系统资源不足。
  4. 对于异步写操作,请确保正确设置OVERLAPPED结构,并处理可能的异步完成通知。
  5. 在调用WriteFile后,确保检查返回值,并在需要时调用GetLastError来获取更多错误信息。
  6. 完成后,使用CloseHandle来关闭文件句柄。

3.68 函数名:WriteFileEx


(1)函数的概述
WriteFileEx 函数是一个增强的文件写入函数,它支持重叠I/O操作,允许应用程序在等待I/O操作完成时执行其他操作。这对于需要同时处理多个I/O操作或需要提高性能的应用程序特别有用。

(2)函数所在的动态链接库
WriteFileEx 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL WriteFileEx(  
  HANDLE       hFile,  
  LPCVOID      lpBuffer,  
  DWORD        nNumberOfBytesToWrite,  
  LPDWORD      lpNumberOfBytesWritten,  
  LPOVERLAPPED lpOverlapped  
);


(4)各参数及返回值的详细解释

  • hFile:文件句柄。这是标识要写入数据的文件的句柄。
  • lpBuffer:指向要写入文件的数据的指针。
  • nNumberOfBytesToWrite:要写入文件的字节数。
  • lpNumberOfBytesWritten:一个指向DWORD变量的指针,该变量将接收实际写入的字节数。
  • lpOverlapped:指向OVERLAPPED结构的指针,该结构用于异步I/O操作。如果hFile参数指定的句柄与I/O完成端口相关联,则必须设置此参数。
  • 返回值:如果函数成功,返回值为非零(TRUE)。如果函数失败,返回值为零(FALSE)。要获取扩展的错误信息,请调用GetLastError。

(5)函数的详细作用
WriteFileEx 函数用于将数据从内存缓冲区异步地写入到文件中。与WriteFile不同,WriteFileEx支持重叠I/O,这意味着在写入操作完成之前,线程可以执行其他操作。这使得它可以更有效地利用系统资源,并可能提高程序的总体性能。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
void CALLBACK FileIOCompletionRoutine(  
  DWORD dwErrorCode,   
  DWORD dwNumberOfBytesTransfered,   
  LPOVERLAPPED lpOverlapped  
) {  
    // 处理I/O完成后的操作  
    std::cout << "File IO operation completed. Bytes transferred: " << dwNumberOfBytesTransfered << std::endl;  
    // 释放lpOverlapped结构占用的任何资源  
    // ...  
}  
  
int main() {  
    HANDLE hFile = CreateFileA(  
        "example.txt",                // 文件名  
        GENERIC_WRITE,                // 打开文件以进行写入  
        0,                            // 不共享  
        NULL,                         // 默认安全  
        CREATE_ALWAYS,                // 如果文件不存在则创建,否则覆盖  
        FILE_ATTRIBUTE_NORMAL,         // 正常文件属性  
        NULL                          // 不使用模板文件  
    );  
  
    if (hFile == INVALID_HANDLE_VALUE) {  
        std::cerr << "CreateFile failed: " << GetLastError() << std::endl;  
        return 1;  
    }  
  
    const char data[] = "Hello, World!";  
    DWORD bytesWritten;  
    OVERLAPPED overlapped = {0};  
    overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建一个事件对象  
  
    if (!WriteFileEx(hFile, data, sizeof(data), &bytesWritten, &overlapped)) {  
        if (GetLastError() != ERROR_IO_PENDING) { // 如果不是ERROR_IO_PENDING,说明有其他错误  
            std::cerr << "WriteFileEx failed: " << GetLastError() << std::endl;  
            CloseHandle(hFile);  
            CloseHandle(overlapped.hEvent);  
            return 1;  
        }  
        // 在这里,你可以开始其他工作,因为WriteFileEx是异步的  
    }  
  
    // 等待I/O操作完成  
    WaitForSingleObject(overlapped.hEvent, INFINITE);  
  
    // 清理  
    CloseHandle(hFile);  
    CloseHandle(overlapped.hEvent);  
  
    return 0;  
}  

// 注意:为了简单起见,上面的示例没有使用FileIOCompletionRoutine回调。  
// 在实际使用中,您可能会将此回调与I/O完成端口一起使用。
(7)使用时的注意事项

  1. 确保你有足够的权限来写入文件。
  2. 在调用WriteFileEx之前,确保文件已经被正确打开,并且具有写入权限。
  3. 当使用重叠I/O时,确保正确设置OVERLAPPED结构,并处理可能的异步完成通知。如果你使用I/O完成端口,则必须提供`FileIOCompletionRoutine回调。

3.69 函数名:WritePrivateProfileSection


(1)函数的概述
WritePrivateProfileSection 函数用于将一个字符串列表(通常是键值对的形式)写入到一个初始化文件(.ini文件)的指定部分中。如果指定的部分已经存在,则该函数会替换该部分的内容;如果部分不存在,则该函数会添加一个新的部分。

(2)函数所在的动态链接库
WritePrivateProfileSection 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL WritePrivateProfileSection(  
  LPCTSTR lpAppName,  
  LPCTSTR lpString,  
  LPCTSTR lpFileName  
);


(4)各参数及返回值的详细解释

  • lpAppName:一个指向字符串的指针,该字符串指定了要写入文件的节的名称。如果此参数为NULL,则该函数将删除整个文件。
  • lpString:一个指向以null结尾的字符串的指针,该字符串包含要写入节的键值对。如果此参数为NULL,则该函数会删除指定的节及其所有条目。
  • lpFileName:一个指向以null结尾的字符串的指针,该字符串指定了要写入其数据的初始化文件的名称。
  • 返回值:如果函数成功,返回值为非零(TRUE)。如果函数失败,返回值为零(FALSE)。要获取扩展的错误信息,请调用GetLastError。

(5)函数的详细作用
WritePrivateProfileSection 函数主要用于在Windows的.ini文件中写入数据。这些文件通常用于存储应用程序的配置信息。通过调用此函数,应用程序可以将一组键值对作为一个节写入到文件中,或者替换、删除现有的节。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* sectionName = "MySection";  
    const char* dataToWrite = "Key1=Value1\nKey2=Value2";  
    const char* fileName = "example.ini";  
  
    BOOL result = WritePrivateProfileSection(sectionName, dataToWrite, fileName);  
    if (result) {  
        std::cout << "Data written successfully." << std::endl;  
    } else {  
        std::cerr << "Failed to write data: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


在这个例子中,我们创建了一个名为"MySection"的节,并向其中写入了两个键值对:"Key1=Value1"和"Key2=Value2"。这些数据将被写入到名为"example.ini"的文件中。

(7)使用时的注意事项

  1. 确保你有足够的权限来写入指定的文件。
  2. 如果指定的文件不存在,并且父目录具有写权限,则该函数将创建该文件。
  3. 如果文件是只读的,则该函数将失败,并返回错误代码ERROR_FILE_READ_ONLY。
  4. 如果lpAppName为NULL,并且文件存在,则该函数将删除整个文件。这是一个危险的操作,因为它会删除文件中的所有数据。
  5. 使用该函数时,应始终检查返回值以确保操作成功。如果操作失败,可以使用GetLastError函数获取更详细的错误信息。
  6. 对于大型配置文件或需要频繁读写配置的应用程序,建议使用更现代的配置存储方法,如XML文件、JSON文件或注册表,因为这些方法通常具有更好的性能和可维护性。

3.70 函数名:WritePrivateProfileString


(1)函数的概述
WritePrivateProfileString 函数用于将一个键值对写入到一个初始化文件(.ini文件)的指定部分中。如果指定的键已经存在,则该函数会替换该键的值;如果键不存在,则该函数会添加一个新的键值对。

(2)函数所在的动态链接库
WritePrivateProfileString 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

DWORD WritePrivateProfileString(  
  LPCTSTR lpAppName,  
  LPCTSTR lpKeyName,  
  LPCTSTR lpString,  
  LPCTSTR lpFileName  
);


(4)各参数及返回值的详细解释

  • lpAppName:一个指向字符串的指针,该字符串指定了要写入数据的节的名称。
  • lpKeyName:一个指向字符串的指针,该字符串指定了要写入或替换的键的名称。如果这个参数为NULL,则lpString指向的字符串会被写入到lpAppName指定的节的开始处,并覆盖该节已有的所有键值对。
  • lpString:一个指向以null结尾的字符串的指针,该字符串包含与lpKeyName参数指定的键相关联的值。如果这个参数为NULL,则指定的键会从lpAppName指定的节中删除。
  • lpFileName:一个指向以null结尾的字符串的指针,该字符串指定了要写入其数据的初始化文件的名称。
  • 返回值:如果函数成功,返回值为非零值。如果函数失败,返回值为0。要获取扩展的错误信息,请调用GetLastError。

(5)函数的详细作用
WritePrivateProfileString 函数用于修改或添加初始化文件(.ini文件)中的键值对。这些文件通常用于存储应用程序的配置信息。通过调用此函数,应用程序可以将一个键值对写入到文件的指定节中,或者删除一个键。

(6)函数的C++示

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* sectionName = "MySection";  
    const char* keyName = "Key1";  
    const char* value = "NewValue";  
    const char* fileName = "example.ini";  
  
    DWORD result = WritePrivateProfileString(sectionName, keyName, value, fileName);  
    if (result != 0) {  
        std::cout << "Key-Value pair written successfully." << std::endl;  
    } else {  
        std::cerr << "Failed to write Key-Value pair: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


在这个例子中,我们创建或修改了名为"MySection"的节中的"Key1"键,并为其赋值为"NewValue"。这些数据将被写入到名为"example.ini"的文件中。

(7)使用时的注意事项

  1. 确保你有足够的权限来写入指定的文件。
  2. 如果指定的文件不存在,并且父目录具有写权限,则该函数将创建该文件。
  3. 如果文件是只读的,则该函数将失败,并返回错误代码ERROR_FILE_READ_ONLY。
  4. 在调用此函数之前,请确保你理解lpKeyName参数为NULL时的行为,因为它会覆盖整个节的内容。
  5. 总是检查函数的返回值以确保操作成功。如果操作失败,可以使用GetLastError函数获取更详细的错误信息。
  6. 对于大型配置文件或需要频繁读写配置的应用程序,建议使用更现代的配置存储方法,如XML文件、JSON文件或注册表,因为这些方法通常具有更好的性能和可维护性。

3.71 函数名:WriteProfileString


(1)函数的概述
WriteProfileString 函数是 Windows API 中的一个函数,用于在 Windows 的初始化文件(.ini 文件)中写入一个字符串值。此函数已过时,并且在 Windows Vista 及更高版本中已被 WritePrivateProfileString 函数取代。但在较旧的 Windows 版本中,它仍然可用。

(2)函数所在的动态链接库
WriteProfileString 函数位于 Kernel32.dll 动态链接库中。

(3)函数的原型

BOOL WriteProfileString(  
  LPCTSTR lpAppName,  
  LPCTSTR lpKeyName,  
  LPCTSTR lpString  
);


注意:与 WritePrivateProfileString 不同,WriteProfileString 没有直接指定文件名的参数,因为它默认使用 Windows 应用程序的 .ini 文件,这些文件通常位于 Windows 目录下的 system.ini、win.ini 或特定于应用程序的 .ini 文件中。

(4)各参数及返回值的详细解释

  • lpAppName:指向一个字符串的指针,该字符串指定了要写入数据的节(部分)的名称。
  • lpKeyName:指向一个字符串的指针,该字符串指定了要写入或替换的键的名称。
  • lpString:指向一个以 null 结尾的字符串的指针,该字符串包含与 lpKeyName 参数指定的键相关联的值。
  • 返回值:如果函数成功,返回值为非零值(TRUE)。如果函数失败,返回值为零(FALSE)。要获取扩展的错误信息,可以调用 GetLastError。

(5)函数的详细作用
WriteProfileString 函数用于在 Windows 的默认 .ini 文件中写入一个键值对。这些文件通常用于存储应用程序的配置信息。然而,由于此函数没有直接指定文件名的参数,它通常用于写入系统级或特定于 Windows 的 .ini 文件,而不是应用程序特定的 .ini 文件。

(6)函数的C++示例(注意:由于 WriteProfileString 已过时,这里仅提供示例)

#include <windows.h>  
#include <iostream>  
  
int main() {  
    const char* sectionName = "MySection";  
    const char* keyName = "MyKey";  
    const char* value = "MyValue";  
  
    // 注意:WriteProfileString 已被 WritePrivateProfileString 取代  
    // 并且通常不推荐用于写入应用程序特定的 .ini 文件  
    BOOL result = WriteProfileString(sectionName, keyName, value);  
    if (result) {  
        std::cout << "Key-Value pair written successfully." << std::endl;  
    } else {  
        std::cerr << "Failed to write Key-Value pair: " << GetLastError() << std::endl;  
    }  
  
    return 0;  
}


注意:此示例仅用于说明目的,并不推荐在实际应用程序中使用 WriteProfileString。

(7)使用时的注意事项

  1. WriteProfileString 函数已过时,并且在 Windows Vista 及更高版本中已被 WritePrivateProfileString 取代。因此,如果你的应用程序需要在这些操作系统上运行,你应该使用 WritePrivateProfileString。
  2. 由于 WriteProfileString 写入的是系统级的 .ini 文件,因此它需要管理员权限才能成功写入。
  3. 在使用此函数时,请确保你了解它将数据写入哪个 .ini 文件,并确保你的应用程序有适当的权限来修改该文件。
  4. 如果你的应用程序需要创建或修改应用程序特定的配置文件,建议使用更现代的方法,如 XML、JSON 或注册表项。

其它API链接:

windows API函数集

windows API函数之文件类函数(一)

windows API函数之文件类函数(二)

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hn_tzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值