C++\CLI语法 在项目中的使用
通常情况下,对一个标准的com组件进行集成,网上普遍使用的方式有:
1、#import *.dll 或 #import *.ocx的方式,VS编译器重新编译后,就会自动生成组件对应的*.tlh文件,该文件类似于头文件,含有com组件中的接口信息,在自己的项目中就可以引用接口或者类了。
2、#pragma comment(lib, "*.lib")的方式,这种方式可以直接引用lib里的接口声明。
好巧不巧:项目中碰到的三方组件恰好用这两种方式都不能集成:用第一种方式,VS生成的tlh文件内容是空的;第二种直接引用后,编译报错
通过三方组件给的C#调用的示例程序,发现该组件的目标运行平台必须选定是X86平台
自身项目属于C++范畴,所以在查阅部分资料后,遇到了C++/CLI
#include <Windows.h> #include <stdio.h> // 在做类型转换时用到 using namespace System; // 组件的路径放在了本地,在实际运行中,将该组件放在了和运行程序的同目录下 #using "E:\C_backup_20180315\jzbank\CallComSln\CallCom\Debug\Interop.SmartCardLib.dll" // SmartCardLib是Interop.SmartCardLib.dll内的命名空间 using namespace SmartCardLib; // 组件的路径放在了本地,在实际运行中,将该组件放在了和运行程序的同目录下 #using "E:\C_backup_20180315\jzbank\CallComSln\CallCom\Debug\Interop.IObjectSafetyTLB.dll" // IObjectSafetyTLB是Interop.IObjectSafetyTLB.dll内的命名空间 using namespace IObjectSafetyTLB; // 时间工具 static SYSTEMTIME t; void main(){ // clsSmartCardClass是namespace SmartCardLib里的 // cli语法 注意 ^ 和 gcnew clsSmartCardClass ^instance = gcnew clsSmartCardClass(); int ret = -1; // namespace SmartCardLib里声明的方法 ret = instance->Connect("param1"); Sleep(3000); // cli语法 声明变量并初始化 System::Object^ cardNo = gcnew System::Object(); System::Object^ customNo1 = gcnew System::Object(); System::Object^ orderdate1 = gcnew System::Object(); System::Object^ orderAmount1 = gcnew System::Object(); System::Object^ orderNum1 = gcnew System::Object(); System::Object^ orderTotal1 = gcnew System::Object(); System::Object^ fgs1 = gcnew System::Object(); System::Object^ glz1 = gcnew System::Object(); System::Object^ cardStatus1 = gcnew System::Object(); System::Object^ cardPwd1 = gcnew System::Object(); System::Object^ cardType1 = gcnew System::Object(); System::Object^ chgPwd1 = gcnew System::Object(); // Int32 int result = instance->readCard(cardNo, customNo1, orderdate1, orderAmount1, // orderNum1, orderTotal1, fgs1, glz1, // cardStatus1, cardPwd1, cardType1, chgPwd1); // 文件生成在本地,临时写在特定目录 FILE *pFile; fopen_s( &pFile, "C:\\Users\\Administrator\\teller\\device\\1\\infofile\\info.txt", "w+" ); if (result == 0) { char resv[32] = {0}; ////////////////////////////////////////////// // cli语法 将 System::String^ 转换为 char* strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)cardNo)); printf("\nok, instance->readCard()-----------cardNo=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); memset(resv, 0, sizeof(resv)); ////////////////////////////////////////////// strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)customNo1)); printf("\nok, instance->readCard()-----------customNo1=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); memset(resv, 0, sizeof(resv)); ////////////////////////////////////////////// strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)orderdate1)); printf("\nok, instance->readCard()-----------orderdate1=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); memset(resv, 0, sizeof(resv)); ////////////////////////////////////////////// GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %d\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, (int)(System::Int32)orderAmount1); fflush(pFile); printf("\nok, instance->readCard()-----------orderAmount1=%d", (int)(System::Int32)orderAmount1); ////////////////////////////////////////////// GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %d\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, (int)(System::Int16)orderNum1); fflush(pFile); printf("\nok, instance->readCard()-----------orderNum1=%d", (int)(System::Int16)orderNum1); ////////////////////////////////////////////// GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %d\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, (int)(System::Int32)orderTotal1); fflush(pFile); printf("\nok, instance->readCard()-----------orderTotal1=%d", (int)(System::Int32)orderTotal1); ////////////////////////////////////////////// strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)fgs1)); printf("\nok, instance->readCard()-----------fgs1=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); memset(resv, 0, sizeof(resv)); ////////////////////////////////////////////// strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)glz1)); printf("\nok, instance->readCard()-----------glz1=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); memset(resv, 0, sizeof(resv)); ////////////////////////////////////////////// strcpy(resv, (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi((System::String^)cardStatus1)); printf("\nok, instance->readCard()-----------cardStatus1=%s", resv); GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d %s\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, resv); fflush(pFile); } else { GetLocalTime(&t); fprintf(pFile, "%4d/%02d/%02d %02d:%02d:%02d.%03d call readCard faild, ret=%d\n", t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute, t.wSecond,t.wMilliseconds, result); } fflush(pFile); fclose(pFile); pFile = NULL; int dret = instance->Disconnect(); //printf("\n--, instance->Disconnect()-----------dret=%d", dret); // 此处延时会导致程序即将结束时报错:Runtime error 217 at 。。。 //Sleep(3000); //getchar(); }
在C++项目中调用如下:
#include "LoadDll.h"
#include <ShlObj.h>
//用于生成文件夹 mkdir
#include <direct.h>
#include <string.h>
char exePath[MAX_PATH] = {0}; ret = checkExePath(exePath, exeName); if(ret < 0) return ret; char params[256] = {0}; sprintf(params, "%s|%d|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s", funcName, timeout, compcode, tmpCardNo, tmpcustomNo, orderdate, orderNum, orderAmount, orderTotal, tmpCardPwd, alertLowLimit, overDraft, idleDays, upLimit ); ret = CallExe(exePath, params, timeout); // 读取生成的文件 char infoFilePath[MAX_PATH] = {0}; ret = checkExePath(infoFilePath, txtName); if(ret < 0) return ret; FILE *pInfoFile = fopen(infoFilePath, "r"); if(NULL == pInfoFile) return -1; char output[8] = {0}; fgets(output, sizeof(output), pInfoFile); fflush(pInfoFile); fclose(pInfoFile); pInfoFile = NULL; // 删除临时生成的文件 //ret = remove(infoFilePath);
其中CallExe函数实现为:
int CallExe(char exePath[], const char* params, int timeout) { SHELLEXECUTEINFO exe = {0}; exe.cbSize = sizeof(SHELLEXECUTEINFO); exe.fMask = SEE_MASK_NOCLOSEPROCESS; exe.hwnd = NULL; exe.lpVerb = NULL; exe.lpFile = exePath; exe.lpParameters = params; exe.lpDirectory = NULL; //exe.nShow = SW_NORMAL; exe.nShow = SW_HIDE; exe.hInstApp = NULL; BOOL suc = ShellExecuteEx(&exe); DWORD m = WaitForSingleObject(exe.hProcess, timeout * 1000); return (int)m; }
其中checkExePath函数实现为:
int checkExePath(char exePath[], char* fileSimpleName) { char path[MAX_PATH] = {0}; if (GetDesktopPath(path)){ int desktopPathLenth = strlen((const char *)path); int i = desktopPathLenth - 1; for(; i > 0; i--){ if(path[i] == '\\' || path[i] == '/'){ break; } } for(int j = 0; j < i; j++){ exePath[j] = path[j]; } sprintf(exePath, "%s%s", exePath, "\\fold1"); // 检查“teller”文件夹是否存在 if (!CheckFolderExist(exePath)){ _mkdir(exePath); } sprintf(exePath, "%s%s", exePath, "\\fold2"); // 检查“device”文件夹是否存在 if (!CheckFolderExist(exePath)){ _mkdir(exePath); } sprintf(exePath, "%s%s", exePath, "\\fold3"); // 检查“CNG_READER_JZBANK”文件夹是否存在 if (!CheckFolderExist(exePath)){ _mkdir(exePath); } // 用户目录/fold1/fold2/fold3/fileSimpleName sprintf(exePath, "%s\\%s", exePath, fileSimpleName); // 检查exe是否存在 return 0; } return -1; }
GetDesktopPath的函数实现为:
//获取桌面目录的绝对路径 bool GetDesktopPath(char* desktopPath) { if (SHGetSpecialFolderPath(NULL, desktopPath, CSIDL_DESKTOP, 0)){ return TRUE; } return FALSE; }
CheckFolderExist的函数实现为:
//目录是否存在的检查: bool CheckFolderExist(const char* strPath) { WIN32_FIND_DATA wfd; bool rValue = FALSE; HANDLE hFind = FindFirstFile(strPath, &wfd); if ((hFind != INVALID_HANDLE_VALUE) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ rValue = TRUE; } FindClose(hFind); return rValue; }