How to convert a string array element to string? - visual-studio-2010

I have a string array
public: array<String ^> ^ sss;
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
array<String ^> ^ sss = gcnew array<String ^>(3);
sss[0]="asdasd";
sss[1]="s115ss";
sss[2]="s115ss";
}
I need to show the 1st element into a textbox.
I used
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
textBox2->Text = sss[0];
}
Vc++ gave System.NullReferenceException. Why? And how to fix it?
The error:
An unhandled exception of type 'System.NullReferenceException' occurred in test000.exe
Additional information: Object reference not set to an instance of an object.

Your code shouldn't compile, unless you also have a field called sss. If that's the case, you want to set the value of that field in your constructor, not of some unrelated local variable with the same name:
array<String ^> ^ sss;
public:
Form1(void)
{
InitializeComponent();
sss = gcnew array<String ^>(3);
sss[0]="asdasd";
sss[1]="s115ss";
sss[2]="s115ss";
}

Related

C++/CLI marshaling .NET delegate to native delegate

I am trying to pass a delegate with managed parameters to native code to be invoked. My code below runs ok, but the string output is garbage.
Native Class
Header
#pragma once
typedef void (* SegmentCreatedDelegate)(char** arg);
public class SampleClass
{
public:
SampleClass(void);
~SampleClass(void);
void DoWork(SegmentCreatedDelegate callback);
};
Code
SampleClass::SampleClass(void)
{
}
SampleClass::~SampleClass(void)
{
}
void SampleClass::DoWork(SegmentCreatedDelegate callback)
{
for(int x = 0; x< 10; x++)
{
char* myStr2 = "newsegment!";
callback(&myStr2);
}
}
Managed Class
Header
#pragma once
public ref class SampleClassNet
{
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet(void);
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
Code
SampleClassNet::SampleClassNet(void)
{
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback)
{
SampleClass* nativeClass = new SampleClass();
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(segmentCreatedCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
System::GC::KeepAlive(segmentCreatedCallback);
}
This code runs fine with the follow c#.
var sampleClass = new SampleClassNet();
sampleClass.DoWork((Console.WriteLine));
Except I get the following output, instead of the expected 10 entries of "newsegment!".
(ÇÆX
(ÇÆX☺
(ÇÆX☻
(ÇÆX♥
(ÇÆX♦
(ÇÆX♣
(ÇÆX♠
(ÇÆX
(ÇÆX
(ÇÆX
Not exactly "newsegment!", but I am not sure why the marshaling is not working. Maybe I need I need some kind of "MarshalAs" attribute so that the System::String knows that I have 8-bit chars?
As mentioned in the comments, you should convert the char** to a String^. (Btw, why pass char**, not char*? String has a constructer taking char*, which might simplify things a lot.)
I haven't tried the following, but you might give it a try:
public ref class SampleClassNet {
private:
delegate void SegmentCreatedDelegateNative(char** str);
SegmentCreatedDelegateNet^ managedCallback;
SegmentCreatedDelegateNative^ nativeCallback;
void printString(char** string);
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet();
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
SampleClassNet::SampleClassNet() {
nativeCallback = printString;
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback) {
SampleClass* nativeClass = new SampleClass();
managedCallback = segmentCreatedCallback;
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(nativeCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
}
void SampleClassNet::printString(char** string) {
if (this->managedCallback != nullptr) {
String^ str = gcnew String(*string);
managedCallback(str);
}
}
The basic idea is to use another delegate, SegmentCreatedDelegateNative, handed to the native class, and to call the actual managed delegate from the function associated with the wrapper.

Can't add action to buttons in Visual Studio C++ using Windows Forms

Hello Dear Community of SO!
I have a following problem - I wrote a simple add_record function using structures (here is my main file):
// Exercise1.cpp : main project file.
#include "stdafx.h"
#include "Form1.h"
using namespace Exercise1;
typedef struct student {
char *name;
int index;
double avg;
student *next;
student *prev;
} stud;
student *first = 0;
[STAThreadAttribute]
void add_record(student **first, char *name, int index, double avg){
student *new_stud = new student;
if (*first!=0) (*first)->prev = new_stud;
new_stud->name = name;
new_stud->avg = avg;
new_stud->index = index;
new_stud->next = *first;
new_stud->prev = 0;
*first = new_stud;
}
However, I can't put this add record function into button action (with predefined data, just for testing purposes)
Code for Form1.h:
#pragma once
namespace Exercise1 {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// Summary for Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button1;
protected:
private: System::Windows::Forms::Button^ button2;
//all remaining buttons here - irrelevant
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
}
#pragma endregion
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
String ^ i = "working";
textBox1->Text = i;
}
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
String ^ g = "test";
if(add_record(student **first, testname, 23, 3.5))
textBox1->Text = g;
}
};
}
How to fix that part with record adding?
I get a following error:
1>d:\visual studio 2010 express\projects\exercise1\exercise1\Form1.h(176): error C2065: 'student' : undeclared identifier
1>d:\visual studio 2010 express\projects\exercise1\exercise1\Form1.h(176): error C2065: 'first' : undeclared identifier
1>d:\visual studio 2010 express\projects\exercise1\exercise1\Form1.h(176): error C2065: 'testname' : undeclared identifier
1>d:\visual studio 2010 express\projects\exercise1\exercise1\Form1.h(176): error C3861: 'add_record': identifier not found
I guess it's something connected with variable declaration but I don't know where to put that in order for it to work..
Thanks in advance
From your code snippet.
There is no type defined as student - the struct is typdef to stud - this explains why the compiler yells at you it doesn't recognize the student **first argument type in the add_record method declaration.
using namespace Exercise1;
typedef struct student {
char *name;
int index;
double avg;
student *next;
student *prev;
} stud; // <<<-------------------- should it be "} student;"?
student *first = 0;
[STAThreadAttribute]
void add_record(student **first, char *name, int index, double avg){
student *new_stud = new student;
if (*first!=0) (*first)->prev = new_stud;
new_stud->name = name;
new_stud->avg = avg;
...

How to extend a listbox in VC++

I tried to extend a listbox by adding a couple functions. I get an error ( error C2144: syntax error : 'Extended_ListBox' should be preceded by ':'). Would anyone please teach me how to fix it? I went to the line which VC++ said there was the error, but I had no clue why the constructor had an error.
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Collections;
using namespace System::Collections::Generic;
#include <stdio.h>
#include <stdlib.h>
#using <mscorlib.dll>
public ref class Extended_ListBox: public ListBox{
public Extended_ListBox(array<String ^> ^ textLineArray, int counter){
textLineArray_store = gcnew array<String ^>(counter);
for (int i=0; i<counter; i++){
this->Items->Add(textLineArray[i]);
textLineArray_store[i] = textLineArray[i];
}
this->FormattingEnabled = true;
this->Size = System::Drawing::Size(380, 225);
this->TabIndex = 0;
this->SelectedIndexChanged += gcnew System::EventHandler(this, &Extended_ListBox::listBox1_SelectedIndexChanged);
}
public Extended_ListBox(){
this->FormattingEnabled = true;
this->Size = System::Drawing::Size(380, 225);
this->TabIndex = 0;
this->SelectedIndexChanged += gcnew System::EventHandler(this, &Extended_ListBox::listBox1_SelectedIndexChanged);
}
private: System::Void listBox1_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {
int index=this->SelectedIndex;
tempstring = textLineArray_store[index];
}
private: array<String ^> ^ textLineArray_store;
private: String ^tempstring;
public: String ^GetSelectedString(){
return tempstring;
}
public: void ListBox_Update(array <String ^> ^ textLineArray, int counter){
textLineArray_store = gcnew array<String ^>(counter);
for (int i=0; i<counter; i++){
this->Items->Add(textLineArray[i]);
textLineArray_store[i] = textLineArray[i];
}
}
};
In C++/CLI, you specify the access modifier (public, private, etc.) differently than in, say, C# or Java.
Instead, you just write one line (note the colon, which is required):
public:
and all the following members are public. So insert that line before your constructors and remove the public keyword before the constructors. Like that:
public ref class Extended_ListBox: public ListBox{
public:
Extended_ListBox(array<String ^> ^ textLineArray, int counter){
// constructor code
}
Extended_ListBox(){
// default constructor code
}
// other public members
// ...
private:
// private members
// ...
}
Similar to the members below the constructors in your current example, except that you don't have to explicitly restate public: or private: if the next member has the same visibility.

How to hand a file path (text box value) to a file reading function in c++?

I created a file chooser for windows it returns me a chosen file path. I want to read the given file but I do not know how to pass the file path to the right function.
File Form1.h I have a button action and inside of it I can get openFileDialog1->FileName but I do not know how to pass this variable to a readFile() function inside of main.cpp file.
I created a method to return the path:
System::String^ filePath;
....
private: System::String^ getPath() { return filePath; }
Here is the file-pickers code:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Stream^ myStream;
OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;
openFileDialog1->InitialDirectory = "c:\\";
openFileDialog1->Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog1->FilterIndex = 2;
openFileDialog1->RestoreDirectory = true;
if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK ){
if ( (myStream = openFileDialog1->OpenFile()) != nullptr ){
// Insert code to read the stream here.
textBox1->Text = openFileDialog1->FileName; //text box displays the chosen path
myStream->Close();
}
}
}
The variable is set on button click:
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
filePath = textBox1->Text;
}
How to call the return methods in my main.cpp:
#include "stdafx.h"
#include "Form1.h"
using namespace main;
using namespace std;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
System::String^ p1 = /*Something missing her?*/getPath1(); //I am guessing it should look like this...
return 0;
}
Put the file name in a public property (public field, if it's what you prefer) in the Form1 class (or make your getPath() method public) then:
Form1^ form = gcnew Form1();
Application::Run(form);
String^ p1 = form->FileName;

call a delegate from click event using C++/CLI

In C#, We can call a new function from button click with arguments like this,
////My function
public static void Method1(int x)
{
Console.WriteLine("Method 1");
}
and set this function on click event of a command button like this,
button1.Click += delegate { mydelegate with argument };
Eg:
delegate void Procedure( int x);
public partial class Window1 : Window
{
public Window1()
{
Procedure pProcedure = new Procedure(Method1);
InitializeComponent();
button1.Click += delegate { pProcedure(10); };
}
public static void Method1(int x)
{
Console.WriteLine("Method 1");
}
}
Now when we click on the button1, then the function "Method1" will be invoke.
How can I do the same using C++/CLI?
I need to find the added delegate from the click event and need to remove. How can i do this?
If you're asking about how to use anonymous delegates in C++/CLI, then the answer is you can't. In C++/CLI, delegates must be bound to a named function.
To accomplish what inline anonymous delegates actually do in C#, you can use the concept of a 'functor' or function object. The following C++/CLI sample illustrates how to create a function object and "bind" it to a specific value and then show how to use it as an event subscriber.
using namespace System;
// Sample class with one event 'Started'
public ref class Widget
{
public:
Widget()
{
}
event EventHandler ^ Started;
void Start()
{
Console::WriteLine("Starting...");
Started(this, EventArgs::Empty);
}
};
// Declare 'functor' class to capture state
private ref class Functor
{
public:
Functor(int input)
: input_(input)
{
}
// This is what we will use as the handler method
void Handler(Object ^ sender, EventArgs ^ e)
{
Console::WriteLine(L"Invoked with input {0}.", input_);
}
private:
int input_;
};
// Entry point
int wmain(int argc, wchar_t ** argv)
{
// Create a functor to capture value '10'
Functor ^ f = gcnew Functor(10);
Widget ^ widget = gcnew Widget();
// Subscribe to event using functor's handler
// (note that we bind to the instance 'f' here)
EventHandler ^ handler = gcnew EventHandler(f, &Functor::Handler);
widget->Started += handler;
// Should print "Invoked with input 10."
widget->Start();
// Remove the handler
widget->Started -= handler;
// Should not print anything extra now
widget->Start();
return 0;
}
Thank you for your help.
With your help I can solve my problem.
The solution is like this,
//FirstWindow.h
#pragma once
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Controls;
ref class Functor;
ref class FirstWindow : Window
{
Canvas^ maincanvas;
Button^ addbutton1;
Button^ addbutton2;
Functor^ pFunctor;
public:
FirstWindow(void);
void InitControls(void);
void MyFunction( int x, int y );
};
//FirstWindow.cpp
#include "FirstWindow.h"
#include "Functor.h"
FirstWindow::FirstWindow(void)
{
Title = "First Avalon App";
Width = 400;
Height = 400;
ResizeMode = System::Windows::ResizeMode::NoResize;
InitControls();
}
void FirstWindow::InitControls(void)
{
addbutton1 = gcnew Button();
addbutton1->Width = 80;
addbutton1->Height = 25;
addbutton1->Content = "Add";
pFunctor = gcnew Functor(this, 10, 20);
addbutton1->Click += gcnew RoutedEventHandler( pFunctor, &Functor::Handler);
Canvas::SetTop(addbutton1, 45);
Canvas::SetLeft(addbutton1, 200);
pFunctor = gcnew Functor(this, 100, 200);
addbutton2 = gcnew Button();
addbutton2->Width = 80;
addbutton2->Height = 25;
addbutton2->Content = "Add";
addbutton2->Click += gcnew RoutedEventHandler(pFunctor, &Functor::Handler);
Canvas::SetTop(addbutton2, 85);
Canvas::SetLeft(addbutton2, 200);
maincanvas = gcnew Canvas();
maincanvas->Children->Add(addbutton1);
maincanvas->Children->Add(addbutton2);
Content = maincanvas;
}
void FirstWindow::MyFunction( int x, int y )
{
MessageBox::Show("This function is call by Button Click with values " + x.ToString() + " , " + y.ToString() );
}
//Functor.h
#pragma once
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Controls;
ref class FirstWindow;
private ref class Functor
{
public:
Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg);
// This is what we will use as the handler method
void Handler(Object ^ sender, RoutedEventArgs ^ e);
private:
int m_pFirstArg;
int m_pSecArg;
FirstWindow^ m_pFirstWindow;
};
//Functor.cpp
#include "Functor.h"
#include "FirstWindow.h"
Functor::Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg) : m_pFirstWindow( pFirstWindow ), m_pFirstArg(pFirstArg), m_pSecArg( pSecArg )
{
}
void Functor::Handler(Object ^ sender, RoutedEventArgs ^ e)
{
if ( m_pFirstWindow )
m_pFirstWindow->MyFunction(m_pFirstArg, m_pSecArg );
}
Now when we click on button one, then the application call the function "MyFunction" with value 10,20 and when we click on button 2 then the same function "MyFunction" with value 100,200.
Thank you for your help.
Sabeesh

Resources