补充漏提交文件
This commit is contained in:
298
MesApi/MesApi/MesApi.cpp
Normal file
298
MesApi/MesApi/MesApi.cpp
Normal 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 POST(6 个参数) ============
|
||||
|
||||
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
35
MesApi/MesApi/MesApi.h
Normal 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
|
||||
);
|
||||
}
|
||||
@@ -147,13 +147,13 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\WebInterface\WebInterface\MesApi.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="MesApi.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\WebInterface\WebInterface\MesApi.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="MesApi.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\WebInterface\WebInterface\MesApi.h">
|
||||
<ClInclude Include="MesApi.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -32,7 +32,7 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\WebInterface\WebInterface\MesApi.cpp">
|
||||
<ClCompile Include="MesApi.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user