自己实现快捷方式文件的创建

  最近写个程序需要创建快捷方式,可是烦人的杀软,每次都会拦截,尤其是程序使用的时候,要创建快捷方式就拦截,真是一肚子火啊。
找了很久的资料,终于找到了一篇关于快捷方式文件的数据结构分析的文章:

http://www.vckbase.com/document/viewdoc/?id=1411

经过阅读分析,编码测试,终于搞定了不用IShellLink接口来创建快捷方式


首先复习下快捷方式文件的数据结构(在原先的基础上增加了注释)

 ///////////快捷方式文件格式部分结构///////////// //文件头段 typedef struct _LNKHEAD { DWORD dwID; DWORD dwGUID[4]; DWORD dwFlags; DWORD dwFileAttributes; FILETIME dwCreationTime; FILETIME dwModificationTime; FILETIME dwLastaccessTime; DWORD dwFileLen; DWORD dwIconNum; DWORD dwWinStyle; DWORD dwHotkey; DWORD dwReserved1; DWORD dwReserved2; }LNKHEAD, *PLNKHEAD; //文件位置信息段 typedef struct _FILELOCATIONINFO { DWORD dwSize; DWORD dwFirstOffset; DWORD dwFlags; DWORD dwOffsetOfVolume; DWORD dwOffsetOfBasePath; DWORD dwOffsetOfNetworkVolume; DWORD dwOffsetOfRemainingPath; }FILELOCATIONINFO, *PFILELOCATIONINFO; //本地卷信息表段 typedef struct _LOCALVOLUMETAB { DWORD dwSize; DWORD dwTypeOfVolume; DWORD dwVolumeSerialNumber; DWORD dwOffsetOfVolumeName; char strVolumeName[0];//这个是可变长度因此为 0,不包含在这个结构里 }LOCALVOLUMETAB, *PLOCALVOLUMETAB; //网络卷信息表段 typedef struct _NETWORKVOLUMETAB { DWORD dwSize; DWORD dwUnknown1; DWORD dwOffsetOfNetShareName; DWORD dwUnknown2; DWORD dwUnknown3; char strNetShareName[0];//这个是可变长度因此设为0,不包含在这个结构里 }NETWORKVOLUMETAB, *PNETWORKVOLUMETAB; //主要宏 #define LNK_HASIDLIST 0x1 //是否有Shell item ID list段 #define LNK_FILEDIR 0x2 //指向文件或文件夹,如果此位为0表示指向其他。 #define LNK_HASDES 0x4 //是否存在描述字符串 #define LNK_HASPATH 0x8 //是否存在相对路径 #define LNK_HASWORKDIR 0x10 //是否存在工作路径 #define LNK_HASCMD 0x20 //是否存在命令行参数 #define LNK_HASICO 0x40 //是否存在自定义图标 #define LNK_LOCALVOLUME 0x1 //表示本地卷有效,反之无效 #define LNK_NETSHARE 0x2 //表示网络卷有效,反之无效 // #define LNK_LOCVOLTAB 0x10 //本地卷信息表段固定大小16位(不包含可变部分) #define LINK_URL "http://www.bai.com" //

接下来就是主要的编码实现了

其中主要的函数是:PackageShortCut
该函数基本与Cuick给的程序是一样的,只不过Cuick那边是fread读取分析,而这里是fwrite写数据,同时将需要转换为宽字节的地方转换,其他的就差不多一样了,好了,废话少说,下面给出主要的实现代码(这个只是测试代码,具体的还有很多地方需要判断优化的,需要的话,可以自己改改^_^)

 

//查找指定的文件是否存在,不存在返回FALSE 存在返回TRUE BOOL CDllShellLinkApp::FileExteriorFile(LPCTSTR FileName) { WIN32_FIND_DATA fd; HANDLE hd=::FindFirstFile(FileName,&fd);//开始查找 if(hd==INVALID_HANDLE_VALUE) { return FALSE; } FindClose(hd);//关闭查找 return TRUE; } ////////////////自写快捷方式文件实现///////////////////////////////////// //参考:http://www.vckbase.com/document/viewdoc/?id=1411 bool CDllShellLinkApp::SetMyShellLink(CString strExe) { CString strStartMenuPath,strQuickLaunchPath,strDesktopPath,strShortcut,strPath,strRelpath,strWorkDir; //获取当前用户名 char cUserName[126]; unsigned long lLength = 125; ::GetUserName(cUserName, &lLength); strPath = GetAppPath(strExe); //程序绝对路径 TRACE("%s",strPath); // if (strPath.IsEmpty()) { CString str = strExe + _T("没找到!"); //AfxMessageBox(str); return false; } strWorkDir = strPath.Left(strPath.ReverseFind('//')+1);//程序工作目录 strShortcut=GetBrowserStr(strExe);//快捷方式名称 strRelpath = _T("..//..//..//") + strPath.Mid(3);//取得桌面快捷方式对应程序的相对路径(跨盘无效) //取得桌面位置 if (!GetDesktopMenuDir((PSTR)(LPCSTR)strDesktopPath)) { strDesktopPath.Format(_T("C://Documents and Settings//%s//桌面"),cUserName); } CString strDesktop=strDesktopPath; strDesktopPath=strDesktop + _T("//") + strShortcut; ::DeleteFile(strDesktopPath);//删除原先存在的 PackageShortCut(strDesktopPath.GetBuffer(0),strPath.GetBuffer(0),strRelpath.GetBuffer(0),LINK_URL,strWorkDir.GetBuffer(0)); //取得快速启动栏的位置 if (!GetQuickLaunchDir((PSTR)(LPCSTR)strQuickLaunchPath))// { strQuickLaunchPath.Format("C://Documents and Settings//%s//Application Data//Microsoft//Internet Explorer//Quick Launch",cUserName); } CString strQuick=strQuickLaunchPath; strQuickLaunchPath = strQuick + "//" + strShortcut; ::DeleteFile(strQuickLaunchPath);//删除原先存在的 PackageShortCut(strQuickLaunchPath.GetBuffer(0),strPath.GetBuffer(0),strRelpath.GetBuffer(0),LINK_URL,strWorkDir.GetBuffer(0)); //取得开始菜单的位置 if (!GetStartMenuDir((LPSTR)(LPCSTR)strStartMenuPath)) { strStartMenuPath.Format("C://Documents and Settings//%s//「开始」菜单",cUserName); } CString strStartMenu=strStartMenuPath; strStartMenuPath=strStartMenu + "//" + strShortcut; ::DeleteFile(strStartMenuPath);//删除原先存在的 PackageShortCut(strStartMenuPath.GetBuffer(0),strPath.GetBuffer(0),strRelpath.GetBuffer(0),LINK_URL,strWorkDir.GetBuffer(0)); return true; } //取得文件大小 unsigned long CDllShellLinkApp::GetFileSize(const char *filename) { struct _stat buf; if(_stat(filename, &buf)<0) { return 0; } return (unsigned long)buf.st_size; } //封装lnk文件 void CDllShellLinkApp::PackageShortCut(char *pFileLnk,char *pFileExe,char *pRelPath,char *pCmd,char *pWorkDir) { SYSTEMTIME SystemTime; FILETIME dwSysTime; FILE *file; unsigned short usLenTemp; size_t iSize; LNKHEAD head; FILELOCATIONINFO fileLocationInfo; LOCALVOLUMETAB localVolTab; //本地卷信息表 char szDescription[1024] = {0}; //快捷方式所指向的文件描述 char szCommand[1024] = {0}; WCHAR wszTemp[512]; DWORD dwFlags; int p; //相对路径的话,无法跨盘取到,用绝对路径代替 unsigned short uRelPath = _tcslen(pFileExe);//pRelPath unsigned short uCmd = _tcslen(pCmd); unsigned short uWorkDir = _tcslen(pWorkDir); unsigned long size = GetFileSize(pFileExe); //获得exe文件的大小 unsigned short uPathlen = _tcslen(pFileExe); //程序路径串长度 //获取FILETIME GetSystemTime(&SystemTime); SystemTimeToFileTime(&SystemTime, &dwSysTime); //设置文件头段 head.dwID = 0x4c; head.dwGUID[0] = 136193; //GUID:这四个值由普通快捷方式获取^_^ head.dwGUID[1] = 0; head.dwGUID[2] = 192; head.dwGUID[3] = 1174405120; head.dwFlags = 0xfa; //186:0xba,250:0xfa head.dwFileAttributes = 0x20; head.dwCreationTime = dwSysTime; head.dwModificationTime = dwSysTime; head.dwLastaccessTime = dwSysTime; head.dwFileLen = size; //对应的exe程序文件的大小 head.dwIconNum = 0; //为0:默认为程序的图标 head.dwWinStyle = 1; head.dwHotkey = 0; head.dwReserved1 = 0; head.dwReserved2 = 0; //设置文件位置段 fileLocationInfo.dwSize = 44 + uPathlen*2 +1; //(44=头28+本地卷信息16,无任何附加信息) fileLocationInfo.dwFirstOffset = 0x1c; //头长28 fileLocationInfo.dwFlags = 0x01; fileLocationInfo.dwOffsetOfVolume = 0x1c; //本地卷信息起始位置16 fileLocationInfo.dwOffsetOfBasePath =0x2d; //本地路径信息起始位置0x2c fileLocationInfo.dwOffsetOfNetworkVolume = 0x00; //网络卷信息起始位置(0表示没有) fileLocationInfo.dwOffsetOfRemainingPath = 44 + uPathlen*2; //附加信息位置起始位置(没有这个信息) //本地卷信息表段 localVolTab.dwSize = 16; //本地卷信息表的长度(暂时设置为16,无可变长度段) localVolTab.dwTypeOfVolume = 0x03; //卷类型 localVolTab.dwVolumeSerialNumber = 254859; //卷序列号(暂时以我机子的序列号2219515958赋值) localVolTab.dwOffsetOfVolumeName = 0x10; //固定长度部分的大小,固定为10h // localVolTab.strVolumeName[1] = 0; //这个是可变长度因此设为0,不包含在这个结构里 if((file = fopen(pFileLnk, "wb")) == NULL)//须以二进制写入 { return; } // head iSize = sizeof(LNKHEAD); if (fwrite(&head, 1, iSize, file) != iSize) { fclose(file); return; } //AfxMessageBox(_T("写文件头"));// dwFlags = head.dwFlags; //是否有Shell item ID list段 if(dwFlags & LNK_HASIDLIST) { // The Shell Item Id List if(fwrite(&usLenTemp, 2, 1, file) != 1) { fclose(file); return; } //fread(&szCommand, usLenTemp, 1, file); fseek(file, usLenTemp, SEEK_CUR); } p = ftell(file);//得到当前指针位置(指向文件位置信息段) // file location info if(fwrite(&fileLocationInfo, sizeof(fileLocationInfo), 1, file) != 1) { fclose(file); return; } //AfxMessageBox(_T("写文件信息段")); //写入本地卷信息表 fseek(file, fileLocationInfo.dwOffsetOfVolume + p, SEEK_SET);// iSize = fileLocationInfo.dwOffsetOfBasePath - fileLocationInfo.dwOffsetOfVolume; if(fwrite(&localVolTab, 1, sizeof(LOCALVOLUMETAB), file) != LNK_LOCVOLTAB) { fclose(file); return; } //AfxMessageBox(_T("写本地卷信息段")); //本地卷信息表中的可变长度 size_t ilen = iSize - localVolTab.dwOffsetOfVolumeName; if(fwrite(&szCommand, 1, ilen, file) != ilen) { fclose(file); return; } //写入本地路径信息的位置 fseek(file, fileLocationInfo.dwOffsetOfBasePath + p, SEEK_SET); //是否有网络卷信息段,否则就是本地卷信息段 if(fileLocationInfo.dwFlags & LNK_NETSHARE) { iSize = fileLocationInfo.dwOffsetOfNetworkVolume - fileLocationInfo.dwOffsetOfBasePath; } else { iSize = fileLocationInfo.dwOffsetOfRemainingPath - fileLocationInfo.dwOffsetOfBasePath; } //本地路径信息字串 // if(fwrite(pFileExe, 1, iSize, file) != iSize) // { // fclose(file); // return; // } // 确保数据文件名为ANSI格式 MultiByteToWideChar(CP_ACP, 0, pFileExe, -1, wszTemp, MAX_PATH); //pRelPath wszTemp[uPathlen+1] = '/0'; if(fwrite(&wszTemp, sizeof(WCHAR), uPathlen, file) != uPathlen) { fclose(file); return; } fseek(file, fileLocationInfo.dwSize + p, SEEK_SET); //是否存在描述字符串 if(dwFlags & LNK_HASDES) { // skip Description string if(fwrite(&usLenTemp, 2, 1, file) != 1) { fclose(file); return; } if(fwrite(&wszTemp, sizeof(WCHAR), usLenTemp, file) != usLenTemp) { fclose(file); return; } wszTemp[usLenTemp+1] = '/0'; WideCharToMultiByte( CP_ACP, 0, wszTemp, -1, szDescription, 512, NULL, NULL ); //fseek(file, usLenTemp*2, SEEK_CUR); } //是否存在相对路径 if(dwFlags & LNK_HASPATH) { // skip Relative path if(fwrite(&uRelPath, 2, 1, file) != 1) { fclose(file); return; } // 确保数据文件名为ANSI格式 MultiByteToWideChar(CP_ACP, 0, pFileExe, -1, wszTemp, MAX_PATH); //pRelPath wszTemp[uRelPath+1] = '/0'; if(fwrite(&wszTemp, sizeof(WCHAR), uRelPath, file) != uRelPath) { fclose(file); return; } //AfxMessageBox(_T("写相对路径信息段")); } //是否存在工作路径 if(dwFlags & LNK_HASWORKDIR) { // skip Working directory if(fwrite(&uWorkDir, 2, 1, file) != 1) { fclose(file); return; } // 确保数据文件名为ANSI格式 MultiByteToWideChar(CP_ACP, 0, pWorkDir, -1, wszTemp, MAX_PATH); wszTemp[uWorkDir+1] = '/0'; if(fwrite(&wszTemp, sizeof(WCHAR), uWorkDir, file) != uWorkDir) { fclose(file); return; } //AfxMessageBox(_T("写工作路径段")); } //是否存在命令行参数 if(dwFlags & LNK_HASCMD) { // Command line arguments if(fwrite(&uCmd, 2, 1, file) != 1) { fclose(file); return; } // 确保数据文件名为ANSI格式 MultiByteToWideChar(CP_ACP, 0, pCmd, -1, wszTemp, MAX_PATH); wszTemp[uCmd+1] = '/0'; if(fwrite(&wszTemp, sizeof(WCHAR), uCmd, file) != uCmd) { fclose(file); return; } //AfxMessageBox(_T("写命令参数段")); } //是否存在图标 if(dwFlags & LNK_HASICO) { // Command line arguments if(fwrite(&uPathlen, 2, 1, file) != 1) { fclose(file); return; } // 确保数据文件名为ANSI格式 MultiByteToWideChar(CP_ACP, 0, pFileExe, -1, wszTemp, MAX_PATH); wszTemp[uPathlen+1] = '/0'; if(fwrite(&wszTemp, sizeof(WCHAR), uPathlen, file) != uPathlen) { fclose(file); return; } //AfxMessageBox(_T("写图标段")); } fclose(file); }

 

好了,基本的代码就是这样了,

几个问题:
1、就是我们的正常的快捷方式右键属性里有个兼容性的属性页,而我创建的这个是没有的
     不知道如何填充这个数据,

2、最重要的是删除快捷方式被杀软拦截这个如何避免呢,谁知道的,希望给予指导

3、不知道像Cuick是怎么分析得到快捷方式文件的这些数据结构的,是不是有什么工具?或者什么方法?

 

    望不吝批评指导

你可能感兴趣的:(数据结构,struct,shell,File,command,Path)