CodeV和C++交互CODEV版本2023-03

尝试用CodeV的API手册中的C++示例代码与CodeV进行交互,但是发现API手册的示例代码与提供的库文件不匹配,网上没有找到很详细的解决方案,自己摸索出来一个解决办法仅供参考,过程如下。

codev2023.03 示例代码(无法运行)

The following sample code in C++ sets the starting directory to C:\CVUSER, starts CODE V, restores the dbgauss lens, runs a surface listing, and then closes the CODE V session. Examples for other languages can be found in the \com subfolder (for example, C:\CODEV202303\com).

翻译:下面C++的示例代码设置起始目录为C:\CVUSER,启动CODEV,打开dbgauss镜头,运行并输出表面参数,然后关闭CODEV回话。其他语言的示例可以在com子文件夹中找到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Copy cvcommand.tlb into the current folder and compile with
// cl /I"." /EHsc sample.cpp
//#define NTDDI_VERSION NTDDI_VISTA
#define WINVER 0x0600
#define WIN32_WINNT 0x0600
#define WIN32_IE 0x0700
#define UNICODE
#define _UNICODE


#include <afxdisp.H>
#include <iostream>
#import "cvcommand.tlb" raw_interfaces_only named_guids


void main()
{
CoInitialize(nullptr);

CVCommandLib::ICVApplication* pCodeV = nullptr;

auto sProgid = std::string("CodeV.Application");
_bstr_t bstrProgID = CA2W(sProgid.c_str());

CLSID nClassId;
auto hr = CLSIDFromProgID(bstrProgID, &nClassId);
if (FAILED(hr))
{
std::cerr << "No COM object registered\n";
exit(1);
}

hr = CoCreateInstance(
nClassId,
nullptr,
CLSCTX_LOCAL_SERVER,
__uuidof(CVCommandLib::ICVApplication),
(void**) &pCodeV);
if (FAILED(hr))
{
std::cerr << "Unable to create COM instance\n";
CoUninitialize();
exit(1);
}

hr = pCodeV->StartCodeV();
if ( FAILED(hr) )
{
std::cerr << "Unable to start CODE V\n";
CoUninitialize();
exit(1);
}

_bstr_t bstrtCommand = CA2W("len new"); // res cv_lens:dbgauss; sur sa");
_bstr_t bstrtResult;
hr = pCodeV->Command(bstrtCommand, &bstrtResult.GetBSTR());
if (SUCCEEDED(hr))
{
std::string result = CW2A(bstrtResult);
std::cout << result.data() << std::endl;
}
else
{
std::cout << "Command() failed. HRESULT = " << std::hex << hr << std::endl;
}
hr = pCodeV->StopCodeV();
hr = pCodeV->Release();
CoUninitialize();
}

运行方法:Copy the cvcommand.tlb file from the CODE V installation folder to the working directory for the Visual C++ project. You can then compile the sample file using the CL command as shown below:

cl /I"." /EHsc sample.cpp

#define NTDDI_VERSION NTDDI_VISTA

where the filename is sample.cpp and Visual C++ is installed and in your path.

翻译:将 cvcommand.tlb 文件从 CODE V 安装文件夹复制到 Visual C 项目的工作目录中。然后可以使用如下所示的 CL 命令编译示例文件:

cl /I"." /EHsc sample.cpp

#define NTDDI_VERSION NTDDI_VISTA

其中文件名为 sample.cpp,并且已安装 Visual C++ 并添加到你的路径中。

按照文档运行后出现报错,我分析主要存在两个报错:第一个是#import "cvcommand.tlb" raw_interfaces_only这里引用的库文件和代码不匹配,有可能是因为版本比较老,导致库文件和代码不匹配;第二个是#include <afxdisp.H>这里引用的afxdisp库比较老,导致CA2W等无法使用,这个可以用其他方法代替。

解决方案

下面这个没有问题,按照这个来就行

Copy the cvcommand.tlb file from the CODE V installation folder to the working directory for the Visual C++ project. You can then compile the sample file using the CL command as shown below:

cl /I"." /EHsc sample.cpp

#define NTDDI_VERSION NTDDI_VISTA

where the filename is sample.cpp and Visual C++ is installed and in your path.

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copy cvcommand.tlb into the current folder and compile with
// cl /I"." /EHsc sample.cpp
//#define NTDDI_VERSION NTDDI_VISTA
#define WINVER 0x0600
#define WIN32_WINNT 0x0600
#define WIN32_IE 0x0700
#define UNICODE
#define _UNICODE

#include <iostream>
#include <string>

#include <comdef.h>
// 确保 Windows 控制台支持宽字符输出
#include <io.h>
#include <fcntl.h>

#import "cvcommand.tlb" raw_interfaces_only named_guids

void main()
{
// 让 stdout/stderr 进入 UTF-16 宽字符模式,配合 wcout/wcerr 输出中文
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stderr), _O_U16TEXT);
CoInitialize(nullptr);

CVCommandLib::ICVCommand* pCodeV = nullptr;

std::string sProgid = "CodeV.Application";
_bstr_t bstrProgID = sProgid.c_str();

CLSID nClassId;

auto hr = CLSIDFromProgID(bstrProgID, &nClassId);
if (FAILED(hr))
{
std::wcerr << L"No COM object registered\n";
exit(1);
}

hr = CoCreateInstance(
__uuidof(CVCommandLib::CVCommand),
nullptr,
CLSCTX_LOCAL_SERVER,
__uuidof(CVCommandLib::ICVCommand),
(void**)&pCodeV);

if (FAILED(hr))
{
// 0x80040154 (Class not registered): 说明 CVCommand 未注册
std::wcerr << L"Unable to create COM instance. HRESULT: 0x" << std::hex << hr << L"\n";
CoUninitialize();
exit(1);
}

// ��ȡ��ʼĿ¼
BSTR bstrStartDir = nullptr;
hr = pCodeV->GetStartingDirectory(&bstrStartDir);
if (SUCCEEDED(hr) && bstrStartDir != nullptr)
{
std::wcout << L"StartDir: " << (wchar_t*)bstrStartDir << std::endl;
SysFreeString(bstrStartDir);
}
else
{
std::wcerr << L"GetStartingDirectory failed. HRESULT: 0x" << std::hex << hr << std::endl;
}

hr = pCodeV->StartCodeV();
if (FAILED(hr))
{
std::wcerr << L"Unable to start CODE V\n";
CoUninitialize();
exit(1);
}

_bstr_t bstrtCommand = "len new";
_bstr_t bstrtResult;
hr = pCodeV->Command(bstrtCommand, &bstrtResult.GetBSTR());
if (SUCCEEDED(hr))
{
if (bstrtResult.length() > 0) {
std::wstring result = (wchar_t*)bstrtResult;
std::wcout << L"Result: " << result << std::endl;
}
else {
std::wcout << L"Command executed successfully (no output)." << std::endl;
}
}
else
{
std::wcout << L"Command() failed. HRESULT = " << std::hex << hr << std::endl;
}
hr = pCodeV->StopCodeV();
hr = pCodeV->Release();
CoUninitialize();

return ;
}

上面这个代码解决了两个问题:1、检查编译得到的cvcommand.tlh文件,可以发现并没有ICVApplication这个成员,检查发现ICVCommand这个才是正确的;2、使用comdef.h代替afxdisp.H来对COM字符串进行处理。

经测试可以成功输出