Give a std::string to StreamWriter to write a txt file - c++-cli

I want give a string as a argument to the Stream Writer writeline method in visual c++
StreamWriter^ sw = gcnew StreamWriter("Positive Sample.txt");
string Loc = "blabla";
sw->WriteLine(Loc);
It generating a error - no instance of overload function match the argument list

WriteLine method accepts CLI's String, and not std's string.
StreamWriter^ sw = gcnew StreamWriter("Positive Sample.txt");
String^ Loc = "blabla";
sw->WriteLine(Loc);
You can use System::Runtime::InteropServices::Marshal::PtrToStringAnsito marshal from C string to String, or you can pass C string into String's constructor:
string Loc = "blabla";
String^ strLoc = gcnew String(Loc.c_str());
EDIT
As Ben pointed out in the comments, you should use marshal_as instead PtrToStringAnsi:
Example from here (inverse operation could be found here)
// marshal_as_test.cpp
// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <msclr\marshal.h>
using namespace System;
using namespace msclr::interop;
int main() {
const char* message = "Test String to Marshal";
String^ result;
result = marshal_as<String^>( message );
return 0;
}

Related

How to set different decimal places in same rapidjson document

I have made a rapidjson document with all my objects and values using usual AddMember() method. Now I want to get the string out of that document for publishing to a mqtt broker. But inside that string, some members shall have 2 decimal places, some only one, and others all decimals.
I don't find how to set decimal place for a specific member after the document was fully builded.
I succeeded to do so by building my json document with a writer but this is not what i want to do because this document can't be easily modified:
#include <string>
#include <iostream>
#include <sstream>
#include <rapidjson/document.h> // rapidjson's DOM-style API
#include <rapidjson/prettywriter.h> // for stringify JSON
#include <rapidjson/stringbuffer.h>
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
Document doc;
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
writer.StartObject();
writer.Key("member1");
writer.SetMaxDecimalPlaces(2);
writer.Double(1.0000001);
writer.Key("member2");
writer.SetMaxDecimalPlaces(3);
writer.Double(3.123456);
writer.Key("member3");
writer.SetMaxDecimalPlaces(8);
writer.Double(2.123456);
writer.EndObject();
cout << buffer.GetString() << endl;
return 0;
}
./decimal
{"member1":1.0,"member2":3.123,"member3":2.123456}
Now, this how i build my document:
#include <string>
#include <iostream>
#include <sstream>
#include <rapidjson/document.h> // rapidjson's DOM-style API
#include <rapidjson/prettywriter.h> // for stringify JSON
#include <rapidjson/stringbuffer.h>
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
Document doc;
Document::AllocatorType& allocator = doc.GetAllocator();
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
doc.SetObject();
doc.AddMember("member1", 1.0000001, allocator);
doc.AddMember("member3", 3.123456, allocator);
doc.AddMember("member2", 2.123456, allocator);
writer.SetMaxDecimalPlaces(2);
doc.Accept(writer);
cout << buffer.GetString() << endl;
return 0;
}
./decimal
{"member1":1.0,"member2":2.12,"member3":3.12}
The SetMaxDecimalPlaces() applies to the whole document this way
I would like to get same output has first code example but using document made from second source code. How can i tell the writer to format each member differently ?
I'm super late to the party, but you can create a second writer with different writing settings:
StringBuffer buffer;
Writer<StringBuffer> writer1(buffer); // original writer
Writer<StringBuffer> writer2(buffer); // a new second writer
writer1.SetMaxDecimalPlaces(1);
writer2.SetMaxDecimalPlaces(2);
and then use the specific writers to write directly into the buffer instead of using the doc to call the writer:
writer.Key("member1");
writer.Double(1.0);
writer2.Key("member2");
writer2.Double(2.12);
writer2.Key("member3");
writer2.Double(3.12);
Full example:
using namespace rapidjson;
using namespace std;
int main (int argc, char* argv[])
{
StringBuffer buffer;
Writer<StringBuffer> writer1(buffer);
Writer<StringBuffer> writer2(buffer);
writer1.SetMaxDecimalPlaces(2);
writer2.SetMaxDecimalPlaces(2);
writer1.StartObject();
writer1.Key("member1");
writer1.Double(1.0);
writer2.Key("member2");
writer2.Double(2.12);
writer2.Key("member3");
writer2.Double(3.12);
writer1.EndObject();
cout << buffer.GetString() << endl;
return 0;
}

C++ Cannot convert from Initializer List to std::pair

I have a function called TestFunction which I've simplified down for this question... but in essence, I'm getting an error which says, <function-style-cast> cannot convert from 'initializer list' to std::pair<int, int>. Here's my simplified function:
#include <iostream>
#include <map>
void MyClass::TestFunction(cli::array<int>^ ids){
std::multimap<int, int> mymap;
int count = ids->Length;
for (int i = 0; i < count; ++i) {
//fill in the multimap with the appropriate data key/values
mymap.insert(std::make_pair((int)ids[i], (int)i));
}
}
As you can see, it's a really basic function (when simplified), but I get an error when I try to insert the data into the multimap. Does anyone know why?
I'd either use
mymap.insert(std::make_pair((int)ids[i], (int)i));
or
mymap.emplace((int)ids[i], (int)i);
I'm building off of the answer by #CoryKramer. It appears that if I create a temporary variable of type int and then pass that into the multimap.insert() function... that the error is fixed. Here's the new function:
#include <iostream>
#include <map>
void MyClass::TestFunction(cli::array<int>^ ids){
std::multimap<int, int> mymap;
int count = ids->Length;
for (int i = 0; i < count; ++i) {
//fill in the multimap with the appropriate data key/values
int ff = (int)ids[i];
mymap.insert(std::make_pair(ff, (int)i));
}
}
Out of curiousity... does anyone know why this worked?

Managed c++ to clr __pin to pin_ptr or interior_ptr

I am trying to compile a project that was previous using /oldsyntax, but now with /clr.
std::string Jhc::Interop::stlString(System::String^ s)
{
std::string out;
const wchar_t __pin * str = PtrToStringChars(s);
int len = s->Length*4;
char *buf = new char[len];
memset(buf,len,0);
I have changed System::String *s to System::String^ s, but how do I covert the line with PtrToStringChars(s);?
I have tried using pin_ptr and interior_ptr, but cannot make it work.

Converting from CStringArray* to C++/CLI Array

Could you please let me know how to convert CStringArray* to C++/CLI array. I am creating a wrapper dll which needs my data to be converted to unmanaged code. I am able to use basic data types like double * but not for CStringArray *.
Thank you.
Here is the solution
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
#include <msclr/marshal_atl.h>
CStringArray * myData; //Assume data is already filled
array<String ^> unmanagedData = gcnew array<String ^) (m_nDataCount);
for (int j = 0; j < m_nDataCount; j++)
{
String ^ stepName = marshal_as<String ^> (myData->GetAt(j));
unmanagedData[j] = stepName;
}
Marshaling as is the solution. Thanks to #crashmstr for helping me to crack this

LdrLoadDll problem

I am trying to code an alternative to LoadLibrary function, based on the idea of calling the function LdrLoadDll from ntdll.
This function needs as a parameter the dll file to load, in a UNICODE_STRING format.
I really can't get what I am doing wrong here (string seems to be correctly initialized), but when LdrLoadDll is called, I get the following error:
Unhandled exception in "Test.exe" (NTDLL.DLL): 0xC0000005: Access Violation.
I use Visual C++ 6.0 for this test, and I am using Windows 7 64 bit.
I post full code here, thanks in advance for any help:
#include <Windows.h>
typedef LONG NTSTATUS; //To be used with VC++ 6, since NTSTATUS type is not defined
typedef struct _UNICODE_STRING { //UNICODE_STRING structure
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef NTSTATUS (WINAPI *fLdrLoadDll) //LdrLoadDll function prototype
(
IN PWCHAR PathToFile OPTIONAL,
IN ULONG Flags OPTIONAL,
IN PUNICODE_STRING ModuleFileName,
OUT PHANDLE ModuleHandle
);
/**************************************************************************
* RtlInitUnicodeString (NTDLL.#)
*
* Initializes a buffered unicode string.
*
* RETURNS
* Nothing.
*
* NOTES
* Assigns source to target->Buffer. The length of source is assigned to
* target->Length and target->MaximumLength. If source is NULL the length
* of source is assumed to be 0.
*/
void WINAPI RtlInitUnicodeString(
PUNICODE_STRING target, /* [I/O] Buffered unicode string to be initialized */
PCWSTR source) /* [I] '\0' terminated unicode string used to initialize target */
{
if ((target->Buffer = (PWSTR) source))
{
unsigned int length = lstrlenW(source) * sizeof(WCHAR);
if (length > 0xfffc)
length = 0xfffc;
target->Length = length;
target->MaximumLength = target->Length + sizeof(WCHAR);
}
else target->Length = target->MaximumLength = 0;
}
NTSTATUS LoadDll( LPCSTR lpFileName)
{
HMODULE hmodule = GetModuleHandleA("ntdll.dll");
fLdrLoadDll _LdrLoadDll = (fLdrLoadDll) GetProcAddress ( hmodule, "LdrLoadDll" );
int AnsiLen = lstrlenA(lpFileName);
BSTR WideStr = SysAllocStringLen(NULL, AnsiLen);
::MultiByteToWideChar(CP_ACP, 0, lpFileName, AnsiLen, WideStr, AnsiLen);
UNICODE_STRING usDllFile;
RtlInitUnicodeString(&usDllFile, WideStr); //Initialize UNICODE_STRING for LdrLoadDll function
::SysFreeString(WideStr);
NTSTATUS result = _LdrLoadDll(NULL, LOAD_WITH_ALTERED_SEARCH_PATH, &usDllFile,0); //Error on this line!
return result;
}
void main()
{
LoadDll("Kernel32.dll");
}
in
_LdrLoadDll(NULL, LOAD_WITH_ALTERED_SEARCH_PATH, &usDllFile,0);
last parameter can't be zero
you can't call SysFreeString before you call _LdrLoadDll,
since the usDllFile.buffer parameter points to this string