📄 shlexec.c
字号:
len = MAX_PATH*sizeof(WCHAR);
res = RegQueryValueW(hkApp, NULL, lpResult, &len);
if (res) goto end;
found = TRUE;
if (env)
{
DWORD count = sizeof(buffer);
if (!RegQueryValueExW(hkApp, wPath, NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
*env = SHELL_BuildEnvW( buffer );
}
end:
if (hkApp) RegCloseKey(hkApp);
return found;
}
static UINT SHELL_FindExecutableByOperation(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
{
static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0};
/* Looking for ...buffer\shell\<verb>\command */
strcatW(filetype, wszShell);
strcatW(filetype, lpOperation);
strcatW(filetype, wCommand);
if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
&commandlen) == ERROR_SUCCESS)
{
commandlen /= sizeof(WCHAR);
if (key) strcpyW(key, filetype);
#if 0
LPWSTR tmp;
WCHAR param[256];
LONG paramlen = sizeof(param);
static const WCHAR wSpace[] = {' ',0};
/* FIXME: it seems all Windows version don't behave the same here.
* the doc states that this ddeexec information can be found after
* the exec names.
* on Win98, it doesn't appear, but I think it does on Win2k
*/
/* Get the parameters needed by the application
from the associated ddeexec key */
tmp = strstrW(filetype, wCommand);
tmp[0] = '\0';
strcatW(filetype, wDdeexec);
if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
¶mlen) == ERROR_SUCCESS)
{
paramlen /= sizeof(WCHAR);
strcatW(command, wSpace);
strcatW(command, param);
commandlen += paramlen;
}
#endif
command[commandlen] = '\0';
return 33; /* FIXME see SHELL_FindExecutable() */
}
return 31; /* default - 'No association was found' */
}
/*************************************************************************
* SHELL_FindExecutable [Internal]
*
* Utility for code sharing between FindExecutable and ShellExecute
* in:
* lpFile the name of a file
* lpOperation the operation on it (open)
* out:
* lpResult a buffer, big enough :-(, to store the command to do the
* operation on the file
* key a buffer, big enough, to get the key name to do actually the
* command (it'll be used afterwards for more information
* on the operation)
*/
UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
LPWSTR lpResult, int resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
{
static const WCHAR wWindows[] = {'w','i','n','d','o','w','s',0};
static const WCHAR wPrograms[] = {'p','r','o','g','r','a','m','s',0};
static const WCHAR wExtensions[] = {'e','x','e',' ','p','i','f',' ','b','a','t',' ','c','m','d',' ','c','o','m',0};
WCHAR *extension = NULL; /* pointer to file extension */
WCHAR filetype[256]; /* registry name for this filetype */
LONG filetypelen = sizeof(filetype); /* length of above */
WCHAR command[1024]; /* command from registry */
WCHAR wBuffer[256]; /* Used to GetProfileString */
UINT retval = 31; /* default - 'No association was found' */
WCHAR *tok; /* token pointer */
WCHAR xlpFile[256]; /* result of SearchPath */
DWORD attribs; /* file attributes */
TRACE("%s\n", (lpFile != NULL) ? debugstr_w(lpFile) : "-");
xlpFile[0] = '\0';
lpResult[0] = '\0'; /* Start off with an empty return string */
if (key) *key = '\0';
/* trap NULL parameters on entry */
if ((lpFile == NULL) || (lpResult == NULL) || (lpOperation == NULL))
{
WARN("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
debugstr_w(lpFile), debugstr_w(lpOperation), debugstr_w(lpResult));
return 2; /* File not found. Close enough, I guess. */
}
if (SHELL_TryAppPathW( lpFile, lpResult, env ))
{
TRACE("found %s via App Paths\n", debugstr_w(lpResult));
return 33;
}
if (SearchPathW(lpPath, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
{
TRACE("SearchPathW returned non-zero\n");
lpFile = xlpFile;
/* Hey, isn't this value ignored? Why make this call? Shouldn't we return here? --dank*/
}
attribs = GetFileAttributesW(lpFile);
if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY))
{
strcpyW(filetype, wszFolder);
filetypelen = 6; /* strlen("Folder") */
}
else
{
/* First thing we need is the file's extension */
extension = strrchrW(xlpFile, '.'); /* Assume last "." is the one; */
/* File->Run in progman uses */
/* .\FILE.EXE :( */
TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
if (extension == NULL || extension[1]==0)
{
WARN("Returning 31 - No association\n");
return 31; /* no association */
}
/* Three places to check: */
/* 1. win.ini, [windows], programs (NB no leading '.') */
/* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
/* 3. win.ini, [extensions], extension (NB no leading '.' */
/* All I know of the order is that registry is checked before */
/* extensions; however, it'd make sense to check the programs */
/* section first, so that's what happens here. */
/* See if it's a program - if GetProfileString fails, we skip this
* section. Actually, if GetProfileString fails, we've probably
* got a lot more to worry about than running a program... */
if (GetProfileStringW(wWindows, wPrograms, wExtensions, wBuffer, sizeof(wBuffer)/sizeof(WCHAR)) > 0)
{
CharLowerW(wBuffer);
tok = wBuffer;
while (*tok)
{
WCHAR *p = tok;
while (*p && *p != ' ' && *p != '\t') p++;
if (*p)
{
*p++ = 0;
while (*p == ' ' || *p == '\t') p++;
}
if (strcmpiW(tok, &extension[1]) == 0) /* have to skip the leading "." */
{
strcpyW(lpResult, xlpFile);
/* Need to perhaps check that the file has a path
* attached */
TRACE("found %s\n", debugstr_w(lpResult));
return 33;
/* Greater than 32 to indicate success FIXME According to the
* docs, I should be returning a handle for the
* executable. Does this mean I'm supposed to open the
* executable file or something? More RTFM, I guess... */
}
tok = p;
}
}
/* Check registry */
if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
&filetypelen) == ERROR_SUCCESS)
{
filetypelen /= sizeof(WCHAR);
filetype[filetypelen] = '\0';
TRACE("File type: %s\n", debugstr_w(filetype));
}
}
if (*filetype)
{
if (lpOperation)
{
/* pass the operation string to SHELL_FindExecutableByOperation() */
filetype[filetypelen] = '\0';
retval = SHELL_FindExecutableByOperation(lpPath, lpFile, lpOperation, key, filetype, command, sizeof(command));
}
else
{
WCHAR operation[MAX_PATH];
HKEY hkey;
/* Looking for ...buffer\shell\<operation>\command */
strcatW(filetype, wszShell);
/* enumerate the operation subkeys in the registry and search for one with an associated command */
if (RegOpenKeyW(HKEY_CLASSES_ROOT, filetype, &hkey) == ERROR_SUCCESS)
{
int idx = 0;
for(;; ++idx)
{
if (RegEnumKeyW(hkey, idx, operation, MAX_PATH) != ERROR_SUCCESS)
break;
filetype[filetypelen] = '\0';
retval = SHELL_FindExecutableByOperation(lpPath, lpFile, operation, key, filetype, command, sizeof(command));
if (retval > 32)
break;
}
RegCloseKey(hkey);
}
}
if (retval > 32)
{
SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args);
/* Remove double quotation marks and command line arguments */
if (*lpResult == '"')
{
WCHAR *p = lpResult;
while (*(p + 1) != '"')
{
*p = *(p + 1);
p++;
}
*p = '\0';
}
}
}
else /* Check win.ini */
{
static const WCHAR wExtensions[] = {'e','x','t','e','n','s','i','o','n','s',0};
/* Toss the leading dot */
extension++;
if (GetProfileStringW(wExtensions, extension, wszEmpty, command, sizeof(command)/sizeof(WCHAR)) > 0)
{
if (strlenW(command) != 0)
{
strcpyW(lpResult, command);
tok = strchrW(lpResult, '^'); /* should be ^.extension? */
if (tok != NULL)
{
tok[0] = '\0';
strcatW(lpResult, xlpFile); /* what if no dir in xlpFile? */
tok = strchrW(command, '^'); /* see above */
if ((tok != NULL) && (strlenW(tok)>5))
{
strcatW(lpResult, &tok[5]);
}
}
retval = 33; /* FIXME - see above */
}
}
}
TRACE("returning %s\n", debugstr_w(lpResult));
return retval;
}
/******************************************************************
* dde_cb
*
* callback for the DDE connection. not really useful
*/
static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hData,
ULONG_PTR dwData1, ULONG_PTR dwData2)
{
TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
return NULL;
}
/******************************************************************
* dde_connect
*
* ShellExecute helper. Used to do an operation with a DDE connection
*
* Handles both the direct connection (try #1), and if it fails,
* launching an application and trying (#2) to connect to it
*
*/
static unsigned dde_connect(WCHAR* key, WCHAR* start, WCHAR* ddeexec,
const WCHAR* lpFile, WCHAR *env,
LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
{
static const WCHAR wApplication[] = {'\\','a','p','p','l','i','c','a','t','i','o','n',0};
static const WCHAR wTopic[] = {'\\','t','o','p','i','c',0};
WCHAR * endkey = key + strlenW(key);
WCHAR app[256], topic[256], ifexec[256], res[256];
LONG applen, topiclen, ifexeclen;
WCHAR * exec;
DWORD ddeInst = 0;
DWORD tid;
HSZ hszApp, hszTopic;
HCONV hConv;
HDDEDATA hDdeData;
unsigned ret = 31;
BOOL unicode = !(GetVersion() & 0x80000000);
strcpyW(endkey, wApplication);
applen = sizeof(app);
if (RegQueryValueW(HKEY_CLASSES_ROOT, key, app, &applen) != ERROR_SUCCESS)
{
FIXME("default app name NIY %s\n", debugstr_w(key));
return 2;
}
strcpyW(endkey, wTopic);
topiclen = sizeof(topic);
if (RegQueryValueW(HKEY_CLASSES_ROOT, key, topic, &topiclen) != ERROR_SUCCESS)
{
static const WCHAR wSystem[] = {'S','y','s','t','e','m',0};
strcpyW(topic, wSystem);
}
if (unicode)
{
if (DdeInitializeW(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
return 2;
}
else
{
if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
return 2;
}
hszApp = DdeCreateStringHandleW(ddeInst, app, CP_WINUNICODE);
hszTopic = DdeCreateStringHandleW(ddeInst, topic, CP_WINUNICODE);
hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
exec = ddeexec;
if (!hConv)
{
static const WCHAR wIfexec[] = {'\\','i','f','e','x','e','c',0};
TRACE("Launching '%s'\n", debugstr_w(start));
ret = execfunc(start, env, TRUE, psei, psei_out);
if (ret < 32)
{
TRACE("Couldn't launch\n");
goto error;
}
hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
if (!hConv)
{
TRACE("Couldn't connect. ret=%d\n", ret);
DdeUninitialize(ddeInst);
SetLastError(ERROR_DDE_FAIL);
return 30; /* whatever */
}
strcpyW(endkey, wIfexec);
ifexeclen = sizeof(ifexec);
if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ifexec, &ifexeclen) == ERROR_SUCCESS)
{
exec = ifexec;
}
}
SHELL_ArgifyW(res, sizeof(res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline);
TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
/* It's documented in the KB 330337 that IE has a bug and returns
* error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
*/
if (unicode)
hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0,
XTYP_EXECUTE, 10000, &tid);
else
{
DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
char *resA = HeapAlloc(GetProcessHeap(), 0, lenA);
WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
hDdeData = DdeClientTransaction( (LPBYTE)resA, lenA, hConv, 0L, 0,
XTYP_EXECUTE, 10000, &tid );
HeapFree(GetProcessHeap(), 0, resA);
}
if (hDdeData)
DdeFreeDataHandle(hDdeData);
else
WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
ret = 33;
DdeDisconnect(hConv);
error:
DdeUninitialize(ddeInst);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -