Необходимо преобразовать String ^ в char *
Я использую .NET DateTime для получения текущей даты и времени. Я преобразовываю его в строку для использования в качестве части имени файла. Проблема заключается в том, что команда OpenCV для сохранения изображения требует char * не строкового типа, а DateTime будет выводить только тип String ^. Как это сделать? Heres код не завершен
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
IplImage* toSave;
CvCapture* capture = cvCreateCameraCapture(0);
toSave = cvQueryFrame( capture );
cvSaveImage(nowString, toSave);
cvReleaseImage(&toSave);
cvReleaseCapture(&capture);
Ответы
Ответ 1
Лучше всего использовать StringToHGlobalAnsi
. Вот полный код, показывающий, как его сделать и запомнить освобождение выделенной памяти.
using namespace System::Runtime::InteropServices;
void MethodName()
{
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
IntPtr ptrToNativeString = Marshal::StringToHGlobalAnsi(nowString);
try
{
CvCapture* capture = cvCreateCameraCapture(0);
IplImage* toSave = cvQueryFrame(capture);
cvSaveImage(static_cast<char*>(ptrToNativeString.ToPointer()), toSave);
cvReleaseImage(&toSave);
cvReleaseCapture(&capture);
}
catch (...)
{
Marshal::FreeHGlobal(ptrToNativeString);
throw;
}
Marshal::FreeHGlobal(ptrToNativeString);
}
Возможно, вы захотите переосмыслить использование символа ':' в имени файла, так как я не считаю, что Windows это очень нравится.
Ответ 2
На самом деле, я нашел самый простой способ получить char *
из String^
- использовать хороший ol 'sprintf()
. Поэтому в вашем случае вы можете просто сделать это:
char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
if (nowString->Length < sizeof(cNow)) // make sure it fits & allow space for null terminator
sprintf(cNow, "%s", nowString);
Не нужно вызывать функции Marshal
!
Обновление
Итак, похоже, что VS 2015 более тесно придерживается стандартов С++ 11, поэтому использование sprintf()
с .NET String не будет работать. Самый простой способ - использовать функцию marshal_as()
следующим образом:
Включите эти строки перед кодом:
#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;
Тогда это должно работать:
char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
string sNow = marshal_as<string>(nowString);
if (sNow.length() < sizeof(cNow)) // make sure it fits & allow space for null terminator
sprintf(cNow, "%s", sNow.c_str());
В противном случае, если вы не хотите использовать функцию marshal_as()
, вы можете скопировать символ строки символом следующим образом:
char cNow[17] = { 0 };
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
if (nowString->Length < sizeof(cNow)) // make sure it fits & allow space for null terminator
{
for (int i = 0; i < nowString->Length; i++)
cNow[i] = static_cast<char>(nowString[i]);
}
Ответ 3
Вам нужно прочитать о взаимодействии С++ и сортировке данных.
В принципе: вам нужно "отличить".NET String
от массива С++ TCHAR
.
Смотрите это: http://msdn.microsoft.com/en-us/library/ef4c3t39(VS.80).aspx
Ответ 4
Случайный гуглинг получил меня. Может быть, кто-то может сократить его?
cli::array<char>^ bytes = Encoding::ASCII::GetBytes(nowString);
pin_ptr<char> pinned = &bytes[0];
std::string nativeString((char*)pinned, bytes->Length);
char const* chars = nativeString.c_str();
Изменить: это больше, чем операции класса маршала, но работает с большим количеством кодировок. В вашем случае это похоже на то, что более простой подход StringToHGlobalAnsi
сделает все, что вам нужно.
Ответ 5
Используйте функции StringToXxxAnsi
в Marshal
class, чтобы выделить буфер char*
, затем соответствующие функции из того же класс, чтобы освободить их.