简介
在做垃圾文件清理的时候,会涉及到快捷方式的解析,以确定其是否有效
工作原理
操作系统提供了解析快捷方式的API,其中新型的 msi 快捷方式,多见于Office的程序,其文件路径是类似 msi:xxxx 的ID信息,可以使用 MsiGetShortcutTarget 进行解析。
普通的快捷方式,可以使用IShellLink 来进行解析,但是这种方法有缺陷,比如指向 C:\Program Files\a.exe 的快捷方式,用64位的程序去解析是正确的,但是用32位的程序去解析,就会得到 C:\Program Files (x86)\a.exe,无论是否使用 Wow64DisableWow64FsRedirection 关闭重定向,都是这样,所以只能解析 lnk 数据格式。
优化代码实现
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
// (MAX_PATH * 2)
#define LARGE_PATH 520
LSTATUS ParseLnkGetPath(_In_ CStringA csLnk, _Out_ CStringA& csPath)
{
csLnk.MakeLower(); // 转为小写
if (csLnk.GetLength() < 5) return ERROR_INVALID_PARAMETER;
if (csLnk.Right(4) != ".lnk") return ERROR_INVALID_PARAMETER;
// 获取新型的快捷方式路径(比如OFFICE的)
CHAR szTemp[LARGE_PATH] = { 0 };
CHAR szProductCode[39] = { 0 };
CHAR szFeatureId[MAX_FEATURE_CHARS + 1] = { 0 };
CHAR szComponentCode[39] = { 0 };
LSTATUS ret = MsiGetShortcutTargetA(
(PCSTR)csLnk, szProductCode, szFeatureId, szComponentCode);
if (ret == ERROR_SUCCESS)
{
DWORD dwSize = LARGE_PATH * sizeof(WCHAR);
// 未检测szTemp空间是否足够大
INSTALLSTATE state = MsiGetComponentPathA(
szProductCode, szComponentCode, szTemp, &dwSize);
if (state == INSTALLSTATE_LOCAL)
{
_strlwr_s(szTemp); // 转为小写
csPath = szTemp;
return ERROR_SUCCESS;
}
return ERROR_INVALID_PARAMETER;
}
// 读取快捷方式的内容
ret = ERROR_INVALID_PARAMETER;
HANDLE hFile = CreateFileA((PCSTR)csLnk, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return ret;
// 按照特定格式解析内容
DWORD dwFlag = 0;
DWORD dwReadLen = 0;
if (!ReadFile(hFile, &dwFlag, sizeof(DWORD), &dwReadLen, NULL)) goto Last;
if (dwReadLen != sizeof(DWORD)) goto Last;
if (dwFlag != 0x0000004CUL) goto Last;
DWORD dwRet = SetFilePointer(hFile, 0x00000014L, NULL, FILE_BEGIN);
if (dwRet == INVALID_SET_FILE_POINTER) goto Last;
if (!ReadFile(hFile, &dwFlag, sizeof(DWORD), &dwReadLen, NULL)) goto Last;
if (dwReadLen != sizeof(DWORD)) goto Last;
dwRet = SetFilePointer(hFile, 0x0000004CL, NULL, FILE_BEGIN);
if (dwRet == INVALID_SET_FILE_POINTER) goto Last;
if (dwFlag & 0x00000001UL)
{
WORD wSize = 0;
if (!ReadFile(hFile, &wSize, sizeof(WORD), &dwReadLen, NULL)) goto Last;
if (dwReadLen != sizeof(WORD)) goto Last;
dwRet = SetFilePointer(hFile, (LONG)wSize, NULL, FILE_CURRENT);
if (dwRet == INVALID_SET_FILE_POINTER) goto Last;
}
dwRet = SetFilePointer(hFile, 0x00000010L, NULL, FILE_CURRENT);
if (dwRet == INVALID_SET_FILE_POINTER) goto Last;
if (!ReadFile(hFile, &dwFlag, sizeof(DWORD), &dwReadLen, NULL)) goto Last;
if (dwReadLen != sizeof(DWORD)) goto Last;
dwRet = SetFilePointer(hFile, -0x00000010L - (LONG)sizeof(DWORD) + (LONG)dwFlag, NULL, FILE_CURRENT);
if (dwRet == INVALID_SET_FILE_POINTER) goto Last;
int i = 0;
char ch = 0;
memset(szTemp, 0, sizeof(szTemp));
do
{
if (!ReadFile(hFile, &ch, sizeof(char), &dwReadLen, NULL)) goto Last;
*(szTemp + i++) = ch; // 未检测szTemp空间是否足够大
} while (ch != '\0');
_strlwr_s(szTemp); // 小写
csPath = szTemp;
ret = ERROR_SUCCESS;
Last:
CloseHandle(hFile);
return ret;
}