补充漏提交文件
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>
|
</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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user