如何用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:
- Parse each UNC path to extract the server identifier (hostname/IP) and share name.
- Verify if two server identifiers refer to the same machine via DNS resolution.
- 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(forPathIsUNC) andws2_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
相关产品推荐
相关产品推荐

