diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in index 54ff0eeafd5..79537960186 100644 --- a/dlls/shell32/Makefile.in +++ b/dlls/shell32/Makefile.in @@ -32,6 +32,7 @@ C_SRCS = \ shellpath.c \ shellstring.c \ shellreg.c \ + shlexec.c \ shlfileop.c \ shlfolder.c \ shlview.c \ diff --git a/dlls/shell32/shell.c b/dlls/shell32/shell.c index 94068ac3f01..2a141a2726f 100644 --- a/dlls/shell32/shell.c +++ b/dlls/shell32/shell.c @@ -2,6 +2,7 @@ * Shell Library Functions * * 1998 Marcus Meissner + * 2002 Eric Pouech */ #include "config.h" @@ -18,6 +19,7 @@ #include "shellapi.h" #include "shlobj.h" #include "shlwapi.h" +#include "ddeml.h" #include "wine/winbase16.h" #include "wine/winuser16.h" @@ -165,302 +167,6 @@ BOOL16 WINAPI DragQueryPoint16(HDROP16 hDrop, POINT16 *p) return bRet; } -/************************************************************************* - * SHELL_FindExecutable [Internal] - * - * Utility for code sharing between FindExecutable and ShellExecute - */ -HINSTANCE SHELL_FindExecutable( LPCSTR lpFile, - LPCSTR lpOperation, - LPSTR lpResult) -{ char *extension = NULL; /* pointer to file extension */ - char tmpext[5]; /* local copy to mung as we please */ - char filetype[256]; /* registry name for this filetype */ - LONG filetypelen=256; /* length of above */ - char command[256]; /* command from registry */ - LONG commandlen=256; /* This is the most DOS can handle :) */ - char buffer[256]; /* Used to GetProfileString */ - HINSTANCE retval=31; /* default - 'No association was found' */ - char *tok; /* token pointer */ - int i; /* random counter */ - char xlpFile[256] = ""; /* result of SearchPath */ - - TRACE("%s\n", (lpFile != NULL?lpFile:"-") ); - - lpResult[0]='\0'; /* Start off with an empty return string */ - - /* trap NULL parameters on entry */ - if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL )) - { WARN_(exec)("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n", - lpFile, lpOperation, lpResult); - return 2; /* File not found. Close enough, I guess. */ - } - - if (SearchPathA( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL)) - { TRACE("SearchPathA returned non-zero\n"); - lpFile = xlpFile; - } - - /* First thing we need is the file's extension */ - extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */ - /* File->Run in progman uses */ - /* .\FILE.EXE :( */ - TRACE("xlpFile=%s,extension=%s\n", xlpFile, extension); - - if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)])) - { WARN("Returning 31 - No association\n"); - return 31; /* no association */ - } - - /* Make local copy & lowercase it for reg & 'programs=' lookup */ - lstrcpynA( tmpext, extension, 5 ); - CharLowerA( tmpext ); - TRACE("%s file\n", tmpext); - - /* Three places to check: */ - /* 1. win.ini, [windows], programs (NB no leading '.') */ - /* 2. Registry, HKEY_CLASS_ROOT\\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 ( GetProfileStringA("windows", "programs", "exe pif bat com", - buffer, sizeof(buffer)) > 0 ) - { for (i=0;i2)) - { - strcat( lpResult, &tok[2] ); - } - } - retval=33; /* FIXME see above */ - } - } - else /* Check win.ini */ - { - /* Toss the leading dot */ - extension++; - if ( GetProfileStringA( "extensions", extension, "", command, - sizeof(command)) > 0) - { - if (strlen(command)!=0) - { - strcpy( lpResult, command ); - tok=strstr( lpResult, "^" ); /* should be ^.extension? */ - if (tok != NULL) - { - tok[0]='\0'; - strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */ - tok=strstr( command, "^" ); /* see above */ - if ((tok != NULL) && (strlen(tok)>5)) - { - strcat( lpResult, &tok[5]); - } - } - retval=33; /* FIXME - see above */ - } - } - } - - TRACE("returning %s\n", lpResult); - return retval; -} - -/************************************************************************* - * ShellExecute [SHELL.20] - */ -HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation, - LPCSTR lpFile, LPCSTR lpParameters, - LPCSTR lpDirectory, INT16 iShowCmd ) -{ HINSTANCE16 retval=31; - char old_dir[1024]; - char cmd[1024] = ""; - - TRACE("(%04x,'%s','%s','%s','%s',%x)\n", - hWnd, lpOperation ? lpOperation:"", lpFile ? lpFile:"", - lpParameters ? lpParameters : "", - lpDirectory ? lpDirectory : "", iShowCmd); - - if (lpFile==NULL) return 0; /* should not happen */ - if (lpOperation==NULL) /* default is open */ - lpOperation="open"; - - if (lpDirectory) - { GetCurrentDirectoryA( sizeof(old_dir), old_dir ); - SetCurrentDirectoryA( lpDirectory ); - } - - /* First try to execute lpFile with lpParameters directly */ - strcpy(cmd,lpFile); - if (lpParameters) { - strcat(cmd, " " ); - strcat(cmd,lpParameters ); - } - - retval = WinExec16( cmd, iShowCmd ); - - /* Unable to execute lpFile directly - Check if we can match an application to lpFile */ - if(retval < 32) - { - cmd[0] = '\0'; - retval = SHELL_FindExecutable( lpFile, lpOperation, cmd ); - - if (retval > 32) /* Found */ - { - if (lpParameters) - { - strcat(cmd," "); - strcat(cmd,lpParameters); - } - retval = WinExec16( cmd, iShowCmd ); - } - else if(PathIsURLA((LPSTR)lpFile)) /* File not found, check for URL */ - { - char lpstrProtocol[256]; - LONG cmdlen = 512; - LPSTR lpstrRes; - INT iSize; - - lpstrRes = strchr(lpFile,':'); - iSize = lpstrRes - lpFile; - - /* Looking for ...protocol\shell\lpOperation\command */ - strncpy(lpstrProtocol,lpFile,iSize); - lpstrProtocol[iSize]='\0'; - strcat( lpstrProtocol, "\\shell\\" ); - strcat( lpstrProtocol, lpOperation ); - strcat( lpstrProtocol, "\\command" ); - - /* Remove File Protocol from lpFile */ - /* In the case file://path/file */ - if(!strncasecmp(lpFile,"file",iSize)) - { - lpFile += iSize; - while(*lpFile == ':') lpFile++; - } - - - /* Get the application for the protocol and execute it */ - if (RegQueryValue16( HKEY_CLASSES_ROOT, lpstrProtocol, cmd, - &cmdlen ) == ERROR_SUCCESS ) - { - LPSTR tok; - LPSTR tmp; - char param[256] = ""; - LONG paramlen = 256; - - /* Get the parameters needed by the application - from the associated ddeexec key */ - tmp = strstr(lpstrProtocol,"command"); - tmp[0] = '\0'; - strcat(lpstrProtocol,"ddeexec"); - - if(RegQueryValue16( HKEY_CLASSES_ROOT, lpstrProtocol, param,¶mlen ) == ERROR_SUCCESS) - { - strcat(cmd," "); - strcat(cmd,param); - cmdlen += paramlen; - } - - /* Is there a replace() function anywhere? */ - cmd[cmdlen]='\0'; - - tok=strstr( cmd, "%1" ); - if (tok != NULL) - { - tok[0]='\0'; /* truncate string at the percent */ - strcat( cmd, lpFile ); /* what if no dir in xlpFile? */ - tok=strstr( cmd, "%1" ); - if ((tok!=NULL) && (strlen(tok)>2)) - { - strcat( cmd, &tok[2] ); - } - } - - retval = WinExec16( cmd, iShowCmd ); - } - } - /* Check if file specified is in the form www.??????.*** */ - else if(!strncasecmp(lpFile,"www",3)) - { - /* if so, append lpFile http:// and call ShellExecute */ - char lpstrTmpFile[256] = "http://" ; - strcat(lpstrTmpFile,lpFile); - retval = ShellExecuteA(hWnd,lpOperation,lpstrTmpFile,NULL,NULL,0); - } - } - if (lpDirectory) - SetCurrentDirectoryA( old_dir ); - return retval; -} - /************************************************************************* * FindExecutable (SHELL.21) */ diff --git a/dlls/shell32/shell32_main.c b/dlls/shell32/shell32_main.c index 0d837e7a9eb..7557040c6bd 100644 --- a/dlls/shell32/shell32_main.c +++ b/dlls/shell32/shell32_main.c @@ -545,50 +545,6 @@ HICON WINAPI ExtractIconW( HINSTANCE hInstance, LPCWSTR lpszExeFileName, return ret; } -/************************************************************************* - * FindExecutableA [SHELL32.@] - */ -HINSTANCE WINAPI FindExecutableA( LPCSTR lpFile, LPCSTR lpDirectory, - LPSTR lpResult ) -{ - HINSTANCE retval=31; /* default - 'No association was found' */ - char old_dir[1024]; - - TRACE("File %s, Dir %s\n", - (lpFile != NULL?lpFile:"-"), - (lpDirectory != NULL?lpDirectory:"-")); - - lpResult[0]='\0'; /* Start off with an empty return string */ - - /* trap NULL parameters on entry */ - if (( lpFile == NULL ) || ( lpResult == NULL )) - { /* FIXME - should throw a warning, perhaps! */ - return 2; /* File not found. Close enough, I guess. */ - } - - if (lpDirectory) - { GetCurrentDirectoryA( sizeof(old_dir), old_dir ); - SetCurrentDirectoryA( lpDirectory ); - } - - retval = SHELL_FindExecutable( lpFile, "open", lpResult ); - - TRACE("returning %s\n", lpResult); - if (lpDirectory) - SetCurrentDirectoryA( old_dir ); - return retval; -} - -/************************************************************************* - * FindExecutableW [SHELL32.@] - */ -HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, - LPWSTR lpResult) -{ - FIXME("(%p,%p,%p): stub\n", lpFile, lpDirectory, lpResult); - return 31; /* default - 'No association was found' */ -} - typedef struct { LPCSTR szApp; LPCSTR szOtherStuff; @@ -696,36 +652,6 @@ DWORD WINAPI SHLoadInProc (REFCLSID rclsid) return DISP_E_MEMBERNOTFOUND; } -/************************************************************************* - * ShellExecuteA [SHELL32.290] - */ -HINSTANCE WINAPI ShellExecuteA( HWND hWnd, LPCSTR lpOperation, - LPCSTR lpFile, LPCSTR lpParameters, - LPCSTR lpDirectory, INT iShowCmd ) -{ TRACE("\n"); - return ShellExecute16( hWnd, lpOperation, lpFile, lpParameters, - lpDirectory, iShowCmd ); -} - -/************************************************************************* - * ShellExecuteW [SHELL32.294] - * from shellapi.h - * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, - * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd); - */ -HINSTANCE WINAPI -ShellExecuteW( - HWND hwnd, - LPCWSTR lpOperation, - LPCWSTR lpFile, - LPCWSTR lpParameters, - LPCWSTR lpDirectory, - INT nShowCmd) { - - FIXME(": stub\n"); - return 0; -} - /************************************************************************* * AboutDlgProc (internal) */ diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h index 9b4a45a42d2..e3bce53a165 100644 --- a/dlls/shell32/shell32_main.h +++ b/dlls/shell32/shell32_main.h @@ -163,8 +163,6 @@ BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI); BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI); BOOL SHELL_WarnItemDelete(int nKindOfDialog, LPCSTR szDir); -extern HINSTANCE SHELL_FindExecutable(LPCSTR,LPCSTR ,LPSTR); - /* 16-bit functions */ void WINAPI DragAcceptFiles16(HWND16 hWnd, BOOL16 b); UINT16 WINAPI DragQueryFile16(HDROP16 hDrop, WORD wFile, LPSTR lpszFile, WORD wLength); diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c new file mode 100644 index 00000000000..8002ee733d3 --- /dev/null +++ b/dlls/shell32/shlexec.c @@ -0,0 +1,552 @@ +/* + * Shell Library Functions + * + * 1998 Marcus Meissner + * 2002 Eric Pouech + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winerror.h" +#include "winreg.h" +#include "shellapi.h" +#include "shlobj.h" +#include "shlwapi.h" +#include "ddeml.h" + +#include "wine/winbase16.h" +#include "shell32_main.h" + +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(exec); + +/* this function is supposed to expand the escape sequences found in the registry + * some diving reported that the following were used: + * + %1, %2... seem to report to parameter of index N in ShellExecute pmts + + + %* seem to report to all parameter (or all remaining, ie after removing + * the already used %1 %2...) + * + %L seems to be %1 as long filename followed by the 8+3 variation + * + %l unknown + * + %S unknown + * + %I unknown + */ +static void argify(char* res, int len, const char* fmt, const char* lpFile) +{ + char xlpFile[1024]; + + while (*fmt) + { + if (*fmt == '%') + { + switch (*++fmt) + { + case '\0': + case '%': + *res++ = '%'; + break; + case '1': + if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL)) + { + strcpy(res, xlpFile); + res += strlen(xlpFile); + } + else + { + strcpy(res, lpFile); + res += strlen(lpFile); + } + break; + default: FIXME("Unknown escape sequence %%%c\n", *fmt); + } + fmt++; + } + else + *res++ = *fmt++; + } + *res = '\0'; +} + +/************************************************************************* + * 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) + */ +static HINSTANCE SHELL_FindExecutable(LPCSTR lpFile, LPCSTR lpOperation, + LPSTR lpResult, LPSTR key) +{ + char *extension = NULL; /* pointer to file extension */ + char tmpext[5]; /* local copy to mung as we please */ + char filetype[256]; /* registry name for this filetype */ + LONG filetypelen = 256; /* length of above */ + char command[256]; /* command from registry */ + LONG commandlen = 256; /* This is the most DOS can handle :) */ + char buffer[256]; /* Used to GetProfileString */ + HINSTANCE retval = 31; /* default - 'No association was found' */ + char *tok; /* token pointer */ + int i; /* random counter */ + char xlpFile[256] = ""; /* result of SearchPath */ + + TRACE("%s\n", (lpFile != NULL) ? lpFile : "-"); + + lpResult[0] = '\0'; /* Start off with an empty return string */ + + /* trap NULL parameters on entry */ + if ((lpFile == NULL) || (lpResult == NULL) || (lpOperation == NULL)) + { + WARN("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n", + lpFile, lpOperation, lpResult); + return 2; /* File not found. Close enough, I guess. */ + } + + if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL)) + { + TRACE("SearchPathA returned non-zero\n"); + lpFile = xlpFile; + } + + /* First thing we need is the file's extension */ + extension = strrchr(xlpFile, '.'); /* Assume last "." is the one; */ + /* File->Run in progman uses */ + /* .\FILE.EXE :( */ + TRACE("xlpFile=%s,extension=%s\n", xlpFile, extension); + + if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)])) + { + WARN("Returning 31 - No association\n"); + return 31; /* no association */ + } + + /* Make local copy & lowercase it for reg & 'programs=' lookup */ + lstrcpynA(tmpext, extension, 5); + CharLowerA(tmpext); + TRACE("%s file\n", tmpext); + + /* Three places to check: */ + /* 1. win.ini, [windows], programs (NB no leading '.') */ + /* 2. Registry, HKEY_CLASS_ROOT\\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. */ + + if (key) *key = '\0'; + + /* 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 (GetProfileStringA("windows", "programs", "exe pif bat com", + buffer, sizeof(buffer)) > 0) + { + for (i = 0;i 0) + { + if (strlen(command) != 0) + { + strcpy(lpResult, command); + tok = strstr(lpResult, "^"); /* should be ^.extension? */ + if (tok != NULL) + { + tok[0] = '\0'; + strcat(lpResult, xlpFile); /* what if no dir in xlpFile? */ + tok = strstr(command, "^"); /* see above */ + if ((tok != NULL) && (strlen(tok)>5)) + { + strcat(lpResult, &tok[5]); + } + } + retval = 33; /* FIXME - see above */ + } + } + } + + TRACE("returning %s\n", lpResult); + return retval; +} + +/****************************************************************** + * dde_cb + * + * callback for the DDE connection. not really usefull + */ +static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv, + HSZ hsz1, HSZ hsz2, + HDDEDATA hData, DWORD dwData1, DWORD dwData2) +{ + return (HDDEDATA)0; +} + +/****************************************************************** + * 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(char* key, char* start, char* ddeexec, + const char* lpFile, + int iCmdShow, BOOL is32) +{ + char* endkey = key + strlen(key); + char app[256], topic[256], ifexec[256], res[256]; + LONG applen, topiclen, ifexeclen; + char* exec; + DWORD ddeInst = 0; + DWORD tid; + HSZ hszApp, hszTopic; + HCONV hConv; + unsigned ret = 31; + + strcpy(endkey, "\\application"); + applen = sizeof(app); + if (RegQueryValueA(HKEY_CLASSES_ROOT, key, app, &applen) != ERROR_SUCCESS) + { + FIXME("default app name NIY %s\n", key); + return 2; + } + + strcpy(endkey, "\\topic"); + topiclen = sizeof(topic); + if (RegQueryValueA(HKEY_CLASSES_ROOT, key, topic, &topiclen) != ERROR_SUCCESS) + { + strcpy(topic, "System"); + } + + if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR) + { + return 2; + } + + hszApp = DdeCreateStringHandleA(ddeInst, app, CP_WINANSI); + hszTopic = DdeCreateStringHandleA(ddeInst, topic, CP_WINANSI); + + hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL); + exec = ddeexec; + if (!hConv) + { + TRACE("Launching '%s'\n", start); + ret = (is32) ? WinExec(start, iCmdShow) : WinExec16(start, iCmdShow); + if (ret < 32) + { + TRACE("Couldn't launch\n"); + goto error; + } + hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL); + if (!hConv) + { + ret = 30; /* whatever */ + goto error; + } + strcpy(endkey, "\\ifexec"); + ifexeclen = sizeof(ifexec); + if (RegQueryValueA(HKEY_CLASSES_ROOT, key, ifexec, &ifexeclen) == ERROR_SUCCESS) + { + exec = ifexec; + } + } + + argify(res, sizeof(res), exec, lpFile); + TRACE("%s %s => %s\n", exec, lpFile, res); + + ret = (DdeClientTransaction(res, strlen(res) + 1, hConv, 0L, 0, + XTYP_EXECUTE, 10000, &tid) != DMLERR_NO_ERROR) ? 31 : 32; + DdeDisconnect(hConv); + error: + DdeUninitialize(ddeInst); + return ret; +} + +static HINSTANCE execute_from_key(LPSTR key, LPCSTR lpFile, INT iShowCmd, BOOL is32) +{ + char cmd[1024] = ""; + LONG cmdlen = sizeof(cmd); + HINSTANCE retval = 31; + + /* Get the application for the registry */ + if (RegQueryValueA(HKEY_CLASSES_ROOT, key, cmd, &cmdlen) == ERROR_SUCCESS) + { + LPSTR tmp; + char param[256] = ""; + LONG paramlen = 256; + + /* Get the parameters needed by the application + from the associated ddeexec key */ + tmp = strstr(key, "command"); + assert(tmp); + strcpy(tmp, "ddeexec"); + + if (RegQueryValueA(HKEY_CLASSES_ROOT, key, param, ¶mlen) == ERROR_SUCCESS) + { + TRACE("Got ddeexec %s => %s\n", key, param); + retval = dde_connect(key, cmd, param, lpFile, iShowCmd, is32); + } + else + { + /* Is there a replace() function anywhere? */ + cmd[cmdlen] = '\0'; + argify(param, sizeof(param), cmd, lpFile); + + retval = (is32) ? WinExec(param, iShowCmd) : WinExec16(param, iShowCmd); + } + } + else TRACE("ooch\n"); + + return retval; +} + +static HINSTANCE SHELL_Execute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, + LPCSTR lpParameters, LPCSTR lpDirectory, + INT iShowCmd, BOOL is32) +{ + HINSTANCE retval = 31; + char old_dir[1024]; + char cmd[1024]; + + TRACE("(%04x,'%s','%s','%s','%s',%x)\n", + hWnd, lpOperation ? lpOperation:"", lpFile ? lpFile:"", + lpParameters ? lpParameters : "", + lpDirectory ? lpDirectory : "", iShowCmd); + + if (lpFile == NULL) return 0; /* should not happen */ + if (lpOperation == NULL) /* default is open */ + lpOperation = "open"; + + if (lpDirectory) + { + GetCurrentDirectoryA(sizeof(old_dir), old_dir); + SetCurrentDirectoryA(lpDirectory); + } + + /* First try to execute lpFile with lpParameters directly */ + strcpy(cmd, lpFile); + if (lpParameters) + { + strcat(cmd, " "); + strcat(cmd, lpParameters); + } + + retval = (is32) ? WinExec(cmd, iShowCmd) : WinExec16(cmd, iShowCmd); + + /* Unable to execute lpFile directly + Check if we can match an application to lpFile */ + if (retval < 32) + { + char lpstrProtocol[256]; + + cmd[0] = '\0'; + retval = SHELL_FindExecutable(lpFile, lpOperation, cmd, lpstrProtocol); + + if (retval > 32) /* Found */ + { + TRACE("%s/%s => %s/%s\n", lpFile, lpOperation, cmd, lpstrProtocol); + if (*lpstrProtocol) + retval = execute_from_key(lpstrProtocol, lpFile, iShowCmd, is32); + else + retval = (is32) ? WinExec(cmd, iShowCmd) : WinExec16(cmd, iShowCmd); + } + else if (PathIsURLA((LPSTR)lpFile)) /* File not found, check for URL */ + { + LPSTR lpstrRes; + INT iSize; + + lpstrRes = strchr(lpFile, ':'); + iSize = lpstrRes - lpFile; + + TRACE("Got URL: %s\n", lpFile); + /* Looking for ...protocol\shell\lpOperation\command */ + strncpy(lpstrProtocol, lpFile, iSize); + lpstrProtocol[iSize] = '\0'; + strcat(lpstrProtocol, "\\shell\\"); + strcat(lpstrProtocol, lpOperation); + strcat(lpstrProtocol, "\\command"); + + /* Remove File Protocol from lpFile */ + /* In the case file://path/file */ + if (!strncasecmp(lpFile, "file", iSize)) + { + lpFile += iSize; + while (*lpFile == ':') lpFile++; + } + + retval = execute_from_key(lpstrProtocol, lpFile, iShowCmd, is32); + } + /* Check if file specified is in the form www.??????.*** */ + else if (!strncasecmp(lpFile, "www", 3)) + { + /* if so, append lpFile http:// and call ShellExecute */ + char lpstrTmpFile[256] = "http://" ; + strcat(lpstrTmpFile, lpFile); + retval = ShellExecuteA(hWnd, lpOperation, lpstrTmpFile, NULL, NULL, 0); + } + } + if (lpDirectory) + SetCurrentDirectoryA(old_dir); + return retval; +} + +/************************************************************************* + * FindExecutableA [SHELL32.@] + */ +HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult) +{ + HINSTANCE retval = 31; /* default - 'No association was found' */ + char old_dir[1024]; + + TRACE("File %s, Dir %s\n", + (lpFile != NULL ? lpFile : "-"), (lpDirectory != NULL ? lpDirectory : "-")); + + lpResult[0] = '\0'; /* Start off with an empty return string */ + + /* trap NULL parameters on entry */ + if ((lpFile == NULL) || (lpResult == NULL)) + { + /* FIXME - should throw a warning, perhaps! */ + return 2; /* File not found. Close enough, I guess. */ + } + + if (lpDirectory) + { + GetCurrentDirectoryA(sizeof(old_dir), old_dir); + SetCurrentDirectoryA(lpDirectory); + } + + retval = SHELL_FindExecutable(lpFile, "open", lpResult, NULL); + + TRACE("returning %s\n", lpResult); + if (lpDirectory) + SetCurrentDirectoryA(old_dir); + return retval; +} + +/************************************************************************* + * FindExecutableW [SHELL32.@] + */ +HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult) +{ + FIXME("(%p,%p,%p): stub\n", lpFile, lpDirectory, lpResult); + return 31; /* default - 'No association was found' */ +} + +/************************************************************************* + * ShellExecute [SHELL.20] + */ +HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation, + LPCSTR lpFile, LPCSTR lpParameters, + LPCSTR lpDirectory, INT16 iShowCmd ) +{ + return (HINSTANCE16)SHELL_Execute(hWnd, lpOperation, lpFile, + lpParameters, lpDirectory, iShowCmd, FALSE ); +} + +/************************************************************************* + * ShellExecuteA [SHELL32.290] + */ +HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile, + LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd) +{ + TRACE("\n"); + return SHELL_Execute( hWnd, lpOperation, lpFile, lpParameters, + lpDirectory, iShowCmd, TRUE ); +} + +/************************************************************************* + * ShellExecuteW [SHELL32.294] + * from shellapi.h + * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, + * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd); + */ +HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, + LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd) +{ + FIXME(": stub\n"); + return 0; +} +