我目前有一个使用ShellExecute打开用户传入的文件的方法。最近发现当文件名包含撇号(ALT + 0146)或Mac简单引用时,ShellExecute返回File Not Found错误。示例文件名:“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));
}
getTextParameter代码:
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_GetTextParameter代码:
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-&gt; fString中返回完整的文件名。
我尝试过使用ShellExecuteW,ShellExecuteA,将文件设置为unicode字符串,以及许多其他变体,似乎没有任何效果。我错过了什么吗?有办法解决这个问题吗?
答案 0 :(得分:2)
ALT + 0146 是Unicode代码点U+2019 SINGLE QUOTATION MARK
。这与Unicode代码点U+0027 APOSTROPHE
不同。 U + 0027在ASCII范围内,因此wcstomb()
将保持原样,但U + 2019不在ASCII范围内,因此需要进行字符集/代码页转换。如果wcstombs()
省略U + 2019,那通常意味着Windows&#39;默认代码页不支持该特定代码点。但是,您也没有考虑到窄字符串的长度可能与同一字符串的宽版本的长度不同,因此这也可能起到一定作用。
在任何情况下,由于您的输入参数是首先使用的Unicode字符串,因此您应该使用Uncode API函数(如ShellExecuteW()
),而不是将Unicode字符串转换为MBS。
void sys_ShellExecute( PA_PluginParameters params )
{
LONG_PTR returnValue;
char returnText[255]; // MWD & Mark De Wever #12225
wchar_t *pChar;
// Get the function parameters.
wchar_t *operation = getTextParameter(params, 1);
wchar_t *file = getTextParameter(params, 2);
wchar_t *parameters = getTextParameter(params, 3);
wchar_t *directory = getTextParameter(params, 4);
INT_PTR howToShow = PA_GetLongParameter( params, 5 );
if ((lstrcmpiW(operation, L"open") != 0) &&
(lstrcmpiW(operation, L"explore") != 0) &&
(lstrcmpiW(operation, L"print") != 0)) {
strncpy(returnText, message->InvalidOperation, 255); // Mark De Wever #12225 replaced the line above
}
else if ((file == NULL) || (lstrlenW(file) == 0)) {
strncpy(returnText, message->InvalidFile, 255); // Mark De Wever #12225 replaced the line above
}
else if (howToShow > 11) {
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 == L'/') {
*pChar = L'\\';
}
} while (*CharNextW(pChar) != L'\0') ;
if (directory != NULL) {
pChar = directory;
while (*pChar != L'\0') {
if (*pChar == L'/') {
*pChar = L'\\';
}
pChar = CharNext(pChar);
}
}
returnValue = (LONG_PTR) ShellExecuteW(NULL, operation, file, parameters, directory, howToShow);
strcpy(returnText, "");
if (returnValue <= 32) { // error occurred
switch (returnValue)
{
case ERROR_FILE_NOT_FOUND :
strncpy(returnText, message->FileNotFound, 255); // Mark De Wever #12225 replaced line above
break;
case ERROR_PATH_NOT_FOUND :
strncpy(returnText, message->PathNotFound, 255); // Mark De Wever #12225 Replaced line above
break;
case ERROR_BAD_FORMAT :
strncpy(returnText, message->BadFormat, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_ACCESSDENIED :
strncpy(returnText, message->AccessDenied, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_ASSOCINCOMPLETE :
strncpy(returnText, message->AssocIncomplete, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DDEBUSY :
case SE_ERR_DDEFAIL :
strncpy(returnText, message->DDEFail, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DDETIMEOUT :
strncpy(returnText, message->DDETimeOut, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_DLLNOTFOUND :
strncpy(returnText, message->DLLNotFound, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_NOASSOC :
strncpy(returnText, message->NoAssoc, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_OOM :
strncpy(returnText, message->OOM, 255); // Mark De Wever #12225 Replaced line above
break;
case SE_ERR_SHARE :
strncpy(returnText, message->ShareViolation, 255); // Mark De Wever #12225 Replaced line above
break;
default:
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));
}
wchar_t * getTextParameter(PA_PluginParameters param, short index)
{
wchar_t *textValue = NULL;
LONG_PTR 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 = (wchar_t *) malloc(textLength * sizeof(wchar_t));
if(textValue != NULL) {
memset(textValue, 0, textLength * sizeof(wchar_t));
if (textLength > 1) {
PA_GetTextParameter( param, index, textValue );
}
}
}
return textValue;
}
void freeTextParameter(wchar_t *param)
{
free(param);
}
LONG_PTR PA_GetTextParameter( PA_PluginParameters params, short index, wchar_t* text )
{
PA_Unistring *UnistringText;
LONG_PTR length;
UnistringText = PA_GetStringParameter( params, index);
if (UnistringText != NULL) {
length = UnistringText->fLength;
} else {
length = 0;
}
if (text != NULL) {
if (UnistringText != NULL) {
memcpy(text, UnistringText->fString, length * sizeof(wchar_t));
}
text[length] = L'\0';
}
return length;
}