String::Format problem

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I spent many hours on this, googling around and experimenting, and still
nothing.

I wrote an umanaged program (actually various classes), while I was
developing them I used command line to test it.
Now, I decided to make GUI for it, so I created new project: "Windows Forms
Application (.NET)" (I was trying to use something that's not managed (e.g.
MFC, but I learned quickly that I don't actually know how to use MFC :)
In .NET I was able to quickly create the GUI that looked as I wanted it too
look.

Now my problem is really silly. While I figured out how to convert
System::String to for example std::string, and looks like the other way
around is actually easy, I can't for a love of God make String::Format do
what I want.
Even the examples from MSDN doesn't work when I copy&paste them verbatim!
Here is an example:
http://msdn2.microsoft.com/en-us/library/fht0f5be.aspx

In a simple program that has just textbox, button and label, the following
code works:
label1->Text = String::Format("Hello, {0}", textBox1->Text);

But this, doesn't want to:
label1->Text = String::Format("Hello, {0}", 10);

My goal is basically do something like this:
unsigned short int pc = 8000;
label1->Text = String::Format("Address: {0,4:X}", pc);

Anyone has idea what I'm doing wrong?

I have also an unrelated question: If I have a managed class (for the
form), and I define inside a pointer to an unmanaged class, is that a good
practice? Right now it appears to work fine, but before I had an exception
that the pointer is null (even though I did new on the form's load, and
pointer was used after selecting an option from a menu). I have no idea how
I even fixed it.

Thanks for help.
 
My goal is basically do something like this:
unsigned short int pc = 8000;
label1->Text = String::Format("Address: {0,4:X}", pc);

Would this be sufficient for you?
label1->Text = "Address: " + pc.ToString("X4");
Anyone has idea what I'm doing wrong?

I have also an unrelated question: If I have a managed class (for the
form), and I define inside a pointer to an unmanaged class, is that a good
practice? Right now it appears to work fine, but before I had an exception
that the pointer is null (even though I did new on the form's load, and
pointer was used after selecting an option from a menu). I have no idea
how
I even fixed it.

That is the right way to use native classes from managed code. Often, you
create a managed class to wrap each native object, and its only
responsibility is taking care of that one native pointer.
 
Would this be sufficient for you?
label1->Text = "Address: " + pc.ToString("X4");

I had no idea I could use .ToString() on non objects...
But unfortunately, I'm getting now:
e:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Form1.h(98) : error C2110: '+' : cannot add two pointers

Also, this solution would solve the current problem I'm having, but I'm
afraid that I'll come with another related question, that .ToString() might
not solve for me...
That is the right way to use native classes from managed code. Often, you
create a managed class to wrap each native object, and its only
responsibility is taking care of that one native pointer.

That's good. Any recommendation. where I can read more about wrapping
unmanaged classes inside of managed ones?
 
Derek Kulinski / takeda said:
I had no idea I could use .ToString() on non objects...

All basic types in C++/CLI have a dual citizenship, they are a native
non-object as well as a .NET value type. Note that this doesn't include
strings, although a string literal can be treated as either a char* or
System::String, variables don't convert back and forth.
But unfortunately, I'm getting now:
e:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Form1.h(98) : error C2110: '+' : cannot add two pointers

one of these should work:

label1->Text = gcnew String("Address: ") + pc.ToString("X4");

label1->Text = String::Concat("Address: ", pc.ToString("X4"));
Also, this solution would solve the current problem I'm having, but I'm
afraid that I'll come with another related question, that .ToString()
might
not solve for me...

I think your format string was wrong. looking at the documentation, I think
it should be:
label1->Text = String::Format("Address: {0,X4}", pc);

if you need the flexibility that String::Format gives (it's useful for
localization, when different languages might want to show the values in a
different order). If you don't need the reordering, explicit ToString will
be much faster than String::Format. In fact, this is quite possibly faster
than what you had:
label1->Text = String::Format("Address: {0}", pc.ToString("X4"));

That's good. Any recommendation. where I can read more about wrapping
unmanaged classes inside of managed ones?

For the pure .NET interop (p/invoke) way (needed for verifiable code), use
..NET Reflector to take a look at SafeHandle.

For the C++ interop way (faster, easier), google for C++/CLI wrapper, there
are some promising results including several on codeproject.
 
All basic types in C++/CLI have a dual citizenship, they are a native
non-object as well as a .NET value type.

So it is just .NET thing, and won't work with other compilers I assume.
Note that this doesn't include
strings, although a string literal can be treated as either a char* or
System::String, variables don't convert back and forth.

I noticed that I can't convert them back and forth, but I learned about
Marshal::StringToHGlobalAnsi which seems to do the job.
one of these should work:
label1->Text = gcnew String("Address: ") + pc.ToString("X4");
label1->Text = String::Concat("Address: ", pc.ToString("X4"));

The second one seems to be working flawlessly.
The first one tells me that gcnew is undeclared:
e:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Form1.h(99) : error C2065: 'gcnew' : undeclared identifier
e:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Form1.h(99) : error C2146: syntax error : missing ';' before
identifier 'String'
e:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Form1.h(99) : error C3604: 'System::String': can only create
a __gc type object on the __gc heap
__gc types can not be created on the stack


Maybe there's some option enabled in my VC++ (it is from VS 2003), but
which option is responsible for that?
There's comman line arguments for the compiler:
/Od /AI "E:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Debug" /D "WIN32" /D "_DEBUG" /D "_MBCS" /FD /EHsc /MTd /GS
/Yu"stdafx.h" /Fp"Debug/test.pch" /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3
/nologo /c /Zi /clr /TP /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\mscorlib.dll" /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.dll" /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Data.dll" /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Drawing.dll" /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.Windows.Forms.dll" /FU
"C:\WINNT\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"

and linker:
/OUT:"E:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Debug\test.exe" /INCREMENTAL /NOLOGO /DEBUG /ASSEMBLYDEBUG
/PDB:"E:\Documents and Settings\takeda\My Documents\Visual Studio
Projects\test\Debug/test.pdb" /SUBSYSTEM:WINDOWS /FIXED:No kernel32.lib
user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib
ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
I think your format string was wrong. looking at the documentation, I think
it should be:
label1->Text = String::Format("Address: {0,X4}", pc);

if you need the flexibility that String::Format gives (it's useful for
localization, when different languages might want to show the values in a
different order). If you don't need the reordering, explicit ToString will
be much faster than String::Format. In fact, this is quite possibly faster
than what you had:
label1->Text = String::Format("Address: {0}", pc.ToString("X4"));

I think I initially wrote it just like you showed me.
It didn't worked, and neither did this:
label1->Text = String::Format("Hello, {0}", 10);
For the pure .NET interop (p/invoke) way (needed for verifiable code), use
.NET Reflector to take a look at SafeHandle.
For the C++ interop way (faster, easier), google for C++/CLI wrapper, there
are some promising results including several on codeproject.

I will, thank you.


While I still have questions, at lest I can work with String::Concat and
..ToString() around that.
I'm really wondering what's wrong with my C++ compiler. Even examples on
MSDN webpage didn't work.
 
[snip]
Maybe there's some option enabled in my VC++ (it is from VS 2003), but
which option is responsible for that?
[snip]
I'm really wondering what's wrong with my C++ compiler. Even examples on
MSDN webpage didn't work.

You need an upgrade to VC 2005, even Express Edition will work. Managed
Extensions for C++ that came with VC 2003 were so full of problems that
Microsoft started over in VC 2005, giving us the C++/CLI language.
 
You need an upgrade to VC 2005, even Express Edition will work. Managed
Extensions for C++ that came with VC 2003 were so full of problems that
Microsoft started over in VC 2005, giving us the C++/CLI language.

Actually one of the readers here (I don't know if he wants me to mention
his name since he answered privately) pointed me to use a __box() around
basic types like integers etc. which seems to do the thing. I can put char*
in String() and it seems to solve most of the problems.
He also recommended me to switch to VS 2005, and I'll try it as soon as I
can.

Anyway, thank you Ben for troubleshooting the problem, I really appreciate
that you tried to help.
I have another question about creating virtual listbox, but I'll create
another thread for it, since it is unrelated.
 
Back
Top