windows - 当两个路径可能是相对路径时,将路径与 Windows API 组合

标签 windows winapi

我需要能够将两个不同的 Windows 路径(它们都可能是相对的)组合成一个路径(通过将第二个应用为第一个的扩展)。文件系统上是否实际存在这两个路径无关紧要。示例:

C:\abc + def -> C:\abc\def
C:\abc + ..\def -> C:\def
\\server\share + def -> \\server\share\def
..\some\path\abc + ..\def -> ..\some\path\def
..\some\path + ..\..\..\def -> ..\..\def

理想情况下,它还应该将驱动器相关的“绝对”路径(即以单个反斜杠开头的路径)解析为给定驱动器上的适当路径:

C:\abc + \def -> C:\def

最后,如果它通过返回绝对路径来处理第二个路径是绝对路径的情况,那就太好了:

C:\abc + D:\def -> D:\def

另一种表达方式是:

我想要一个将路径“A”和路径“B”作为参数的函数。输出“C”应该与我先用 A 调用 SetCurrentDirectory 然后用 B 然后调用 GetCurrentDirectory 相同(但是,路径是否不应该无关紧要'存在,它不应该改变当前的工作目录,如果 A 和 B 都是相对路径,结果应该是相对路径;我并不特别关心结果路径是否包含“..”段)。

代码需要在 Windows 7 上运行。我查看了 shell path handling functions在 Windows API 中,但它们似乎不合适:

  • PathAppend ,第一个路径不能是相对的:

    The path supplied in pszPath cannot begin with "..\" or ".\" to produce a relative path string. If present, those periods are stripped from the output string.

  • PathCombine ,第一个路径不能是相对路径,也不能是 UNC 路径:

    The directory path should be in the form of A:,B:, ..., Z:

(编辑:仔细检查后,该文档片段似乎可能真的属于另一个函数。提到的参数名称与方法签名中给出的参数名称不同。在事实上,正如下面第二个答案所示,PathCombine 似乎确实适用于 UNC 路径。但是,它与 PathAppend 存在同样的问题 - 因为它去除了前导 .. 来自输出路径的片段)。

是否有任何我忽略的标准函数,或者是否有任何库可以正确处理所有情况,包括 UNC 样式路径?或者至少有一种简单的方法可以使用其他已经可用的方法来实现满足我要求的功能?

最佳答案

#include <stdio.h>
#include <stdlib.h>

#ifndef MAX_PATH
#define MAX_PATH 260
#endif

char *rootFolder(char *folder);

int IsFullPath(const char *p){
    if(p && *p){
        if(((*p>='A') && (*p<='Z')) ||((*p>='a') && (*p<='z'))){
            return  p[1]==':';
        }
        return *p=='\\' & p[1]=='\\';
    }
    return 0;
}
/*_______________________________________________________
*/
char *FolderUp(char *path,int deep){



    path=rootFolder(path);
    if(!*path) return path;

    int i=strlen(path);

    char *p=path;
    if(path[i-1]=='\\') path--;

    while(i &&(deep>0)){
         i--;
        if(path[i]=='\\'){
            p=&path[i+1];
            deep--;
        }
    }
    return  p;

}
/*_________________________________________________________________
*/
char *NextFolder(char *path){
    while(*path){
        path++;
        if(*path=='\\'){
            path++;
            break;
        }
    }
    return path;
}
/*_________________________________________________________________
*/
char *rootFolder(char *folder){
    char *p;
    if((*folder=='\\') && (folder[1]=='\\')){
        return NextFolder(&folder[2]);
    }

    if(*folder && folder[1]==':' && folder[2]=='\\')
        return &folder[3];
    return folder;
}


int chdir(/*IN_OUT*/char *curDir,const /*IN*/char *newDir){ 

    int deep=0,i;
    const char *p=newDir,*tmp;


    if(!newDir ||!*newDir ) return 0;

    if(IsFullPath(newDir)){
        strcpy(curDir,newDir);
        return 1;
    }

    if(*newDir=='\\'){
        tmp=rootFolder(curDir);
        if(*tmp!='\\') tmp--;
        strcpy(tmp,newDir);
        return 1;
    }

    /**/

    while(*p && (p[0]=='.' && p[1]=='.')) {
        if(p[2]!='\\') {
            deep=0;
            break;
        }
        p+=3;
        deep++;
    }
    if(deep){
        tmp=FolderUp(curDir,deep);
        if(tmp[-1]!='\\') p--;
        strcpy(tmp,p);
        return 1;
    }

    i=strlen(curDir);
    if(i && curDir[i-1]!='\\'){
        curDir[i]='\\';
        curDir[i+1]=0;
    }
    strcat(curDir,newDir);
    return 1;
    /**/
}

void DoTest(char *curDir,char *newDir){
    char path[MAX_PATH];
    strcpy(path,curDir);

    if(chdir(path,newDir))
        printf("'%s' + '%s' -> %'%s'\n",curDir,newDir,path);
    else
        printf("Error: an unhandled error occured\n");
    return ;

}
int main(){

    DoTest("C:\\abc","def");
    DoTest("C:\\abc","..\\def");
    printf("\n");

    DoTest("C:\\abc\\","def");
    DoTest("C:\\abc\\","..\\def");
    printf("\n");

    DoTest("\\\\server\\share","def");
    DoTest("\\\\server\\share","..\\def");
    printf("\n");

    DoTest("\\\\server\\share\\","def");
    DoTest("\\\\server\\share\\","..\\def");
    printf("\n");

    DoTest("\\\\server","def");
    DoTest("\\\\server","..\\def");
    printf("\n");

    DoTest("\\\\server\\","def");
    DoTest("\\\\server\\","..\\def");
    printf("\n");

    DoTest("c:\\Folder","\\\\server\\share");
    DoTest("\\\\server\\share","c:\\Folder");
    printf("\n");

    DoTest("..\\Folder\\sub folder","..\\sibling");
    printf("\n");
    return 0;
}

这是输出:

'C:\abc' + 'def' -> 'C:\abc\def'
'C:\abc' + '..\def' -> 'C:\def'

'C:\abc\' + 'def' -> 'C:\abc\def'
'C:\abc\' + '..\def' -> 'C:\def'

'\\server\share' + 'def' -> '\\server\share\def'
'\\server\share' + '..\def' -> '\\server\def'

'\\server\share\' + 'def' -> '\\server\share\def'
'\\server\share\' + '..\def' -> '\\server\def'

'\\server' + 'def' -> '\\server\def'
'\\server' + '..\def' -> '\\server\def'

'\\server\' + 'def' -> '\\server\def'
'\\server\' + '..\def' -> '\\server\def'

'c:\Folder' + '\\server\share' -> '\\server\share'
'\\server\share' + 'c:\Folder' -> 'c:\Folder'

'..\Folder\sub folder' + '..\sibling' -> '..\Folder\sibling'

关于windows - 当两个路径可能是相对路径时,将路径与 Windows API 组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33150102/

相关文章:

winapi - Win32 ListView 控制自定义绘制子项的子项填充?

java - Swing 应用程序通过 JNA 调用 GetOpenFileName 失败

c# - 在任务栏中实现单独的应用程序实例,如 Skype

.net - 检测 Windows 中的内存抖动

c++ - Win32 无法添加具有透明度的自定义工具栏图标

windbg - Windows 调试工具未安装

java - 如何将批处理脚本多选集成到JAVA GUI中?

c++ - 使用内置 Windows 方法获取文件夹内容

c++ - 确定处理器对 SSE2 的支持?

c++ - WM_CLOSE事件从不发送/接收?