- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用C++ / CLR编写包装器。托管的C#类具有如下功能签名
//C#
int WriteToInstrument(string command, ref string response, int stage);
//C++
int WriteToInstrumentWrap(const char * command, char * response, int stage);
最佳答案
我将添加一些今天上午编写的代码示例。通常,在谈到返回对象时(从广义上讲,甚至char*
字符串都是对象),C / C++中的主要问题是:
const char* Message()
{
return "OK";
}
Message()
返回的内存! malloc
和
new
与主程序使用的
malloc
和
new
可以不同/不同。程序(或另一个dll),以便您不应该在主程序中使用
free
释放由dll的
malloc
(ed)所占用的内存。
LocalAlloc
和CoTaskMemAlloc
。甚至可以从.NET(Marshal.AllocHGlobal
和Marshal.AllocCoTaskMem
)访问它们。这样,主应用程序可以释放由dll Free()
方法,必须使用该方法来释放由dll SetAllocator(void *(*allocator)(size_t))
和SetFree(void (*free)(void*))
,因此存储函数指针的方法可供主应用程序用来设置分配器并由dll免费使用,以便它们在主应用程序之间共享和dll。 dll将使用这些分配器。请注意,如果由主应用程序完成SetAllocator(malloc); SetFree(free)
是完全合法的:现在该dll将使用主应用程序的malloc
,而不是dll的malloc
! char*
。使用
wchar_t
。总是。
int WriteToInstrument(string command, ref string response, int stage)
{
response = "The quick brown fox jumps over the lazy dog";
return 0;
}
WriteToInstrument
,然后将
response
结果复制到ansi字符串(
char*
)的简单方法。该缓冲区由调用方分配,大小为
length
。执行该方法后,
length
包含使用的字符数(包括终止的
\0
)。
response
始终是
\0
终止的。这里的问题是
response
可能会被截断和/或调用者可能分配的缓冲区太大(如果它很不幸,它并不能真正保护它免受截断问题的影响:-))。我将在这里重复我自己:在2018年对字符串使用
char*
是古老的技术。
// Utility method to copy a unicode string to a fixed size buffer
size_t Utf16ToAnsi(const wchar_t *wstr, char *str, size_t length)
{
if (length == 0)
{
return 0;
}
// This whole piece of code can be moved to a method
size_t length2 = WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, (int)length, nullptr, nullptr);
// WideCharToMultiByte will try to write up to *length characters, but
// if the buffer is too much small, it will return 0,
// **and the tring won't be 0-terminated**
if (length2 != 0)
{
return length2;
}
// Buffer too much small
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// We add a terminating 0
str[length - 1] = 0;
return length;
}
// Big bad error, shouldn't happen. Return 0 but terminate the string
str[0] = 0;
return 0;
}
char response[16];
size_t length = sizeof(response) / sizeof(char); // useless / sizeof(char) == / 1 by definition
WriteToInstrumentWrap1("cmd1", response, &length, 1);
std::cout << "fixed buffer char[]: " << response << ", used length: " << length << std::endl;
std::vector<>
/
std::array<>
)
//Alternative: std::array<char, 16> response;
std::vector<char> response(16);
size_t length = response.size();
WriteToInstrumentWrap1("cmd1", response.data(), &length, 1);
std::cout << "fixed buffer vector<char>: " << response.data() << ", used length: " << length << std::endl;
WriteToInstrument
,然后将
response
结果复制到unicode字符串(
wchar_t*
)的简单方法。该缓冲区由调用方分配,大小为
length
。执行该方法后,
length
包含使用的字符数(包括终止的
\0
)。
response
始终是
\0
终止的。
// in input length is the size of response, in output the number of characters (not bytes!) written to response
// (INCLUDING THE \0!). The string is always correctly terminated.
int WriteToInstrumentWrap2(const wchar_t *command, wchar_t *response, size_t *length, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
*length = (size_t)str2->Length < *length ? str2->Length : *length - 1;
memcpy(response, pch, *length * sizeof(wchar_t));
response[*length] = '\0';
*length++;
return res;
}
wchar_t response[16];
size_t length = sizeof(response) / sizeof(wchar_t);
WriteToInstrumentWrap2(L"cmd1", response, &length, 1);
std::wcout << L"fixed buffer wchar_t[]: " << response << L", used length: " << length << std::endl;
std::vector<>
/
std::array<char, 16>
)
//Alternative: std::array<wchar_t, 16> response;
std::vector<wchar_t> response(16);
size_t length = response.size();
WriteToInstrumentWrap2(L"cmd1", response.data(), &length, 1);
std::wcout << L"fixed buffer vector<wchar_t>: " << response.data() << ", used length: " << length << std::endl;
char
而不是wchar_t
。转换它们非常容易。我将在这里重复我自己:在2018年对字符串使用char*
是古老的技术。就像使用ArrayList
而不是List<>
WriteToInstrument
的简单方法,使用
response
分配
CoTaskMemAlloc
缓冲区,然后将结果复制到ansi字符串(
char*
)。调用者必须
CoTaskMemFree
分配的内存。
response
始终是
\0
终止的。
// Memory allocated with CoTaskMemAlloc. Remember to CoTaskMemFree!
int WriteToInstrumentWrap3(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)CoTaskMemAlloc(length * sizeof(char));
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
char *response;
WriteToInstrumentWrap3("cmd1", &response, 1);
std::cout << "CoTaskMemFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with CoTaskMemFree!
CoTaskMemFree(response);
WriteToInstrument
的简单方法,使用“私有(private)”“库”分配器分配
response
缓冲区,并将结果复制到ansi字符串(
char*
)。调用者必须使用库解除分配器
MyLibraryFree
释放已分配的内存。
response
始终是
\0
终止的。
// Free method used by users of the library
void MyLibraryFree(void *p)
{
free(p);
}
// The memory is allocated through a proprietary allocator of the library. Use MyLibraryFree() to free it.
int WriteToInstrumentWrap4(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)malloc(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
char *response;
WriteToInstrumentWrap4("cmd1", &response, 1);
std::cout << "Simple MyLibraryFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with the MyLibraryFree() method
MyLibraryFree(response);
WriteToInstrument
的简单方法,使用可设置的分配器(通过
response
/
SetLibraryAllocator
方法)分配
SetLibraryFree
缓冲区(如果未选择特殊分配器,则使用默认值),然后将结果复制到ansi字符串(
char*
)。调用者必须使用库释放器
LibraryFree
(使用
SetLibraryFree
选择的分配器)释放分配的内存,或者如果它设置了其他分配器,则它可以直接使用该释放器。
response
始终是
\0
终止的。
void *(*libraryAllocator)(size_t length) = malloc;
void (*libraryFree)(void *p) = free;
// Free method used by library
void SetLibraryAllocator(void *(*allocator)(size_t length))
{
libraryAllocator = allocator;
}
// Free method used by library
void SetLibraryFree(void (*free)(void *p))
{
libraryFree = free;
}
// Free method used by library
void LibraryFree(void *p)
{
libraryFree(p);
}
// The memory is allocated through the allocator specified by SetLibraryAllocator (default the malloc of the dll)
// You can use LibraryFree to free it, or change the SetLibraryAllocator and the SetLibraryFree with an allocator
// of your choosing and then use your free.
int WriteToInstrumentWrap5(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)libraryAllocator(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
void* MyLocalAlloc(size_t size)
{
return LocalAlloc(0, size);
}
void MyLocalFree(void *p)
{
LocalFree(p);
}
// Using the main program malloc/free
SetLibraryAllocator(malloc);
SetLibraryFree(free);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(malloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using the main program free, because the allocator has been set to malloc
free(response);
// Using the Windows LocalAlloc/LocalFree. Note that we need to use an intermediate method to call them because
// they have a different signature (stdcall instead of cdecl and an additional parameter for LocalAlloc)
SetLibraryAllocator(MyLocalAlloc);
SetLibraryFree(MyLocalFree);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(LocalAlloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using diretly the Windows API LocalFree
LocalFree(response);
WriteToInstrument
,但有一个
allocator
作为参数,它将用于分配
response
缓冲区。还有一个附加参数
par
将传递给
allocator
。然后,该方法将结果复制为ansi字符串(
char*
)。调用者必须根据使用的
allocator
使用特定的释放程序释放内存。
response
始终是
\0
终止的。
// allocator is a function that will be used for allocating the memory. par will be passed as a parameter to allocator(length, par)
// the length of allocator is in number of elements, *not in bytes!*
int WriteToInstrumentWrap6(const char *command, char **response, char *(*allocator)(size_t length, void *par), void *par, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = allocator(length, par);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
vector<>
,
malloc
,
new[]
和
unique_ptr<>
):
par
参数的使用。
template<typename T>
T* vector_allocator(size_t length, void *par)
{
std::vector<T> *pvector = static_cast<std::vector<T>*>(par);
pvector->resize(length);
return pvector->data();
}
template<typename T>
T* malloc_allocator(size_t length, void *par)
{
return (T*)malloc(length * sizeof(T));
}
template<typename T>
T* new_allocator(size_t length, void *par)
{
return new T[length];
}
template<typename T>
T* uniqueptr_allocator(size_t length, void *par)
{
std::unique_ptr<T[]> *pp = static_cast<std::unique_ptr<T[]>*>(par);
pp->reset(new T[length]);
return pp->get();
}
WriteToInstrumentWrap6
的参数之一就是
useless
,因为我们已经有一个指向缓冲区的指针了):
{
std::vector<char> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, vector_allocator<char>, &response, 1);
std::cout << "vector char: " << response.data() << ", used length: " << response.size() << std::endl;
// The memory is automatically freed by std::vector<>
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, malloc_allocator<char>, nullptr, 1);
std::cout << "malloc char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with free
free(response);
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, new_allocator<char>, nullptr, 1);
std::cout << "new[] char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with delete[]
delete[] response;
}
{
std::unique_ptr<char[]> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, uniqueptr_allocator<char>, &response, 1);
std::cout << "unique_ptr<> char: " << response.get() << ", used length: " << strlen(response.get()) + 1 << std::endl;
// The memory is automatically freed by std::unique_ptr<>
}
关于c# - 如何编写以引用字符串作为参数的托管C#dll的C++包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50531733/
正在尝试创建一个 python 包。似乎有效,但我收到警告。我的 setup.py 是: #! /usr/bin/env python from distutils.core import setup
我导入了一个数据类型 X ,定义为 data X a = X a 在本地,我定义了一个通用量化的数据类型,Y type Y = forall a. X a 现在我需要定义两个函数, toY 和 fro
我似乎无法让编译器让我包装 Tokio AsyncRead: use std::io::Result; use core::pin::Pin; use core::task::{Context, Po
我有两个函数“a”和“b”。当用户上传文件时,“b”被调用。 “b”重命名文件并返回新文件名。之后应该编辑该文件。像这样: def a(): edits file def b(): r
我使用 Entity Framework 作为我的 ORM,我的每个类都实现了一个接口(interface),该接口(interface)基本上表示表结构(每个字段一个只读属性)。这些接口(inter
有没有办法打开一个程序,通常会打开一个新的jframe,进入一个现有的jframe? 这里是解释,我下载了一个java游戏,其中一个是反射游戏,它在一个jframe中打开,框架内有一堆子面板,我想要做
我想要下面的布局 | AA BBBBBBB | 除非没有足够的空间,在这种情况下 | AA | | BBBBBBB | 在这种情况下,A 是复选框,B 是复选框旁边的 Text
我正在尝试以不同的方式包装我的网站,以便将背景分为 2 部分。灰色部分是主要背景,还有白色部分,它较小并包装主要内容。 基本上我想要this看起来像this . 我不太确定如何添加图像来创建阴影效果,
我正在使用 : 读取整数文件 int len = (int)(new File(file).length()); FileInputStream fis = new FileInputStream(f
我使用 maven 和 OpenJDK 1.8 打包了一个 JavaFX 应用程序我的 pom.xml 中的相关部分: maven-assembly-plugin
我正在使用两个不同的 ItemsControl 来生成一个按钮列表。
我有一个情况,有一个变量会很方便,to , 可以是 TimerOutput或 nothing .我有兴趣提供一个采用与 @timeit 相同参数的宏来自 TimerOutputs(例如 @timeit
我正在尝试包装一个名为 content 的 div与另一个具有不同背景的 div。 但是,当将“margin-top”与 content 一起使用时div,似乎包装 DIV 获得了边距顶部而不是 co
文档不清楚,它似乎允许包装 dll 和 csproj 以在 Asp.Net Core 5 应用程序中使用。它是否允许您在 .Net Core 5 网站中使用针对 .Net Framework 4.6
我被要求开发一个层,该层将充当通用总线,而不直接引用 NServiceBus。到目前为止,由于支持不引人注目的消息,这并不太难。除了现在,我被要求为 IHandleMessages 提供我们自己的定义
我正在尝试包装 getServersideProps使用身份验证处理程序函数,但不断收到此错误:TypeError: getServerSideProps is not a function我的包装看
我有一个项目,它在特定位置(不是/src/resources)包含资源(模板文件)。我希望在运行 package-bin 时将这些资源打包。 我看到了 package-options 和 packag
我正在寻找打印从一系列对象中绘制的 div。我可以通过使用下面的管道语法来实现这一点。 each i, key in faq if (key == 0) |
我在 Meteor.js“main.js - Server”中有这个方法。 Meteor.methods({ messageSent: function (message) { var a
我注意到,如果我的自定义Polymer 1.x元素的宽度比纸张输入元素上的验证错误消息的宽度窄,那么错误将超出自定义元素的右边界。参见下图: 有没有一种机制可以防止溢出,例如在到达自定义元素的边界时自
我是一名优秀的程序员,十分优秀!