补充漏提交文件

This commit is contained in:
chenjiangqun
2026-04-23 10:06:24 +08:00
parent 223c0d2940
commit 3a99feb12a
4 changed files with 337 additions and 4 deletions

298
MesApi/MesApi/MesApi.cpp Normal file
View File

@@ -0,0 +1,298 @@
#pragma execution_character_set("utf-8")
#include "MesApi.h"
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <sstream>
#include <vector>
#include <cstring>
#pragma comment(lib, "winhttp.lib")
// ============ 内部工具函数 ============
static std::wstring Utf8ToWide(const std::string& utf8)
{
if (utf8.empty()) return L"";
int len = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0);
std::wstring wide(len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &wide[0], len);
wide.resize(len - 1);
return wide;
}
static std::string WideToUtf8(const std::wstring& wide)
{
if (wide.empty()) return "";
int len = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, nullptr, 0, nullptr, nullptr);
std::string utf8(len, '\0');
WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, &utf8[0], len, nullptr, nullptr);
utf8.resize(len - 1);
return utf8;
}
static int SafeCopyToBuffer(const std::string& src, char* outBuffer, int bufferSize)
{
if (!outBuffer || bufferSize <= 0) return -3;
if ((int)src.size() >= bufferSize) return -3;
memcpy(outBuffer, src.c_str(), src.size());
outBuffer[src.size()] = '\0';
return 0;
}
static std::string ExtractJsonValue(const std::string& json, const std::string& key)
{
std::string searchKey = "\"" + key + "\"";
size_t pos = json.find(searchKey);
if (pos == std::string::npos) return "";
pos += searchKey.size();
while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t' || json[pos] == '\r' || json[pos] == '\n')) pos++;
if (pos >= json.size() || json[pos] != ':') return "";
pos++;
while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t' || json[pos] == '\r' || json[pos] == '\n')) pos++;
if (pos >= json.size()) return "";
if (json.compare(pos, 4, "null") == 0)
{
return "";
}
if (json[pos] == '\"')
{
pos++;
std::string result;
while (pos < json.size())
{
if (json[pos] == '\\' && pos + 1 < json.size())
{
char next = json[pos + 1];
switch (next)
{
case '\"': result += '\"'; break;
case '\\': result += '\\'; break;
case '/': result += '/'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
default: result += '\\'; result += next; break;
}
pos += 2;
}
else if (json[pos] == '\"')
{
break;
}
else
{
result += json[pos];
pos++;
}
}
return result;
}
else
{
size_t end = json.find_first_of(",} \t\r\n", pos);
if (end == std::string::npos) end = json.size();
return json.substr(pos, end - pos);
}
}
static std::string EscapeJsonString(const char* input)
{
if (!input) return "";
std::string output;
output.reserve(strlen(input) + 16);
for (const char* p = input; *p; ++p)
{
switch (*p)
{
case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break;
case '\f': output += "\\f"; break;
case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
default: output += *p; break;
}
}
return output;
}
// ============ HTTP POST6 个参数) ============
static int HttpPostJson(
const std::wstring& host,
int port,
const std::wstring& path,
const std::string& jsonBody,
int timeoutMs,
std::string& responseBody)
{
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
int ret = -1;
hSession = WinHttpOpen(L"MesApi/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) goto cleanup;
WinHttpSetTimeouts(hSession, timeoutMs, timeoutMs, timeoutMs, timeoutMs);
hConnect = WinHttpConnect(hSession, host.c_str(), (INTERNET_PORT)port, 0);
if (!hConnect) goto cleanup;
hRequest = WinHttpOpenRequest(hConnect, L"POST", path.c_str(),
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
if (!hRequest) goto cleanup;
{
const wchar_t* header = L"Content-Type: application/json; charset=utf-8";
if (!WinHttpAddRequestHeaders(hRequest, header, (DWORD)-1, WINHTTP_ADDREQ_FLAG_ADD))
goto cleanup;
}
if (!WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
(LPVOID)jsonBody.c_str(), (DWORD)jsonBody.size(),
(DWORD)jsonBody.size(), 0))
goto cleanup;
if (!WinHttpReceiveResponse(hRequest, NULL))
goto cleanup;
{
DWORD bytesAvailable = 0;
DWORD bytesRead = 0;
std::string body;
body.reserve(4096);
char tmpBuf[4096];
do
{
bytesAvailable = 0;
if (!WinHttpQueryDataAvailable(hRequest, &bytesAvailable) || bytesAvailable == 0)
break;
DWORD toRead = (bytesAvailable < sizeof(tmpBuf)) ? bytesAvailable : sizeof(tmpBuf);
bytesRead = 0;
if (WinHttpReadData(hRequest, tmpBuf, toRead, &bytesRead) && bytesRead > 0)
{
body.append(tmpBuf, bytesRead);
}
else
{
break;
}
} while (true);
// 剥离 UTF-8 BOM
if (body.size() >= 3 &&
(unsigned char)body[0] == 0xEF &&
(unsigned char)body[1] == 0xBB &&
(unsigned char)body[2] == 0xBF)
{
body.erase(0, 3);
}
responseBody = std::move(body);
ret = 0;
}
cleanup:
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return ret;
}
// ============ 导出函数 ============
extern "C"
MESAPI_API int MESAPI_CALL UploadResult(
const char* sn,
const char* station,
const char* function,
const char* result,
const char* costtime,
char* outBuffer,
int bufferSize)
{
try
{
// 1. 构建 JSON
std::ostringstream oss;
oss << "{"
<< "\"USERCODE\":\"SAPEDI\","
<< "\"TOKEN\":\"SCBCSMESAPI2021!@#\","
<< "\"METHOD\":\"UploadResult\","
<< "\"PARAS\":{"
<< "\"SN\":\"" << EscapeJsonString(sn) << "\","
<< "\"Station\":\"" << EscapeJsonString(station) << "\","
<< "\"FunctionName\":\"" << EscapeJsonString(function) << "\","
<< "\"TestResult\":\"" << EscapeJsonString(result) << "\","
<< "\"CostTime\":\"" << EscapeJsonString(costtime) << "\","
<< "\"Remark\":\"\""
<< "}}";
std::string jsonBody = oss.str();
// 2. HTTP POST
std::wstring host = L"10.222.16.22";
int port = 80;
std::wstring path = L"/SMESCommAPI/API/SAPEDI/SMESDataExchage";
int timeout = 8000;
std::string responseBody;
int httpRet = HttpPostJson(host, port, path, jsonBody, timeout, responseBody);
if (httpRet != 0)
{
// ★ 中文字面量现在是 UTF-8靠文件顶部 pragma 保证)
std::string errMsg = "ERROR:网络无连接";
return SafeCopyToBuffer(errMsg, outBuffer, bufferSize) == 0 ? -1 : -3;
}
// 3. 解析响应
std::string resultField = ExtractJsonValue(responseBody, "Result");
if (resultField == "true")
{
std::string ok = "TRUE";
int copyRet = SafeCopyToBuffer(ok, outBuffer, bufferSize);
return copyRet == 0 ? 0 : -3;
}
else
{
// ★ errorField 来自服务器响应,本身就是 UTF-8
// ★ 前缀中文也是 UTF-8靠 pragma拼接后编码一致不会乱码
std::string errorField = ExtractJsonValue(responseBody, "Error");
std::string dataField = ExtractJsonValue(responseBody, "Data");
std::string errMsg;
if (!errorField.empty())
errMsg = "ERROR:" + errorField;
else if (!dataField.empty())
errMsg = "ERROR:" + dataField;
else
errMsg = "ERROR:MES返回失败(Result=" + resultField + ")";
int copyRet = SafeCopyToBuffer(errMsg, outBuffer, bufferSize);
return copyRet == 0 ? -2 : -3;
}
}
catch (...)
{
std::string errMsg = "ERROR:未知异常";
SafeCopyToBuffer(errMsg, outBuffer, bufferSize);
return -4;
}
}

35
MesApi/MesApi/MesApi.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#ifdef MESAPI_EXPORTS
#define MESAPI_API __declspec(dllexport)
#else
#define MESAPI_API __declspec(dllimport)
#endif
#if defined(_WIN64)
#define MESAPI_CALL __cdecl
#else
#define MESAPI_CALL __stdcall
#endif
extern "C"
{
/// @brief 上传测试结果到 MES 系统
/// @param sn 产品序列号
/// @param station 工站名
/// @param function 功能名称
/// @param result 测试结果
/// @param costtime 耗时
/// @param outBuffer 输出缓冲区(调用方分配)
/// @param bufferSize 输出缓冲区大小
/// @return 0=成功, -1=网络错误, -2=MES返回失败, -3=缓冲区不足, -4=其他异常
MESAPI_API int MESAPI_CALL UploadResult(
const char* sn,
const char* station,
const char* function,
const char* result,
const char* costtime,
char* outBuffer,
int bufferSize
);
}

View File

@@ -147,13 +147,13 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\WebInterface\WebInterface\MesApi.h" />
<ClInclude Include="framework.h" /> <ClInclude Include="framework.h" />
<ClInclude Include="MesApi.h" />
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\WebInterface\WebInterface\MesApi.cpp" />
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="MesApi.cpp" />
<ClCompile Include="pch.cpp"> <ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>

View File

@@ -21,7 +21,7 @@
<ClInclude Include="pch.h"> <ClInclude Include="pch.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\WebInterface\WebInterface\MesApi.h"> <ClInclude Include="MesApi.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
@@ -32,7 +32,7 @@
<ClCompile Include="pch.cpp"> <ClCompile Include="pch.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\WebInterface\WebInterface\MesApi.cpp"> <ClCompile Include="MesApi.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>