2010-02-01 27 views
10

Estoy usando .NET DateTime para obtener la fecha y hora actuales. Lo estoy convirtiendo en una cadena para usar como parte de un nombre de archivo. El problema es que el comando OpenCV para guardar una imagen requiere un carácter * no un tipo de cadena, y DateTime solo dará como resultado un tipo de cadena ^. ¿Cómo hago que esto funcione? Aquí está el código no completadoNecesita convertir String^en 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

¿POR QUÉ TODAS LAS CAPS? ¿ESTÁS GRITANDO? –

+1

Es de suponer que su bloqueo de mayúsculas está atascado. Eso también explica por qué deletreó ".net" sin mayúsculas. – jalf

+0

golpeó erróneamente las tapas de bloqueo – kman99

Respuesta

0

aleatoria googlear mí esto tiene. Tal vez alguien puede acortarlo?

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(); 

Editar: Esto es más largo que las operaciones de la clase Marshal, pero funciona con más codificaciones. En su caso, parece que el enfoque más simple de StringToHGlobalAnsi hará todo lo que necesite.

0

Use los StringToXxxAnsi funciones en el Marshal class asignar un búfer char*, entonces las funciones apropiadas de la misma clase para liberarlos.

15

Su mejor opción es usar StringToHGlobalAnsi. Aquí hay un código completo que muestra cómo se hace y recuerda liberar la memoria asignada.

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); 
} 

Es posible que desee reconsiderar el uso de un ':' carácter en el nombre del archivo, ya que no creo que las ventanas le gusta mucho esta idea.

+0

Sería más apropiado para usar Marshal :: FreeHGlobal() en lugar de Marshal :: FreeCoTaskMem()? Mi ayuda de MSDN para StringToHGlobalAnsi() dice que use FreeHGlobal() para liberar la memoria. – cmw

+0

Sí, llamada justa; Editar hecho. Supongo que adquirí el hábito de usar FreeCoTaskMem por defecto. – mcdave

+0

en lugar de escribir el código para liberar el puntero aquí dos veces, podría usar finalmente. 'try {...} finally {Marshal :: FreeHGlobal (...)}' –

4

En realidad, he encontrado la manera más fácil de conseguir un char * de un String^ es utilizar el buen ol' sprintf(). Así, en su caso, se puede hacer esta sencilla:

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

No hay necesidad de llamar a las funciones Marshal!

actualización

lo que parece que VS 2015 se adhiere más estrechamente a las normas C++ 11, por lo que usar sprintf() con .NET cadena no va a funcionar. La forma más sencilla es utilizar la función marshal_as() así:

Incluir estas líneas antes de su código:

#include <msclr/marshal_cppstd.h> 
using namespace msclr::interop; 

Entonces esto debería funcionar:

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()); 

De lo contrario, si no se desea para usar la función marshal_as(), puede copiar la cadena carácter por carácter de esta manera:

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

Bueno, era escéptico, nada es tan fácil, pero parece funcionar (con Visual Studio 2012). ¿Hay algo malo sucediendo detrás de escena que significa que no deberíamos hacer esto? – njplumridge

+0

@njplumridge Yo también era escéptico cuando aprendí sobre esta técnica. Supongo que se está organizando entre bastidores, pero otros pueden saber más al respecto. Esto oculta toda la complejidad sin embargo. Haría una comprobación del tamaño antes de que el sprintf() evite los desbordamientos del búfer. Ver mi edición arriba. – Ionian316

+0

@njplumridge Está organizando detrás de bastidores. Vea [esta respuesta SO] (http://stackoverflow.com/a/11831686/1516125) para más detalles. – Ionian316