问题
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(&toSave);
cvReleaseCapture(&capture);
回答1:
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.
回答2:
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]);
}
回答3:
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.
回答4:
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
回答5:
Use the StringToXxxAnsi
functions in the Marshal class to allocate a char*
buffer, then the appropriate functions from the same class to free them.
来源:https://stackoverflow.com/questions/2178023/need-to-convert-string-to-char