windows-nt/Source/XPSP1/NT/shell/tools/blesslnk/blesslnk.cpp
2020-09-26 16:20:57 +08:00

255 lines
7.6 KiB
C++

// blesslnk.cpp : Program to bless a LNK file with darwin descriptor
// or logo3 app name/id
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <shlobj.h>
#include <shlguidp.h>
#include <shlwapi.h>
#include "cdfsubs.hpp"
#include "resource.h"
#define FAIL_ARGS 1
#define FAIL_OLE 2
#define FAIL_LOAD 3
#define FAIL_ENTRY 4
#define FAIL_REG 5
#define FAIL_SHELL 6
#define DARWIN_ID 0x1
#define LOGO3_ID 0x2
// The following strings are used to support the shell link set path feature that
// allows us to bless links for Darwin or Logo3 publising support in IE4
#define DARWINGUID_TAG TEXT("::{9db1186e-40df-11d1-aa8c-00c04fb67863}:")
#define DARWIN_TAG_LEN (ARRAYSIZE(DARWINGUID_TAG)-1)
#define LOGO3GUID_TAG TEXT("::{9db1186f-40df-11d1-aa8c-00c04fb67863}:")
#define LOGO3_TAG_LEN (ARRAYSIZE(LOGO3GUID_TAG)-1)
// checking for shell32 4.72.2106.0 or greater
#define IE401_SHELL_MAJOR 0x0004
#define IE401_SHELL_MINOR 0x48
#define IE401_SHELL_BUILD 0x083a
BOOL IE401ShellAvailable()
{
BOOL bCanBlessLink = FALSE;
DLLGETVERSIONPROC lpfnVersionProc = NULL;
DLLVERSIONINFO dlinfo;
HMODULE hMod = LoadLibrary("shell32.dll");
if (hMod) {
if ( (lpfnVersionProc = (DLLGETVERSIONPROC)GetProcAddress(hMod,"DllGetVersion")) )
{
dlinfo.cbSize = sizeof(DLLVERSIONINFO);
if ( (lpfnVersionProc(&dlinfo) == S_OK) &&
(dlinfo.dwMajorVersion > IE401_SHELL_MAJOR) ||
((dlinfo.dwMajorVersion == IE401_SHELL_MAJOR) &&
(dlinfo.dwMinorVersion >= IE401_SHELL_MINOR)
))
{
bCanBlessLink = TRUE;
if (dlinfo.dwMajorVersion == IE401_SHELL_MAJOR &&
dlinfo.dwMinorVersion == IE401_SHELL_MINOR &&
dlinfo.dwBuildNumber < IE401_SHELL_BUILD)
{
bCanBlessLink = FALSE;
}
}
}
}
if (hMod)
FreeLibrary(hMod);
return bCanBlessLink;
}
HRESULT SetLnkBlessing( IShellLink *pishl, DWORD dwSig, LPSTR szBlessing )
{
HRESULT hr = S_OK;
char szPath[MAX_PATH*4];
char szTarget[MAX_PATH];
if (dwSig == DARWIN_ID) {
lstrcpy(szPath, DARWINGUID_TAG);
} else if (dwSig == LOGO3_ID) {
lstrcpy(szPath, LOGO3GUID_TAG);
}else {
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr)) {
lstrcat(szPath, szBlessing);
lstrcat(szPath, "::");
// get real target
hr = pishl->GetPath(szTarget, MAX_PATH, NULL,0);
// copy real target name
if (SUCCEEDED(hr)) {
lstrcat(szPath, szTarget);
hr = pishl->SetPath( szPath );
}
}
return hr;
}
int __cdecl main(int argc, char * argv[])
{
int iReturn = 0;
HRESULT hr = S_OK;
LPSTR pszLnkName = NULL;
LPSTR pszLogo3ID = NULL;
LPSTR pszDarwinID = NULL;
LPSTR pszCDFURL = NULL;
LPSTR pszTok;
IPersistFile *pipfLnk = NULL;
// Parse command line arguments.
int iTok;
for (iTok = 1; iTok < argc; iTok++)
{
pszTok = argv[iTok];
if ((pszTok[0] == '-') || (pszTok[0] == '/'))
{
switch (pszTok[1])
{
case 'c':
case 'C':
pszCDFURL = argv[iTok+1];
iTok++;
break;
case 'l':
case 'L':
pszLogo3ID = argv[iTok+1];
iTok++;
break;
case 'd':
case 'D':
pszDarwinID = argv[iTok+1];
iTok++;
break;
case '?':
fprintf(stderr, "\nUsage: blesslnk [/l Logo3-ID] [/d Darwin-ID] lnkname\n/l - bless for Logo3 Application Channel notifcation.\n/d - bless for Darwin\n" );
break;
default:
fprintf(stderr, "err - unrecognized flag: %s\n", pszTok);
return FAIL_ARGS;
}
}
else
{
if (pszLnkName == NULL)
{
pszLnkName = pszTok;
break;
}
else
{
fprintf(stderr, "err - extra argument: %s\n", pszTok);
return FAIL_ARGS;
}
}
}
if (pszLnkName == NULL)
{
fprintf(stderr, "err - no lnk file specified\n" );
return FAIL_ARGS;
}
if (!IE401ShellAvailable())
{
fprintf(stderr, "err - Need to have IE401 shell enabled for this feature.\n" );
return FAIL_SHELL;
}
// Initialize OLE.
if (FAILED(CoInitialize(NULL)))
{
return FAIL_OLE;
}
if ( SUCCEEDED(hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IPersistFile, (LPVOID*)&pipfLnk)) )
{
WCHAR szwLnkName[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, pszLnkName, -1, szwLnkName, MAX_PATH );
if ( SUCCEEDED(hr = pipfLnk->Load(szwLnkName, STGM_READ)) )
{
IShellLink *pishl = NULL;
if ( SUCCEEDED(hr = pipfLnk->QueryInterface(IID_IShellLink, (LPVOID*)&pishl)) )
{
if ( pszLogo3ID )
{
if ( FAILED(hr = SetLnkBlessing( pishl, LOGO3_ID, pszLogo3ID )) )
fprintf( stderr, "err - failed to bless %s with Logo3-ID %s\n", pszLnkName, pszLogo3ID );
}
if ( pszDarwinID )
{
if ( FAILED(hr = SetLnkBlessing(pishl, DARWIN_ID, pszDarwinID)) )
fprintf( stderr, "err - failed to bless %s with Darwin-ID %s\n", pszLnkName, pszDarwinID );
}
}
if ( SUCCEEDED(hr) )
hr = pipfLnk->Save( NULL, FALSE );
if ( FAILED(hr) )
fprintf( stderr, "err - failed with error %lx\n", hr );
}
pipfLnk->Release();
}
if (pszCDFURL && SUCCEEDED(hr)) {
// FEATURE: pszLogo3ID is passed instead of a friendly name. In
// the future, we can add another switch to blesslnk to accomodate
// this. Also, we must subscribe with UI (non-silent mode) because
// subscribing will not work properly otherwise.
SubscribeChannel(NULL, pszLogo3ID, pszCDFURL, FALSE);
}
CoUninitialize();
return iReturn;
}