|
Hi Mike,
led mike wrote: I would be interested in knowing the answer to this.
I _think_ I found the answer - it's a question of ownership. Apparently, Microsoft's object claims ownership to the streams (which they did not open). I've read through the documentation on the various ctors and Close() methods, but I must have missed who owns what.
I like unmanaged code better . At least with unmanaged, I could fire up WinDbg and walk in, observing what is happening. With managed, I get an error about attempting to set a breakpoint.
Others have asked this question also. In an MSDN blog, the BCL team (owner of System.IO) claims objects should only dispose of streams they create [1]:
The default behavior of a class that takes a Stream in it’s Constructor is to also be IDisposable and close the stream when the wrapper is closed. So, if I am reading this correctly, I am responsible for StreamWriter. When I call Close() on the StreamWriter, it will close the CryptoStream and Memory Stream.
I believe the following listing is correct (at least its behavior is not throwing exceptions). I should only close the outer most object. If an exception occurs, close the CryptoStream (as per the documentation of CryptoStream) and let the CLR clean up the rest. So, to summarize:
1) I hold the StreamWriter^ writer because I call Close() on it if all goes well
2) I hold the CryptoStream^ crypto because I call Close() on it if anything fails.
3) I hold the MemoryStream^ memory because I need to do something with the cipher text stream/byte array if all goes well _before_ I call Close() on the StreamWriter
Finally, I believe Microsoft's example on MSDN is incorrect [2]. I suspect it will throw the exception 'Cannot access a closed stream' also. But I did not attempt to run their code.
Jeff
StreamWriter^ writer;
CryptoStream^ crypto;
MemoryStream^ memory;
try
{
writer = gcnew StreamWriter(
crypto = gcnew CryptoStream(
memory = gcnew MemoryStream(),
tdes->CreateEncryptor( key, iv ),
CryptoStreamMode::Write
)
);
writer->Write( ... );
}
catch( System::Exception^ e )
{
crypto->Close();
Console::WriteLine(L"CLR Exception: {0}", e->Message);
}
finally
{
writer->Close( );
} [1] Should I close the stream?[^]
[2] CryptoStream Class[^]
|
|
|
|
|
Yeah, that's what I thought, thanks for posting your findings.
led mike
|
|
|
|
|
Hello,
I am porting an unmanaged console application to windows app using Visual Studio 2005 C++ Express. I worked with Visual C++ and MFC before but this is my first time to use .NET and Windows form in C++. I was able to create the windows GUI on Windows form easily. My problem is for the function in unmanaged DLL to print out the message in my Windows form. I've seen a few blogs and discussions about the managed C++ code to unmanaged code. But I have not seen yet about my particular problem which is unmanaged to managed. Again, here is my specific problem.
1. I've created a textBox in Windows form and set the property to read only.
2. I developed a wrapper function that the unmanaged DLL will use to print its message.
3. How can my wrapper function access the textBox from the Windows form to print the message?
4. Do I need to add a public method in my windows form class to access the private textBox method/property?
I appreciate the help and thanks.
Manny
|
|
|
|
|
You can't call managed code from unmanaged code.
You can, however, call managed code from native code that is compiled to CLR.
If the DLL is not a .NET assembly (all native - none of it is compiled with /CLR) then you'll need to expose a
native method somewhere for the DLL to call. Maybe that's what you already have in item 2 (see question below)?
Manny Roxas wrote: 2. I developed a wrapper function that the unmanaged DLL will use to print its message.
Is this function in the DLL or the app?
Is the DLL a managed or mixed-mode assembly or pure native DLL?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark,
Thanks for your reply. To answer your question, the wrapper function is a managed code in the app. The DLL is compiled in VS 2005 C++ as "No CLR support". But even without the DLL, just my Windows app and wrapper function, I need to know how my wrapper function access the textBox in my Windows form. I need to get the instances of my Windows form or its handle. But I don't know how to do it in .NET.
Manny
|
|
|
|
|
Managed handles can be moved at any time, so to keep a managed handle around
for use by unmanaged code, you can use the GCHandle Structure[^].
There's a handy template wrapper for GCHandle called gcroot[^] that you can use to
simplify the code.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi Mark,
What I really want to do is declare the Form handle as global or public as shown below so I that my wrapper function can access it. My wrapper function is still a managed code. Can I do that? I was told that it can be done in Visual Basic.
Form1 ^MyWindowsForm = gcnew Form1();
Thanks,
Manny
|
|
|
|
|
I still recommend reading those links to understand what's going on.
The simplest syntax is using gcroot, which hides some messier code used
when using GCHandle directly...
#include <vcclr.h>
gcroot<Form1 ^> MyWindowsForm;
...
MyWindowsForm = gcnew Form1();
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I got it. Thanks, Mark.
Manny
|
|
|
|
|
Can anyone suggest a good book for C++/CLI??
I dont find much books in the market though...
Strange!!
And I heard somewhere that CLI is the most powerful language!!
I need a book with imtermediate skills..
Although I am a beginner, still I think I can learn those basics from internet..
So any help to get a good intermidiate C++/CLI book will be highly appreciated..
Thanks!!
|
|
|
|
|
wrote: CLI is the most powerful language!!
CLI means Common Language Interface. It is not an actual programming language, but rather a set of classes that make up the .NET Framework.
"I guess it's what separates the professionals from the drag and drop, girly wirly, namby pamby, wishy washy, can't code for crap types." - Pete O'Hanlon
|
|
|
|
|
Nishant Sivukumar has an excellent book on the topic, it's published by Manning.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Christian Graus wrote: Nishant Sivukumar has an excellent book on the topic, it's published by Manning.
I've seen Nishant's book..
Its really excellent, but it is not for intermediate developers..
It teaches interop capabilities and WPF,WCF which I think is relevant for advanced developers..
Anyways, thanks for your help..
If anybody else knows an intermediate level book please let me know..
Thanks again..
|
|
|
|
|
|
I have searched for last 2 months the C++/CLI programming book in few public university but what I can find are books on native c++ maybe mixed with part of the C++/CLI and C#. If want to use .NET Framework it is better look for C# as reference.
|
|
|
|
|
Q1:
enum class Instrution{sit, sleep, jog, nullptr};
ref class DataPack{
public: Instruction^ xxx;
DataPack(array<Byte>^ data){
this->xxx = safe_cast<instruction^>(BitConvert::ToInt32(data, 0));
}
};
I create an object of the ref class DataPack in ref class Form1:
array<Byte>^ byData = gcnew array<Byte>(1024);
DataPack^ DataRecv = gcnew DataPack(byData);
switch(DataRecv->xxx) {}
2 error occur:
(1)error C2682: cannot use 'safe_cast' to convert from 'int' to 'DataPack::Instruction ^' (happen in ref class DataPack)
(2)error: illegal type of switch statement.(happen in ref class Form1)
I think main cause is due to the error(1). Whats wrong with my casting? Reference to c# this.xxx = (Instruction)BitConvert::ToInt32(data, 0); work properly.
Q2:
List<Byte>^ result = gcnew List<Byte>();
result->AddRange(BitConverter::GetBytes((int)xxx));
error C2664:'System::Collections::Generic::List<t>::AddRange': cannot convert parameter 1 from 'cli::array <type>^' to 'System::Collections::Generic::IEnumerable<t>^'
What is about 'IEnumerable<t>? Any example for understanding? The above usage of list::AddRange is reference to the c# but not work that way in c++/cli.
Thanks..
modified on Tuesday, March 18, 2008 4:43 AM
<div class="ForumMod">modified on Tuesday, March 18, 2008 4:46 AM</div>
|
|
|
|
|
It's really difficult to decipher your post, but I'll take a crack at Q1.
The error messages pretty much explain the errors. You can't convert an Int32 to an enum^.
You also can't switch on an enum^.
You can't use the nullptr keyword in the enumeration.
Use your enumeration like an enumeration - you don't create handles to them on the GC heap.
Maybe this is what you wanted:
enum class Instruction {sit, sleep, jog};
ref class DataPack
{
public:
Instruction xxx;
DataPack(array<Byte>^ data)
{
this->xxx = safe_cast<Instruction>(BitConverter::ToInt32(data, 0));
}
};
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Err...what you mean by decipher my post? Is that about my question expression hard to understand or something else? Anyway, I am sorry. Just tell me what should I do to improve. Thank you.
|
|
|
|
|
Unknown types/classes, case sensitivity, etc. I re-read it many times and deduced the types as well as I could, mostly
based on the error messages.
Actual pasted code is much easier to work with than pseudocode, but that's just me.
Unless maybe that wasn't C++?
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Is there any method in BCL which eliminates the Duplicate items from a listbox?
I am using C++/CLI in Visual Studio 2008..
Or do I have to specifically write a method for it??
|
|
|
|
|
Don't cross post, it is rude. Your question has been already answered in C# forum.
Giorgi Dalakishvili
#region signature
my articles
#endregion
|
|
|
|
|
|
Hi,
I am creating a treeview,like Solution Explorer. I done the linking of current file. Now what i want is, it will check the function syntax based on that it will generate the treenode automatically . can you give me some sample code.
|
|
|
|
|
Hi All,
The only thing I can say is I am missing something... Can anyone bail me out.
Thanks,
Jeff
array<Byte>^ key = { ... };
array<Byte>^ encrypted = { ... };
...
pin_ptr<Byte> pk = const_cast< interior_ptr<Byte> >(key);
pin_ptr<Byte> pe = const_cast< interior_ptr<Byte> >(encrypted);
bool result = Decrypt( pk, key->Length, pe, encrypted->Length );
|
|
|
|
|
Found it...
Jeffrey Walton wrote: const_cast< interior_ptr<byte> >(key);
const_cast< interior_ptr<Byte> >(&key[0]);
Jeff
|
|
|
|