|
Could someone provide me with code examples of:
- A C++/CLI program with a function that takes a string as an argument, writes it into every entry of an array of length 5, and returns that array to the caller.
- A C# program which invokes the above program.
I've spent a good portion of the day poking at C# and C++/CLI trying to get them to talk to each other and a simply am getting no where.
I'm certain, given the above example, I can extrapolate what I'll need to complete my task. My problem, is most of the stuff I've found via google searches either just shows off C++/CLI syntax (and does not shows how to access it via another .NET language), or uses what I've learned are "old" interoperability conventions.
Any assistance would be greatly appreciated.
|
|
|
|
|
Sound like homework question. But here you go..
Shadowsoal wrote: A C++/CLI program with a function that takes a string as an argument, writes it into every entry of an array of length 5, and returns that array to the caller.
typedef array<System::String^> StringArray;
public ref class Foo
{
public:
StringArray^ GetStringArray(System::String^ str)
{
StringArray^ a = gcnew StringArray(5);
for(int i = 0; i < 5; i++)
{
a[i] = str;
}
return a;
}
};
int main(StringArray^ args)
{
Foo^ foo = gcnew Foo();
StringArray^ a = foo->GetStringArray("Test");
for each(String^ str in a)
{
Console::WriteLine(str);
}
return 0;
}
Shadowsoal wrote: A C# program which invokes the above program.
In your C# project, add reference to the assembly you got from the above code. You will get access to class Foo .
|
|
|
|
|
Certainly not a homework question. Initially I was just going to ask for the C++/CLI to write helloworld, but I figured I'd ensure I figured out how to pass around arrays and the like.
I've got a library written in C that i need to make C# compliant for a client, and from what I've seen the way to do that is to write a wrapper around the C library in C++/CLI.
Regardless of that, thank you for the response. I'm not developing this specifically in Visual Studio though, I was just compiling with cl and csc. Which is why I was wondering if someone could explain how to explicitly link the two. There's lots on the internet about C++/CLI, what I'm having trouble with is convincing a C# program to play nice with something like the above code.
Thanks again!
|
|
|
|
|
Shadowsoal wrote: Certainly not a homework question
My mistake
Shadowsoal wrote: I'm not developing this specifically in Visual Studio though, I was just compiling with cl and csc. Which is why I was wondering if someone could explain how to explicitly link the two.
I am not getting where you are stuck.
Use cl with /clr command switch to compile C++/CLI program. Make a DLL from it which can be run on common language runtime. See the compiler switches here[^].
Once you generated the DLL, use csc to compile the C# application. There is no linker needed for C# programs. Specify the DLL as reference to the compiler. I guess /reference is the compiler switch used for that. See /lib[^] as well for specifying the directories where to look for assembly.
|
|
|
|
|
Yeah, that's exactly what I was doing before. I suppose I just had something wrong in the C++/CLI file.
Thanks again!
|
|
|
|
|
Shadowsoal wrote: I suppose I just had something wrong in the C++/CLI file.
Does it compile? Are you able to view the produced DLL via reflector[^]?
|
|
|
|
|
Haha, it's midnight in my neck of the woods, and I don't have any of my code on my home machine. Despite that, I'm fairly confident I'll be able to resolve my issues given what you've said. My biggest problem was every Google query resulted in different people answering similar, but non-identical, questions all in different manners. From what I've read, Microsoft's .NET interoperability standards have changed quite a bit over the years, so I'm fairly certain I was probably mixing some old stuff and new stuff that just didn't jive. That combined with the fact that all of the explicit tutorials involved going step by step through visual studio, which is not a tool I'm using.
My deepest thanks, you've been extremely helpful!
|
|
|
|
|
Okay, here is your code, very slightly changed
using namespace System;
typedef array<String^> StringArray;
public ref class Foo
{
public:
StringArray^ GetStringArray(String^ str)
{
StringArray^ a = gcnew StringArray(5);
for(int i = 0; i < 5; i++)
{
a[i] = str;
}
return a;
}
};
int main(StringArray^ args)
{
Foo^ foo = gcnew Foo();
StringArray^ a = foo->GetStringArray("Test");
for each(String^ str in a)
{
Console::WriteLine(str);
}
return 0;
}
This is my C# program:
public class CSTest
{
public static void Main()
{
System.Console.WriteLine("Hello World!");
Foo myFoo = new Foo();
string[] myArr = myFoo.GetStringArray("Pineapple");
}
}
And this is what happens:
$ cl CLIWrapper.cpp /clr /LD /FeCLIWrapper.dll -nologo
cl CLIWrapper.cpp /clr /LD /FeCLIWrapper.dll -nologo
CLIWrapper.cpp
$ csc CSTest.cs /r:CLIWrapper.dll -nologo
csc CSTest.cs /r:CLIWrapper.dll -nologo
$ CSTest
CSTest
Unhandled Exception: System.IO.FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)
at CSTest.Main()
This is what was happening yesterday, the C++/CLI program compiles into a DLL which I can see (with a program like reflector) has my functions in it. The C# file compiles just fine, but the moment I try to run the C# program, a windows error report window pops up, and when I close it the above error message appears.
Anyone have any ideas?
|
|
|
|
|
Shadowsoal wrote: Unhandled Exception: System.IO.FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)
at CSTest.Main()
To understand the problem you should read the /clr[^] switches and it's use. You are using /clr option which will allow both native and managed assemblies. To achieve this side by side assemblies, it has to create a separate manifest file which will have all details about the assemblies used. Regardless of the .dll extension, a manifest file is just a XML file and you can open it in any supported editor to view the contents.
If you goto the C++/CLI program's directory, you will see two files CLIWrapper.dll and CLIWrapper.dll.manifest . The second one contains manifest information and it tells that side by side assemblies are used. Application requires msvcm80.dll when compiled using /clr or /clr:pure thus you can't avoid manifest files when using these compiler switches. This manifest information is not embedded into the executable you are producing and it is the reason for error. When compiling from VS, it does this internally.
When you use csc CSTest.cs /r:CLIWrapper.dll to compile your C# application, it will compile but the manifest information for C++/CLI library is not included. You have to include this after the compilation. mt.exe[^] is the exe which can do this. Once the compilation finishes run the following command
mt -manifest CLIWrapper.dll.manifest -outputresource:CSTest.exe This will set the manifest. Now run the exe and it should work fine.
If clr:/safe is used then manifest files are not required. Your code should work without doing any extra work.
Hope that helps
|
|
|
|
|
It compiles and it runs! Thank you very much navaneeth. My simple test programs compile and run just fine now that I'm using /clr:safe instead of just /clr. Now all I need to do is write a handful of wrapper functions around my old library, and things should be golden.
I'm sure I'll be back here in the relatively near future if I find myself hitting my head against a wall again. You've been a tremendous help, a gentleman and a scholar.
|
|
|
|
|
Shadowsoal wrote: My simple test programs compile and run just fine now that I'm using /clr:safe instead of just /clr. Now all I need to do is write a handful of wrapper functions around my old library
clr:/safe can't compile the application when native classes are involved. It is OK if you have only managed classes. Since you have native classes, go with /clr or /clr:pure .
|
|
|
|
|
After having worked with a handful of other things related to this project, I return to the C++/CLI looking to finish things off, but alas, I run into an issue once again. Hopefully it can be easily resolved.
|
|
|
|
|
|
Hello,
is there any way, that the UnlockBits-Method doesn't release my byte-pointer, when I
created an image from it?
The byte-pointer, that I give to the Bitmapdata Scan0 value, is contains always after the "UnlockBits"-Method an <undefined_value>.
But I have to do further operations on that pointer. Is there a way to keep track of that pointer or am I doing something wrong?
Tanks in advance, cherry
|
|
|
|
|
stop using the pointer after calling UnlockBits, or postpone calling UnlockBits until you're done with the pointer.
FWIW: When passing a data pointer to some native code, I prefer using the GCHandle class.
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Thanks so far,
I describe my problem a little bit more exactly:
As soon as my camera has taken a new picture, I get a BYTE- (or char)-pointer of it. This happens in unmanaged code, but it's no problem
to delegate it to managed.
Now I create my bitmap like that:
myBitmapData = myImage->LockBits(*myRect,WriteOnly,Format8bppIndexed);
myBitmapData->Scan0 = myBytePtr;
myBitmapData->Stride = iImageWidth*iImagePlanes;
myImage->UnlockBits(myBitmapData);
The final call of UnlockBits makes my BYTE pointer to an undefined value, so if this Function is called again (and it has to be called again to define the new Bitmap) without a new Image was taken, the function gets an empty pointer and crashes.
Is there no possibility to keep that pointer?
Or would anyone of you even create that bitmap some other way?
I'm not sure if this method is a good one...
I'd be happy for some hints!
Thanks
|
|
|
|
|
Hi,
1.
whatever pointer operations you want to do to the pixels need to be done in between the LockBits and the UnlockBits.
2.
do you have to have the native code allocate the data buffer? if yes, there is no way around copying all the pixels into the managed image, which is an expensive and unproductive operation. If no, allocating a managed buffer (could be with new Bitmap and LockBits) and passing the pointer to the native world might eliminate the need for a copy operation.
What is the native code you are using?
out of curiosity: what is the make and model of your camera?
Luc Pattyn [Forum Guidelines] [My Articles]
The quality and detail of your question reflects on the effectiveness of the help you are likely to get.
Show formatted code inside PRE tags, and give clear symptoms when describing a problem.
|
|
|
|
|
Also, if you want to keep a pointer to the pixel bits around,
use the Bitmap constructor that takes an IntPtr. If you pass
a pointer to a pre-allocated array, you can use that pointer
until the array is freed, and you don't need to use LockBits to
access it (although in multithread situations you may need to
synchronize access to it).
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Here's an example of what I'm talking about:
public ref class Form1 : public System::Windows::Forms::Form
{
unsigned char *pBitmapBits;
Bitmap ^testBitmap;
public:
Form1(void)
{
InitializeComponent();
pBitmapBits = new unsigned char[120 * 120 * 3];
for (int x = 0; x < (120*120*3); x += 3)
{
pBitmapBits[x+0] = 0;
pBitmapBits[x+1] = 0;
pBitmapBits[x+2] = 255;
}
testBitmap = gcnew Bitmap(120, 120, 120*3, PixelFormat::Format24bppRgb, IntPtr(pBitmapBits));
}
...
private: System::Void testButton_Click(System::Object^ sender, System::EventArgs^ e)
{
for (int x = 120*3*40; x < (120*3*80); x += 3)
{
pBitmapBits[x+0] = 255;
pBitmapBits[x+1] = 0;
pBitmapBits[x+2] = 255;
}
Graphics ^g = this->CreateGraphics();
g->DrawImage(testBitmap, 10, 10);
}
};
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks a lot you people!
I'm very happy of always getting such good answers.
Respect, for me you are number #1 in the web!
On Topic:
I'll test your way to create bitmap tomorrow, it's late in europe right now
It looks good, but I remember some problems as I wanted to get it done like that.
The cam I use is a monochrome Leutron PicSight P52M-USB, and the only way I get monochrome
Bitmaps done is to assign the Format8bppIndexed - which further made some problems in resizing,
so that I have to work with a temp-Image. I'm not happy with that, but I didn't get a better way yet.
I'd be more happy with not having to work with marshaling between managed and unmanaged. But my company
has "old" native interfaces (one for graphic, one for cam), which must not be changed. So I had to delegate
all function (the way I got it done is also from codeproject) - but it seems to me as a not very stable solution,
to call a managed GUI in creating a thread from native and so on...
Maybe someone wonders about an odd comment, please let me know.
I may be on the wrong way somewhere...
Thanks again for your time, bye!
|
|
|
|
|
Hi,
I have a COM component developed in VC++ which provides hundreds of interfaces.
Many people use this component in their managed code using interop DLLs.
1. I just want to know if this is the right way of doing it?
2. Does it make sense providing a .NET assembly for them to do development in the .NET environment?
3. Is there any advantage if we use .NET assemblies instead of using COM via interop DLLs?
4. Is there any good article that explains how to convert unmanaged COM into managed assembly using managed C++?
Thanks in advance
cheers
Varghese Paul
|
|
|
|
|
I don't know that there is a definitive "right" way to do that. It likely depends on what services your COM components are providing and what the use model is etc. That said you should take a look at how Microsoft provides managed assemblies for using the Office Object Models. They are called Primary Interop Assemblies[^], and how they are different (better) than the standard Interop Generated .NET code.
|
|
|
|
|
Hi!
I have a windows forms control of the following type with 4 Labels in it:
*****************************
*label1......*label2........*
*****************************
*label3......*label4........*
*****************************
Each oft the labels has to fill exactly one quarter of the whole form, because the background color
of the labels is changed at runtime and it doesn't look good if the color fills just the back oft the text.
Labelproperty autosize seems like a simple solution, but if i set it, the label is always just as big as the text is.
Without autosize, it looks not bad, but I don't get it to split in the center.
It looks like that:
*******************************
*label1...............*label2 *
*label3...............*label4 *
*******************************
The rightern labels don't grow with the control, the remain on rightern side in their usual size.
Anyone an idea?
Thanks, cherry
|
|
|
|
|
I would set the Anchor property of labels 1 and 3 to Left, and set labels 2 and 4 to Right (this keeps the left/right edge of the label a fixed distance from the corresponding edge of the form. Then implement on OnResize event for your form, and set the Width of labels 1 and 3, and the Left of labels 2 and 4, like so:
void OnResize(Object^ sender, EventArgs^ e)
{
label1->Width = Width / 2;
label3->Width = Width / 2;
label2->Left = Width / 2;
label4->Left = Width / 2;
}
You may need to add a slight offset to one of these if the labels look like they overlap at all, but this should get you started. You can also do something similar to this for making your labels fill the form vertically.
Dybs
|
|
|
|
|
Thanks Dybs, that might help - I just thought it could be made more nicely.
Something like autosizing with setting the anchors to all sides...
Thanks and bye!
|
|
|
|