Необходимо преобразовать 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*, затем соответствующие функции из того же класс, чтобы освободить их.