2010-02-01 27 views
10

Ich verwende die .NET DateTime, um das aktuelle Datum und die Uhrzeit zu erhalten. Ich konvertiere es in eine Zeichenfolge, die als Teil eines Dateinamens verwendet wird. Das Problem besteht darin, dass der OpenCV-Befehl zum Speichern eines Bildes einen char * nicht einen String-Typ benötigt und DateTime nur einen String^-Typ ausgibt. Wie mache ich das? Heres der Code nicht abgeschlossenMüssen String konvertieren^nach 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

WARUM DIE ALL-CAPS? SCHREIEN SIE? –

+1

Vermutlich steckt sein Caps-Lock fest. Das erklärt auch, warum er ".net" ohne Großbuchstaben geschrieben hat. – jalf

+0

fälschlicherweise Caps Lock – kman99

Antwort

0

Zufall Googeln hat mir diese. Vielleicht kann jemand es verkürzen?

Edit: Dies ist länger als die Operationen der Marshal-Klasse, funktioniert aber mit mehr Codierungen. In Ihrem Fall klingt es wie der einfachere StringToHGlobalAnsi Ansatz wird alles tun, was Sie brauchen.

0

Verwenden Sie die StringToXxxAnsi Funktionen in der Marshal class, um einen char* Puffer zuzuweisen, dann die entsprechenden Funktionen aus der gleichen Klasse, um sie zu befreien.

15

Am besten verwenden Sie StringToHGlobalAnsi. Hier ist der vollständige Code, der zeigt, wie es gemacht wurde und sich daran erinnert, den zugewiesenen Speicher freizugeben.

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

Vielleicht möchten Sie mit einem zu überdenken ‚:‘ Zeichen im Dateinamen, wie ich Windows nicht glauben mag dies sehr.

+0

Würde es sein besser geeignet, Marshal :: FreeHGlobal() anstelle von Marshal :: FreeCoTaskMem() zu verwenden? Meine MSDN-Hilfe für StringToHGlobalAnsi() besagt, dass FreeHGlobal() verwendet wird, um den Speicher freizugeben. – cmw

+0

Ja, fairer Anruf; Bearbeiten gemacht. Ich denke, ich habe mich angewöhnt, FreeCoTaskMem standardmäßig zu verwenden. – mcdave

+0

anstatt den Code für die Freigabe des Zeigers hier zweimal zu schreiben, könnte man endlich verwenden. 'versuchen {...} endlich {Marshal :: FreeHGlobal (...)}' –

4

Eigentlich fand ich den einfachsten Weg, um eine char * von einem String^ zu bekommen, ist gute ol 'sprintf() zu verwenden. Also in Ihrem Fall können Sie einfach tun:

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

Keine Notwendigkeit, die Marshal Funktionen aufzurufen!

aktualisieren

So scheint es, dass VS 2015 stärker an den C++ 11-Standards entspricht, so sprintf() mit dem .NET-String verwendet, wird nicht funktionieren. Der einfachste Weg ist es, die marshal_as() Funktion wie folgt zu verwenden:

Fügen Sie diese Zeilen, bevor Sie Ihren Code:

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

Dann sollte diese Arbeit:

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

Andernfalls, wenn Sie nicht wollen, Um die Funktion marshal_as() zu verwenden, können Sie die Zeichenfolge Zeichen für Zeichen wie folgt kopieren:

+0

Nun, ich war skeptisch - nichts ist jemals so einfach - aber es scheint zu funktionieren (mit Visual Studio 2012). Ist hinter den Kulissen etwas Schlimmes passiert, was bedeutet, dass wir das nicht einfach tun sollten? – njplumridge

+0

@njplumridge Ich war auch skeptisch, als ich von dieser Technik erfuhr. Ich vermute, dass es hinter den Kulissen mahnt, aber andere wissen vielleicht mehr darüber. Das verbirgt jedoch die ganze Komplexität. Ich würde eine Überprüfung für die Größe vor dem sprintf() Pufferüberläufe verhindern. Siehe meine Bearbeitung oben. – Ionian316

+0

@njplumridge Es macht Marshalling hinter den Kulissen. Details finden Sie in dieser SO-Antwort (http://stackoverflow.com/a/11831686/1516125). – Ionian316