简介这份资源面向具备一定C基础的开发者聚焦VC环境下调用MySQL数据库并访问外网Google服务的实现方案可用于数据库管理、网络通信及Web服务集成等场景的学习与参考。压缩包共41个文件约3.89MB以h头文件、cpp源文件、obj编译中间文件为主另含exe可执行程序、dll与lib动态及静态库、ico图标、rc资源脚本和dsp、dsw工程文件覆盖从源码到可运行工程的完整结构。资源中提供了mysql.h头文件引用、libmysqlclient库链接以及mysql_real_connect建立连接、执行SQL查询并处理结果集的示例代码同时演示了借助cURL向Google Maps Geocoding API等外网服务发送HTTP请求并解析响应的思路有助于读者理解VC与MySQL交互及外网API调用的关键环节。目前已有312人学习下载适合需要动手实践数据库连接与外部服务集成的开发者参考借鉴。1. 从一份 2003 年的 VC6 工程说起它到底解决了什么问题翻到Google.zip这个包的时候我第一反应是「这名字起得真敢」。解压出来一看Google.dsp、Google.dsw、vc60.idb、vc60.pdb全在典型的 Visual C 6.0 工程结构编译产物Google.exe和libmySQL.dll也一并躺在目录里。这不是什么新项目而是一份把「VC 通过 MySQL C API 读写数据库」和「VC 发起 HTTP 请求访问外部服务」两件事揉在一个 MFC 单文档程序里的老工程。标题里那个「连接外网 Google」落到代码层面其实就是用 WinINet 或 socket 去请求 Google 的 HTTP 接口跟今天说的 RESTful 调用是一回事只是年代早、封装薄。它适合谁适合两类人一类是还在维护 VC6 遗留系统、需要把本地数据同步到远端服务的工程师另一类是想搞明白「MFC 程序怎么同时挂数据库和网络请求」的学生或转行者。你不需要把它当成生产级模板但它是一份能跑通的、结构完整的最小闭环比看十篇割裂的 API 文档管用。下面我按「先跑起来、再拆原理、最后说坑」的顺序把这份工程拆开讲。2. 把工程跑起来VC6 环境、libmySQL 链接与 MFC 骨架2.1 先确认你手里有什么解压Google.zip根目录下能看到的文件大致分四类先认清楚再动手不然编译报错你都不知道缺哪块。文件/目录作用是否必须Google.dsw/Google.dspVC6 工作区与工程文件必须双击 dsw 打开GoogleView.cpp/.h、MainFrm.cpp/.h、GoogleDoc.cpp/.hMFC 单文档视图框架必须程序主体googleearth.cpp/.h业务逻辑网络请求相关必须libmySQL.lib/libmySQL.dllMySQL C API 的导入库与运行时必须缺一编译或运行失败res/、Toolbar.bmp、Google.ico资源文件必须否则资源编译报错Debug/已有编译产物可删建议重新编译ReadMe.txt里通常写着原始作者的环境说明先读一遍里面往往有数据库版本和连接参数的线索。2.2 配置 VC6 的包含目录与库目录VC6 默认不认识 MySQL 的头文件和库得手动告诉它。打开Tools → Options → Directories在Include files里加上 MySQL 安装目录下的include在Library files里加上lib目录。这一步是血泪经验很多人直接把libmySQL.lib拷到工程目录就以为完事结果链接阶段报一堆unresolved external symbol就是因为库搜索路径没配。配好之后在Project → Settings → Link的Object/library modules里补上libmySQL.lib多个库用空格隔开。如果你用的是 MySQL 5.x 以上版本注意libmySQL.lib可能是 32 位还是 64 位的问题——VC6 只能编 32 位所以必须用 32 位的库拿 64 位的来链接会直接失败。2.3 让程序先连上本地 MySQL工程里连接数据库的核心代码在googleearth.cpp或GoogleDoc.cpp里逻辑跟下面这段基本一致。先确保本地 MySQL 服务在跑建好库和表再改连接参数。#include mysql.h #include iostream MYSQL* conn; MYSQL_RES* res; MYSQL_ROW row; // 初始化连接句柄 conn mysql_init(NULL); if (conn NULL) { std::cerr mysql_init failed std::endl; return; } // 建立连接主机、用户、密码、库名、端口、socket、flag if (!mysql_real_connect(conn, 127.0.0.1, root, your_password, test_db, 3306, NULL, 0)) { std::cerr connect error: mysql_error(conn) std::endl; mysql_close(conn); return; } // 设置字符集避免中文乱码 mysql_query(conn, SET NAMES utf8); // 执行查询 if (mysql_query(conn, SELECT id, name FROM users)) { std::cerr query error: mysql_error(conn) std::endl; mysql_close(conn); return; } res mysql_store_result(conn); if (res NULL) { std::cerr store result error: mysql_error(conn) std::endl; mysql_close(conn); return; } // 逐行取数据 while ((row mysql_fetch_row(res)) ! NULL) { std::cout id row[0] name row[1] std::endl; } mysql_free_result(res); mysql_close(conn);这段代码有几个参数值得说清楚。mysql_real_connect的第五个参数是端口写 0 表示用默认 3306第六个是 unix socketWindows 下传 NULL第七个是客户端标志位一般填 0需要压缩协议或 SSL 时才改。mysql_store_result会把整个结果集拉到客户端内存数据量大时改用mysql_use_result逐行读但那样就不能在读完前发新查询。SET NAMES utf8这行别省VC6 默认是 GBK 环境不设字符集中文进去就是乱码这是最常见的翻车点之一。2.4 编译时最容易卡住的两个地方第一个是mysql.h找不到。除了目录没配还有一种情况是 MySQL 安装包只带了 Connector/C 而没带 C API 头文件那就得单独装 MySQL Server 或下载对应版本的开发包。第二个是libmySQL.dll运行时找不到。编译通过不代表能跑双击 exe 报「无法启动此程序因为计算机中丢失 libmySQL.dll」把 dll 拷到 exe 同目录或C:\Windows\System32即可。Debug 目录里原本就带着一份 dll说明原作者也是这么干的。3. 从本地到外网VC 里发起 HTTP 请求的三种做法3.1 为什么这份工程选了 WinINet 而不是 cURL标题里「连接外网 Google」听着玄乎本质就是发 HTTP 请求。VC6 时代能用的方案有三类WinINet、WinSock 手写 HTTP、第三方库如 libcurl。这份工程大概率用的是 WinINet因为它是 Windows 自带、不用额外链接库、MFC 里调用最省事。libcurl 功能强但要自己编译或找预编译包在 VC6 下配起来麻烦。WinSock 手写则要自己拼请求头、处理分块传输容易出错。选型逻辑很简单如果你只是发个 GET 拿 JSONWinINet 够用如果要处理 HTTPS、重定向、超时重试、上传大文件libcurl 更稳。这份工程属于前者所以别指望它有多强的网络健壮性。3.2 用 WinINet 发一个 GET 请求下面这段是 WinINet 的标准调用流程放在googleearth.cpp里就能跑。注意它请求的是 Google 的某个 HTTP 接口实际使用时把 URL 换成你要访问的服务地址。#include windows.h #include wininet.h #include string #include iostream #pragma comment(lib, wininet.lib) void HttpGet(const std::string host, const std::string path) { HINTERNET hInternet InternetOpenA(VCApp, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternet) { std::cerr InternetOpen failed: GetLastError() std::endl; return; } // 建立到目标主机的连接端口 80 为 HTTP HINTERNET hConnect InternetConnectA(hInternet, host.c_str(), 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (!hConnect) { std::cerr InternetConnect failed: GetLastError() std::endl; InternetCloseHandle(hInternet); return; } // 打开请求flag 里 INTERNET_FLAG_RELOAD 表示不走缓存 HINTERNET hRequest HttpOpenRequestA(hConnect, GET, path.c_str(), NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0); if (!hRequest) { std::cerr HttpOpenRequest failed: GetLastError() std::endl; InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); return; } // 发送请求 if (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0)) { std::cerr HttpSendRequest failed: GetLastError() std::endl; } else { // 循环读取响应体 char buffer[4096]; DWORD bytesRead 0; std::string response; while (InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, bytesRead) bytesRead 0) { buffer[bytesRead] \0; response buffer; } std::cout response length: response.size() std::endl; std::cout response.substr(0, 500) std::endl; } InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); }参数逐个说InternetOpenA的第一个参数是 User-Agent有些服务会校验别乱填第二个INTERNET_OPEN_TYPE_PRECONFIG表示用系统已有的网络配置这是最省事的方式。InternetConnectA的端口参数HTTP 是 80HTTPS 是 443但 WinINet 走 HTTPS 还需要在HttpOpenRequestA的 flag 里加INTERNET_FLAG_SECURE并且 VC6 自带的 wininet 对现代 TLS 支持有限访问 HTTPS 站点经常握手失败这是老工程的硬伤。HttpSendRequestA的第三、四参数用于 POST 时传 bodyGET 传 NULL 和 0 即可。3.3 如果换成 libcurl 会怎样libcurl 的写法更简洁跨平台也好但在 VC6 下要先解决库的问题。核心调用是curl_easy_init→curl_easy_setopt设 URL →curl_easy_perform→curl_easy_cleanup。它自带 HTTPS 支持取决于编译时的 SSL 后端超时、重定向、代理设置都是一行setopt的事。如果你要长期维护这个工程我一般会建议把 WinINet 那部分替换成 libcurl代价是引入一个 dll收益是网络层少踩很多坑。3.4 把数据库数据和网络请求串起来这份工程真正的价值在于它把两件事连起来了先从 MySQL 读出数据再把数据作为参数发到远端服务。典型流程是查出一批待同步记录拼成 URL 或 POST body逐条发送根据响应更新本地状态字段。这里要注意的是VC6 的 MFC 界面线程里直接做网络请求会卡死 UI正确做法是开工作线程用AfxBeginThread起一个线程跑网络逻辑主线程只负责刷新界面。工程里如果没做这一步数据量一大界面就假死这是遗留系统里最常见的体验问题。4. 避坑与排查这份老工程最容易翻车的五个地方4.1 编译报 unresolved external symbol _mysql_init4现象是链接阶段一堆_mysql_xxx找不到。原因通常是libmySQL.lib没加进链接选项或者加的是 64 位版本。VC6 只能链接 32 位库去 MySQL 安装目录确认lib下是libmySQL.lib还是libmysql.lib名字大小写在不同版本里不一样工程设置里要跟实际文件名完全一致。解决方式是在Project Settings → Link → Object/library modules里补上正确路径和文件名。4.2 程序启动就报缺少 libmySQL.dll现象是编译通过双击 exe 弹窗提示缺 dll。原因是动态链接的库在运行时找不到。解决方式是把libmySQL.dll放到 exe 同目录或者放进系统 PATH 覆盖的目录。注意 dll 的位数要和 exe 一致32 位 exe 配 32 位 dll混了会报「不是有效的 Win32 程序」。4.3 中文数据读出来是乱码现象是数据库里明明是中文程序里显示问号或方块。原因是连接字符集和客户端编码不一致。解决方式是在mysql_real_connect之后立刻执行mysql_query(conn, SET NAMES utf8)同时确认数据库表和字段的字符集也是 utf8。如果 VC6 源文件本身是 GBK 编码界面显示时还要做一次转换MFC 里用MultiByteToWideChar或CString的转换宏处理。4.4 访问 HTTPS 接口时 HttpSendRequest 返回失败现象是请求 Google 的 https 地址时GetLastError返回 12029 或 12157。原因是 VC6 自带的 WinINet 版本太老不支持现代 TLS 协议。解决方式有两条一是改用 libcurl 并带上 SSL 后端二是如果只是内部服务退回 HTTP。硬要在老工程里支持 HTTPS基本是给自己找麻烦不如把网络层单独抽出来用新工具编译成 dll 再调用。4.5 查询结果集没释放导致内存持续增长现象是程序跑久了内存越占越大。原因是mysql_store_result拿到的MYSQL_RES*用完没调mysql_free_result或者连接断开前没mysql_close。解决方式是把资源释放写进固定的清理流程每次查询配对释放连接用完即关。在 MFC 里可以封装一个 RAII 类构造时连接、析构时释放避免手动漏掉。5. 进阶用法把这份工程改造成可维护的数据库网络模块5.1 用 RAII 封装 MySQL 连接老工程里连接、查询、释放散在各处改起来容易漏。我一般会封一个MySqlConn类构造时mysql_init和mysql_real_connect析构时mysql_close查询方法返回结果集并负责释放。这样调用方只管业务不用记 API 的配对关系。class MySqlConn { public: MySqlConn(const char* host, const char* user, const char* pwd, const char* db, unsigned int port 3306) { conn_ mysql_init(NULL); if (!mysql_real_connect(conn_, host, user, pwd, db, port, NULL, 0)) { throw std::runtime_error(mysql_error(conn_)); } mysql_query(conn_, SET NAMES utf8); } ~MySqlConn() { if (conn_) mysql_close(conn_); } MYSQL* raw() { return conn_; } private: MYSQL* conn_; };这个类把连接生命周期绑在对象上异常安全也不会忘记关连接。参数默认端口 3306需要改就传参。注意构造函数里抛异常时mysql_init已经分配的资源要确保释放严格写法是在抛之前先mysql_close。5.2 网络请求加超时和重试WinINet 默认超时很长网络不通时界面会卡很久。可以在InternetOpenA之后用InternetSetOption设置超时DWORD timeout 5000; // 5 秒 InternetSetOptionA(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, timeout, sizeof(timeout)); InternetSetOptionA(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, timeout, sizeof(timeout));重试逻辑放在调用层失败后 sleep 一小段时间再试最多三次。别在底层无限重试那样出问题时更难定位。5.3 验证改造是否成功改完之后怎么确认没退化我一般做三件事一是用同一批数据跑一遍对比改造前后数据库里的记录数和内容是否一致二是断网测试看超时和重试是否按预期触发程序是否还能正常退出三是用任务管理器观察内存连续跑几十次查询和请求内存曲线应该是平的不该持续上升。这三点过了基本可以认为改造是稳的。从那以后我每次接手这类老工程都强制先把数据库连接和网络请求各自封成独立模块再谈业务逻辑。不然改一处崩三处后悔药都没得吃。希望帮到你。本文还有配套的精品资源点击获取