I am using the .NET DateTime to get the current date and time. I am converting it to a string to use as part of a file name. The problem is the OpenCV command to save an image requires a char * not a string type, and DateTime will only output a String^ type. How do I make this work? Heres the code not completed
String^ nowString = DateTime::Now.ToString("yyyy-MM-dd-HH:mm");
IplImage* toSave;
CvCapture* capture = cvCreateCameraCapture(0);
toSave = cvQueryFrame( capture );
cvSaveImage(nowString, toSave);
cvReleaseImage开发者_JAVA技巧(&toSave);
cvReleaseCapture(&capture);
Your best bet is to use StringToHGlobalAnsi
. Here is complete code showing how its done and remembering to free the memory allocated.
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);
}
You might want to rethink using a ':' character in the filename, as I don't believe windows likes this very much.
Actually, I found the easiest way to get a char *
from a String^
is to use good ol' sprintf()
. So in your case, you can simple do this:
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 need to call the Marshal
functions!
Update
So it appears that VS 2015 adheres more closely to the C++11 standards, so using sprintf()
with the .NET String won't work. The easiest way is to use the marshal_as()
function like this:
Include these lines before your code:
#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;
Then this should work:
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());
Otherwise, if you don't want to use the marshal_as()
function, you can copy the string character by character like this:
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]);
}
Random Googling got me this. Maybe someone can shorten it?
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();
Edit: This is longer than the operations of the Marshal class, but works with more encodings. In your case, it sounds like the simpler StringToHGlobalAnsi
approach will do everything you need.
You need to read about C++ interop and data marshalling.
Basically: you need to "cast" the .NET String
to a C++ TCHAR
array.
See this: http://msdn.microsoft.com/en-us/library/ef4c3t39(VS.80).aspx
Use the StringToXxxAnsi
functions in the Marshal
class to allocate a char*
buffer, then the appropriate functions from the same class to free them.
精彩评论