2010-02-01 3 views
10

Я использую .NET DateTime, чтобы получить текущую дату и время. Я преобразовываю его в строку для использования в качестве части имени файла. Проблема заключается в том, что команда OpenCV для сохранения изображения требует символа char *, а не строкового типа, а DateTime будет выводить только тип String ^. Как это сделать? Heres код не заполненНеобходимо преобразовать String^в char *

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); 
+5

ПОЧЕМУ ВСЕ-КАПС? ВЫ СМОТРИТЕ? –

+1

Предположительно, его колпачок заблокирован. Это также объясняет, почему он написал «.net» без крышек. – jalf

+0

ошибочно хит колпачок блокировка – kman99

ответ

0

Случайные Googling у меня это. Может быть, кто-то может сократить его?

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 сделает все, что вам нужно.

0

Используйте StringToXxxAnsi функции в Marshal class, чтобы выделить буфер char*, а затем соответствующие функции из того же класса, чтобы освободить их.

15

Ваш лучший выбор - использовать 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); 
} 

Вы можете пересмотреть, используя символ «:» в имени файла, так как я не верю, что окна любит это очень много.

+0

Будет ли это более целесообразно использовать маршал :: FreeHGlobal() вместо маршала :: FreeCoTaskMem()? Моя помощь MSDN для StringToHGlobalAnsi() говорит, что FreeHGlobal() использует свободную память. – cmw

+0

Да, честный вызов; Сделано редактирование. По-моему, я привык использовать FreeCoTaskMem по умолчанию. – mcdave

+0

вместо того, чтобы писать код для освобождения указателя здесь дважды, вы могли бы использовать, наконец. 'try {...} finally {Marshal :: FreeHGlobal (...)}' –

4

На самом деле, я нашел самый простой способ получить 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 функции!

Update

Получается, что VS 2015 более тесно прилипает к C++ 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]); 
} 
+0

Ну, я был настроен скептически - ничего не бывает так просто, но он работает (с Visual Studio 2012). Что-то плохое происходит за кулисами, а это значит, что мы не должны просто так делать? – njplumridge

+0

@njplumridge Я тоже был настроен скептически, когда узнал об этой технике. Я предполагаю, что он делает сортировку за кулисами, но другие могут знать об этом больше. Тем не менее, это скрывает всю сложность. Я бы сделал проверку размера до того, как sprintf() предотвратит переполнение буфера. См. Мое редактирование выше. – Ionian316

+0

@njplumridge Он делает сортировку за кулисами. См. [Этот ответ SO] (http://stackoverflow.com/a/11831686/1516125) для получения дополнительной информации. – Ionian316