【发布时间】:2014-03-29 12:43:39
【问题描述】:
我目前有一个方法使用 ShellExecute 打开用户传入的文件。最近发现当文件名包含撇号 (ALT+0146) 或 Mac 简单引号时,ShellExecute 会返回 File Not Found Error。示例文件名:“C:\Users\AMS\Documents\te'st.txt”
代码:
void sys_ShellExecute( PA_PluginParameters params )
{
LONG_PTR returnValue = 0;
char returnText[255]; // MWD & Mark De Wever #12225
INT_PTR howToShow;
char *pChar;
char *operation = NULL;
char *file = NULL;
char *parameters = NULL;
char *directory = NULL;
//PA_Unistring *file; // AMS 2/24/14
// Get the function parameters.
operation = getTextParameter(params, 1);
file = getTextParameter(params, 2);
//file = PA_GetStringParameter(params, 2); // AMS 2/24/14
parameters = getTextParameter(params, 3);
directory = getTextParameter(params, 4);
howToShow = PA_GetLongParameter( params, 5 );
if ((strcmp(_strlwr(operation), "open") != 0) &&
(strcmp(_strlwr(operation), "explore") != 0) &&
(strcmp(_strlwr(operation), "print") != 0) &&
(file == NULL || strlen(file) == 0)) {
//strcpy(returnText, "Invalid Operation");
strncpy(returnText, message->InvalidOperation, 255); // Mark De Wever #12225 replaced the line above
}
else if (howToShow > 11) {
//strcpy(returnText, "Invalid HowToShow Constant");
strncpy(returnText, message->InvalidShowConstant, 255); // Mark De Wever #12225 replaced the line above
}
else
{
pChar = file; // added 10/28/02 shellExecute wants backslashes
do {
if (*pChar == '/') {
*pChar = '\\';
}
} while (*pChar++ != '\0') ;
pChar = directory;
do {
if (*pChar == '/') {
*pChar = '\\';
}
} while (*pChar++ != '\0');
returnValue = (LONG_PTR) ShellExecute(NULL, operation, file, parameters, directory, howToShow);
strcpy(returnText, "");
if (returnValue <= 32) { // error occurred
switch (returnValue)
{
case ERROR_FILE_NOT_FOUND :
//strcpy(returnText, "File Not Found");
strncpy(returnText, message->FileNotFound, 255); // Mark De Wever #12225 replaced line above
break;
case ERROR_PATH_NOT_FOUND :
//strcpy(returnText, "Path Not Found");
strncpy(returnText, message->PathNotFound, 255); // Mark De Wever #12225 Replaced line above
break;
case ERROR_BAD_FORMAT :
//strcpy(returnText, ".EXE File is Invalid");
strncpy(returnText, message->BadFormat, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_ACCESSDENIED :
//strcpy(returnText, "OS Denied Access to File");
strncpy(returnText, message->AccessDenied, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_ASSOCINCOMPLETE :
//strcpy(returnText, "File Name Association is Incomplete or Invalid");
strncpy(returnText, message->AssocIncomplete, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DDEBUSY :
case SE_ERR_DDEFAIL :
//strcpy(returnText, "DDE Transaction Could Not be Completed");
strncpy(returnText, message->DDEFail, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DDETIMEOUT :
//strcpy(returnText, "DDE Request Timed Out");
strncpy(returnText, message->DDETimeOut, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DLLNOTFOUND :
//strcpy(returnText, "DLL Libray Not Found");
strncpy(returnText, message->DLLNotFound, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_NOASSOC :
//strcpy(returnText, "No Application Associated with File Extenstion");
strncpy(returnText, message->NoAssoc, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_OOM :
//strcpy(returnText, "Insufficient Memory");
strncpy(returnText, message->OOM, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_SHARE :
//strcpy(returnText, "Sharing Violation Occurred");
strncpy(returnText, message->ShareViolation, 255); // Mark De Wever #12225 Replaced line above
break;
default:
//strcpy(returnText, "Unknown error occurred");
strncpy(returnText, message->Default, 255); // Mark De Wever #12225 Replaced line above
break;
}
}
}
freeTextParameter(operation);
freeTextParameter(file);
freeTextParameter(parameters);
freeTextParameter(directory);
PA_ReturnText( params, returnText, strlen(returnText));
}
getText参数代码:
char * getTextParameter(PA_PluginParameters param, short index)
{
char *textValue = NULL;
LONG_PTR textLength = 0;
textLength = PA_GetTextParameter( param, index, 0L ) + 1;
// modified by Mark de Wever on 20060721
// textLength was always > 0 due to the +1
// revert change since sys_ShellExecute
// fails if NULL pointer is returned...
// So if malloc fails it will crash 4D
// if(textLength > 1) {
if(textLength > 0) {
textValue = (char *)malloc(textLength);
if(textValue != NULL) {
memset(textValue, 0, textLength);
textLength = PA_GetTextParameter( param, index, textValue );
}
}
return textValue;
}
PA_GetText参数代码:
LONG_PTR PA_GetTextParameter( PA_PluginParameters params, short index, char* text )
{
PA_Unistring *UnistringText;
LONG_PTR length;
char *textParameter;
UnistringText = PA_GetStringParameter( params, index);
if(text != 0L){
textParameter = malloc((UnistringText->fLength + 1) * sizeof(char));
memset(textParameter, 0, ((UnistringText->fLength + 1) * sizeof(char)));
wcstombs(textParameter, UnistringText->fString, UnistringText->fLength);
textParameter[strlen(textParameter)] = '\0';
strcpy(text, textParameter);
free (textParameter);
length = strlen(text);
}else{
length = UnistringText->fLength;
}
return length;
}
我注意到 wcstombs 在 textParameter 中返回不带撇号的文件名,在 UnistringText->fString 中返回完整文件名。
我尝试过使用 ShellExecuteW、ShellExecuteA、将文件设置为 unicode 字符串以及许多其他变体,但似乎没有任何效果。我错过了什么吗?有没有办法解决这个问题?
【问题讨论】:
-
试试processmoitor 实用程序。使用此程序,您可以监视哪个进程打开了哪些文件。它非常强大,可以帮助您发现问题。
-
如果您调用 ShellExecuteW 将文件名作为文字 unicode 字符串(例如
L"C:\\Users\\AMS\\Documents\\te'st.txt")传递,它是否有效?如果是这样,请不要对原始字符串 (UnistringText->fString) 应用任何转换,它应该可以正常工作。
标签: c winapi unicode shellexecute