You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++ Win32 API判断Windows共享路径重复或获取文件夹唯一ID

Resolving Duplicate UNC Paths in C++ with Win32 API

To identify and remove duplicate UNC paths pointing to the same shared folder (like \\anil-win10\TestFolder and \\10.130.63.10\TestFolder), we need to:

  1. Parse each UNC path to extract the server identifier (hostname/IP) and share name.
  2. Verify if two server identifiers refer to the same machine via DNS resolution.
  3. Compare share names (case-insensitive, as Windows shares are case-insensitive).

Here's a practical implementation using Win32 API functions:

Step 1: Helper Functions

First, let's build utility functions to handle path parsing, server resolution, and server comparison.

Parse UNC Path

Extracts the server and share name from a valid UNC path:

#include <windows.h>
#include <shlwapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <vector>
#include <string>
#include <cstring>

#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "ws2_32.lib")

bool ParseUNCPath(const wchar_t* path, std::wstring& server, std::wstring& share) {
    if (!PathIsUNC(path)) {
        return false;
    }

    // Skip leading backslashes
    const wchar_t* ptr = path + 2;
    const wchar_t* serverEnd = wcschr(ptr, L'\\');
    if (!serverEnd) {
        return false;
    }

    server = std::wstring(ptr, serverEnd - ptr);
    ptr = serverEnd + 1;

    // Extract share name (ignore subdirectories if present)
    const wchar_t* shareEnd = wcschr(ptr, L'\\');
    if (shareEnd) {
        share = std::wstring(ptr, shareEnd - ptr);
    } else {
        share = ptr;
    }

    return true;
}

Resolve Server to IP Addresses

Gets all IP addresses associated with a server name (hostname or IP):

std::vector<std::wstring> GetIPAddresses(const wchar_t* serverName) {
    std::vector<std::wstring> ips;
    struct addrinfo hints = {0};
    hints.ai_family = AF_UNSPEC; // Support IPv4 and IPv6
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    struct addrinfo* result = nullptr;
    int res = getaddrinfo(serverName, nullptr, &hints, &result);
    if (res != 0) {
        return ips;
    }

    for (struct addrinfo* addrPtr = result; addrPtr != nullptr; addrPtr = addrPtr->ai_next) {
        wchar_t ipStr[INET6_ADDRSTRLEN] = {0};
        if (addrPtr->ai_family == AF_INET) {
            struct sockaddr_in* sockAddr = reinterpret_cast<struct sockaddr_in*>(addrPtr->ai_addr);
            InetNtopW(AF_INET, &sockAddr->sin_addr, ipStr, INET6_ADDRSTRLEN);
        } else if (addrPtr->ai_family == AF_INET6) {
            struct sockaddr_in6* sockAddr = reinterpret_cast<struct sockaddr_in6*>(addrPtr->ai_addr);
            InetNtopW(AF_INET6, &sockAddr->sin6_addr, ipStr, INET6_ADDRSTRLEN);
        }
        ips.push_back(ipStr);
    }

    freeaddrinfo(result);
    return ips;
}

Check if Two Servers Are Identical

Compares server identifiers by checking overlapping IPs and reverse DNS resolution:

bool AreServersSame(const wchar_t* server1, const wchar_t* server2) {
    // Direct match first
    if (_wcsicmp(server1, server2) == 0) {
        return true;
    }

    // Get all IPs for both servers
    auto ips1 = GetIPAddresses(server1);
    auto ips2 = GetIPAddresses(server2);

    // Look for overlapping IP addresses
    for (const auto& ip1 : ips1) {
        for (const auto& ip2 : ips2) {
            if (_wcsicmp(ip1.c_str(), ip2.c_str()) == 0) {
                return true;
            }
        }
    }

    // Reverse DNS: Check if server1 (IP) resolves to server2 (hostname)
    wchar_t hostName[NI_MAXHOST] = {0};
    struct sockaddr_storage ss = {0};
    int res = InetPtonW(AF_INET, server1, &reinterpret_cast<struct sockaddr_in*>(&ss)->sin_addr);
    if (res == 1) {
        ss.ss_family = AF_INET;
        res = getnameinfo(reinterpret_cast<struct sockaddr*>(&ss), sizeof(ss), hostName, NI_MAXHOST, nullptr, 0, NI_NAMEREQD);
        if (res == 0 && _wcsicmp(hostName, server2) == 0) {
            return true;
        }
    } else {
        res = InetPtonW(AF_INET6, server1, &reinterpret_cast<struct sockaddr_in6*>(&ss)->sin6_addr);
        if (res == 1) {
            ss.ss_family = AF_INET6;
            res = getnameinfo(reinterpret_cast<struct sockaddr*>(&ss), sizeof(ss), hostName, NI_MAXHOST, nullptr, 0, NI_NAMEREQD);
            if (res == 0 && _wcsicmp(hostName, server2) == 0) {
                return true;
            }
        }
    }

    // Reverse DNS: Check if server2 (IP) resolves to server1 (hostname)
    memset(hostName, 0, sizeof(hostName));
    res = InetPtonW(AF_INET, server2, &reinterpret_cast<struct sockaddr_in*>(&ss)->sin_addr);
    if (res == 1) {
        ss.ss_family = AF_INET;
        res = getnameinfo(reinterpret_cast<struct sockaddr*>(&ss), sizeof(ss), hostName, NI_MAXHOST, nullptr, 0, NI_NAMEREQD);
        if (res == 0 && _wcsicmp(hostName, server1) == 0) {
            return true;
        }
    } else {
        res = InetPtonW(AF_INET6, server2, &reinterpret_cast<struct sockaddr_in6*>(&ss)->sin6_addr);
        if (res == 1) {
            ss.ss_family = AF_INET6;
            res = getnameinfo(reinterpret_cast<struct sockaddr*>(&ss), sizeof(ss), hostName, NI_MAXHOST, nullptr, 0, NI_NAMEREQD);
            if (res == 0 && _wcsicmp(hostName, server1) == 0) {
                return true;
            }
        }
    }

    return false;
}

Step 2: Deduplication Function

Iterates through the path list, checking for duplicates using the helper functions:

std::vector<std::wstring> DeduplicateUNCPaths(const std::vector<std::wstring>& paths) {
    std::vector<std::wstring> uniquePaths;

    for (const auto& path : paths) {
        std::wstring server, share;
        if (!ParseUNCPath(path.c_str(), server, share)) {
            // Add non-UNC paths directly (treat as unique)
            uniquePaths.push_back(path);
            continue;
        }

        bool isDuplicate = false;
        for (const auto& existingPath : uniquePaths) {
            std::wstring existingServer, existingShare;
            if (!ParseUNCPath(existingPath.c_str(), existingServer, existingShare)) {
                continue;
            }

            // Compare share names case-insensitively
            if (_wcsicmp(share.c_str(), existingShare.c_str()) != 0) {
                continue;
            }

            if (AreServersSame(server.c_str(), existingServer.c_str())) {
                isDuplicate = true;
                break;
            }
        }

        if (!isDuplicate) {
            uniquePaths.push_back(path);
        }
    }

    return uniquePaths;
}

Step 3: Usage Example

int main() {
    // Initialize Winsock
    WSADATA wsaData;
    int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (res != 0) {
        return 1;
    }

    std::vector<std::wstring> paths = {
        L"\\\\anil-win10\\TestFolder",
        L"\\\\10.130.63.10\\TestFolder",
        L"\\\\another-server\\SharedDocs"
    };

    auto uniquePaths = DeduplicateUNCPaths(paths);

    // Print unique paths
    for (const auto& path : uniquePaths) {
        wprintf(L"Unique path: %s\n", path.c_str());
    }

    WSACleanup();
    return 0;
}

Key Notes

  • Case Insensitivity: Windows shares and server names are case-insensitive, so all comparisons use _wcsicmp.
  • DNS Resolution: Relies on DNS to resolve hostnames to IPs and vice versa. If DNS fails (e.g., offline server), the function treats paths as unique (a safe default).
  • Dependencies: Links against shlwapi.lib (for PathIsUNC) and ws2_32.lib (for Winsock functions).
  • Edge Cases: Doesn't handle server aliases or NetBIOS names that don't resolve via DNS. For those, you might need NetBIOS functions like NetServerGetInfo, which requires additional permissions.

内容的提问来源于stack exchange,提问作者Anil8753

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:54:11