Ich versuche ein Programm von C++ Builder auf Microsoft Visual Studio zu
überschreiben.
Das läuft in C++ Builder ohne Fehler:
VarBesch(&i,z,0,VarInfo,"[Form->MinimumPixelE→Text]", (DWORD)Form1->MinimumPixelE,EDITEXT);
Im Visual Studio Microsoft:
VarBesch(&i, z, 0, VarInfo, "[MinimumPixelE->Text]",(DWORD)this->MinimumPixelE->Text, EDITEXT);
bringt Fehler:
Ungültige Typkonvertierung.
"Typumwandlung": "System::String ^" kann nicht in "DWORD" konvertiert werden.
Weitere Test haben das ergeben:
System::Windows::Forms::CheckBox *gg; //← Fehler!
gg = this→KreisZu;
E1986: ein normaler Zeiger auf eine C++/CLI-Verweisklasse oder -Schnittstellenklasse ist nicht zulässig.
Also: C++/CLI erlaubt „keine normale Zeiger auf eine
C++/CLI-Verweisklasse oder -Schnittstellenklasse“ Gibts es
auch „nicht normalen Zeiger“... ? Das Bedeutet dass
Visual Studio keine Zeiger auf eine C++/CLI-Verweisklasse
erlaubt!
Ich habe eine Frage an Microsoft Entwickler:
Passiert das, dass anders technisch nicht möglich wäre.
Oder absichtlich wurde die Begrenzung eingeführt mit der
Begründung:„sicheres Programmieren".
Veganen essen kein Fleisch und das geht mich nicht an. Aber
manche Veganen wollen anderen Menschen das Essen von Fleisch
(auch Milchprodukten…) verbieten!
C++ Builder hat keine solchen Begrenzungen und nach vielen
Jahren ist weiter beliebt und effektiv! In 80. und 90.
Jahren 20. Jahrhundert kamen Schulabsolventen In Betrieben
mit Pascal kenntnissen. Professoren in Schulen haben nur
Pascal gelernt… In Betrieben mussten Sie aber in „C“
programmieren. Pointer Akrobatik war in Softentwicklung
notwendig. Pascal hat mit „C“ verloren!
Wie sind die Parameter von "VarBesch(...)" deklariert?
Von welchem Type ist "Form1->MinimumPixelE"?
Von welchem Type ist "this->MinimumPixelE->Text"?
Das it nicht wichtig. Das habe im Grrif.
Das ist wichtig:
Weitere Test haben das ergeben:
System::Windows::Forms::CheckBox *gg; //← Fehler!
gg = this→KreisZu;
E1986: ein normaler Zeiger auf eine C++/CLI-Verweisklasse oder
Schnittstellenklasse ist nicht zulässig.
Ich versuche ein Programm von C++ Builder auf Microsoft Visual Studio zu
überschreiben.
Das läuft in C++ Builder ohne Fehler:
VarBesch(&i,z,0,VarInfo,"[Form->MinimumPixelE→Text]",
(DWORD)Form1->MinimumPixelE,EDITEXT);
System::Windows::Forms::CheckBox *gg; //← Fehler!
gg = this→KreisZu;
E1986: ein normaler Zeiger auf eine C++/CLI-Verweisklasse oder
-Schnittstellenklasse ist nicht zulässig.
Also: C++/CLI erlaubt „keine normale Zeiger auf eine
C++/CLI-Verweisklasse oder -Schnittstellenklasse“ Gibts es
auch „nicht normalen Zeiger“... ?
Ja, nennt sich sharedPointer (smartpointer) und der enthält den "normalen" Pointer bzw eine Referenz auf den String und kann ihn löschen wenn der Referenzzähler auf 0 ist).
-> https://en.cppreference.com/w/cpp/memory/shared_ptr
Seit C++11, freilich: std::shared_ptr<>, std::weak_ptr<>, std::unique_ptr<>. Letztere sind vom Footrprint her das Pendant zu Raw-Pointern.
[C++/CLI-Verweisklasse]
Die sind, soweit ich das überblicke, ein Brückenschlag zwischen C++ und den gemanagten Ressourcen von dot-NET. Dass die zu diesem Zweck auf C++-Seite auch mit gemanagten Zeigern betan werden wollen, ist irgendwie einleuchtend.
Aber manche Veganen wollen anderen Menschen das Essen von Fleisch
(auch Milchprodukten…) verbieten!
[MSVC-C++/CLI] ... wer in ein veganes Restaurant geht, kann sich schwerlich darüber aufregen, dass dort der Wunsch nach Fleisch auf Ablehnung stößt. Letzteres gibt es dann im Steakhouse.
Aber manche Veganen wollen anderen Menschen das Essen von Fleisch
(auch Milchprodukten…) verbieten!
[MSVC-C++/CLI] ... wer in ein veganes Restaurant geht, kann sich
schwerlich darüber aufregen, dass dort der Wunsch nach Fleisch auf
Ablehnung stößt. Letzteres gibt es dann im Steakhouse.
Mit anderen Worten: Wenn dir die Einschränkungen, die dir das .net-Zeugs mit "C++/CLI" auferlegt, nicht magst, dann nimm halt echtes C++.
Ja, nennt sich sharedPointer (smartpointer) und der enthält den
"normalen" Pointer bzw eine Referenz auf den String und kann ihn löschen
wenn der Referenzzähler auf 0 ist).
-> https://en.cppreference.com/w/cpp/memory/shared_ptr
Zitat (Auszug...)vom pdf-Buch von Prof.Richard Kaiser:
"int* p=0; // p zeigt nicht auf einen reservierten
// Speicherbereich
Bei einem Handle muss man dafür nullptr verwenden:
int^ h=nullptr; // h zeigt auf keinen Wert"
Das bringt schon keinen Fehler:
System::Windows::Forms::CheckBox^ x = nullptr;
Also einen nullptr kann ich definieren. Was kann man damit
weiter machen...dann... sehe ich noch...
Würdest Du den C++-Compiler verwenden, hättest Du das Problem nicht. C++/CLI ist /kein/ C++, sondern eine Microsoft-Perversion für das .Net-Geraffel.
Visual Studio kommt aber auch mit einem richtigen, nativen C++-Compiler, und der ist a) standardkonform, b) ziemlich aktuell und kann c) echte C++-Programme übersetzen.
Würdest Du den C++-Compiler verwenden, hättest Du das Problem
nicht. C++/CLI ist /kein/ C++, sondern eine Microsoft-Perversion für das
.Net-Geraffel.
Visual Studio kommt aber auch mit einem richtigen, nativen C++-Compiler,
und der ist a) standardkonform, b) ziemlich aktuell und kann c) echte
C++-Programme übersetzen.
Dann gibt's aber kein Windows Forms, und die MFC ist nicht in der kostenlosen Version drin.
Was spricht gegen natives C#? Geschwindigkeit? Da könnte man den kritischen Code immer noch in C++ schreiben und als DLL einbinden.
Dann gibt's aber kein Windows Forms, und die MFC ist nicht in der
kostenlosen Version drin.
Dann nimmt man halt was anderes; wxWidgets ist in der Struktur der MFC ähnlich und hat den Vorteil, sogar auf anderen Betriebssystemen nutzbar zu sein. Keine Abhängigkeit von einer nur von Microsoft unterstützten Sprache und/oder Entwicklungsumgebung.
Warum eigentlich musste der C++-Builder verlassen und das Projekt "portiert" werden?
using namespace System;
using namespace System::Windows::Forms;
Zitaten:
Namespaces werden verwendet, um Code in logischen Gruppen zu organisieren und Namenskonflikte zu vermeiden, die insbesondere dann auftreten können, wenn die Codebasis mehrere Bibliotheken enthält. Alle Bezeichner im Gültigkeitsbereich des Namespaces sind ohne Qualifizierung füreinander sichtbar.
Die Variante mit using namespace sollte üblicherweise nur innerhalb von Funktionen genutzt werden, da bei Verwendung im globalen Namensraum das ganze Konzept der Namensräume obsolet wird. In gedruckten Büchern wird es gern global verwendet, da dies etwas Platz spart und der in solchen Büchern knapp ist.
"using namespace std" braucht man, um das Namespace-Konzept von C++ ad-absurdum zu führen. Namespaces dienen dazu, Namensbereiche zu trennen. Mit diesem unsäglichen "using namespace" wird genau das wieder aufgehoben. Oder anders ausgedrückt: Laßt es einfach weg und schreibt std::string, std::cout, std::endl usw.
using namespace ? könnte jemand das logisch erklären...
Zitat:
Da nicht auszuschließen ist, dass zwei unabhängig voneinander entstandene Quelltexte die gleichen Namen verwenden, wurde in C++ der Namensraum eingeführt. Damit können Deklarationen und Definitionen unter einem Namen zusammengefasst und gegen andere Namen abgegrenzt werden.
Das klingt vernünftig:
macht all das, was im Namensraum enthalten ist und durch Header bereits eingebunden wurde, im aktuellen Namensraum bekannt. ( Funktionen, Typen, ... )
In meinem Entwurf von Forms sehe ich keine #include
von diesem System...:
namespace $safeprojectname$ {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
Das müsste auf einer anderen Stelle (für mich nicht sichtbar passieren...)
Das namespace ist eine Art von Erinnerung...?
using namespace ? könnte jemand das logisch erklären...
Ein Zweck von "using namespace" ist u.a., den Bestand an qualifiziertem (oder sogar zertifiziertem) Legacy-Code, bei denen die Funktionen der Standard-Library oder anderen Bibliothenken noch nicht durch Namensräume getrennt gewesen waren, ohne umfangreiche Änderungen mit modernem C++ weiterbenutzen zu können,
Dass man in neu geschriebenen oder refaktorierten Code-Zeilen mit solchen Mechanismen sehr sparsam umgehen sollte, versteht sich wohl von selbst.
"using namespace std" braucht man, um das Namespace-Konzept von C++
ad-absurdum zu führen.
Das halte ich für maßlos übertrieben. Ja, man sollte es vermeiden. Aber Namensräume, die nicht per "using" eingebunden werden, bleiben ja weiterhin gekapselt. Nix "ad-absurdum".
ein Beispiel vom pdf-Buch von Prof.Richard Kaiser:
In C++ kann man die zusammengehörigen Deklarationen dagegen jeweils
in einen eigenen Namensbereich aufnehmen und die Elemente
dann innerhalb des Namensbereichs unter ihrem angemessenen Namen
ansprechen:
namespace Kunden { // Ein sehr einfaches Beispiel
struct Adresse {
// Elemente, die für Kunden notwendig sind
};
const int Max=1000;
Adresse Adressen[Max];
void show(TextBox^ tb)
{ // ...
}
} // end of namespace Kunden
namespace Mitarbeiter {
struct Adresse {
// andere Elemente wie bei Kunden
};
const int Max=5000;
Adresse Adressen[Max];
void show(TextBox^ tb)
{
}
} // end of namespace Mitarbeiter
Außerhalb eines Namensbereichs kann man seine Elemente mit den
Namen des Namensbereichs, dem Bereichsoperator und den Namen des
Elements ansprechen:
Auf diese Weise lassen sich auch Namenskonflikte zwischen verschiedenen Bibliotheken (z.B. von verschiedenen Herstellern) vermeiden
Die C++-Standardbibliothek fasst alle ihre Elemente in den Namensbereich
std. Wenn man diesen Namen nicht für einen eigenen Namensbereich
verwendet (was man nie tun sollte), bekommt man mit den
Namen der Standardbibliothek nie Namenskonflikte.
Deswegen ja mein Einwurf, dann könne man gleich C# nehmen, das macht dann viele Dinge einfacher. Das managed c++ muss man halt wollen und nimmt man eigentlich nur, wenn man unbedingt muss. Z.B. um eine .net DLL in ein bestehendes C++ Programm einzubinden. Ohne Not würde ich das nicht nehmen, dann lieber alles C++ oder alles C#. Wenn es nur um das GUI geht, wurden ja schon Alternativen genannt.
Deswegen ja mein Einwurf, dann könne man gleich C# nehmen
Ich kenne C# nicht. Bei meinem ersten Einsatz in Visual Studio
habe ich schon bemerkt dass Beispiele in C# waren näher in
Programmierung Logik an meinen Erkenntnissen von C++ als C++/Cli.
Das muss ich wirklich überlegen....
Na ja, so schlimm ist das C++/CLI doch nicht. Es setzt aber halt ein zweites Objektmodell dem nativen C++-Objektmodell obendrüber - nämlich das der .net-Objekte. Vorteile davon sind unter anderem halt ähnliche wie anno dazumals für Objective-C++: man kann bestehenden C++-Code nehmen, einen .net-Wrapper verpassen und ziemlich schnell integrieren. In C# müssteste für jeden nativen C/C++-Funktionsaufruf sonst entweder mit COM-INterfaces arbeiten oder eben P/Invoke-Wrapper basteln - die bisweilen auch recht lustige und abgefahrene Funktionssignaturen im Resultat haben können, pinvoke.net hin oder her.
Im Endeffekt ist einfach ne 2. Abstraktion für Objekte dazugekommen:
new (C++) vs. gcnew (.net)
Pointer (* in C++) vs. Handles (^ in .net)
Referenzen (& in C++) vs. Ref-Handles (% in .net)
Dazu gibts 4 zusätzliche Typen von struct/class-Kombinationen:
ref class (.net Klasse, default private, GC)
ref struct (.net Klasse, default alles public, GC)
value class (.net Datatype struct, default private)
value struct (.net Datatype struct, default public)
Die structs in .net sind halt die Teile, die nur bei Konstruktion initialisiert werden können.
Als Adapter-Layer für die wechselseitige Interaktion zwischen C++ und .net ist das C++/CLI gar nicht soo schlecht. Man muss dann aber auch mit ähnlichen Dingen rechnen, wie eben bei .net auch: Assemblyreferenzen setzen, GlobalassemblyCache, Nugets usw. usf.
Ich bin für C.Auch emotional! C gibst Programmierung Freiheit.
Das Visual Studio muss ich besser kennenlernen.
Bei neuen Sachen um Zeit zu sparen bewegt sich oft man wie
ich das nenne: intuitiv.
Das läuft ohne Fehler:
Sender:
VarBesch(&i, z, 0, VarInfo, "[MinimumPixelE→Text]",
MinimumPixelE->Text, EDITEXT);
Bingo!:
short VarBesch(unsigned short* i, unsigned short z, char MemReservieren,
VarInfo_typ* VarInfo, char* Name,
System::Windows::Forms::TextBox^ a, char Art)
{ ...
VarInfo[*i].TextBoxPointer = &a;
(*VarInfo[*i].TextBoxPointer)->Text = " DD";
...
}
Ich kann die einzelnen Elemente von Forms auch beschreiben. Info
über Pointer in VarInfo[];
Das ist das, was ich wollte!. Bei Borland Builder könte ich
alle Pointer durch cast in DWORD umwandeln. Jetzt brauche ich
für jede Art von Pointer eine Funktion. Aber das ist
kein Problem!
Das ist kein C und auch kein C++, sondern die von MS verwürgste
Pseudo-C++-Variante "Managed C++" bzw. "C++/CLI".
Von Freiheit ist das mit Abstand am weitestens entfernt.
Nein, das ist Quatsch.
Das war so ziemlich das Beste, was man machen könnte, um diesen unsäglichen Schrotthaufen C++ den Zugang zu in einer prinzipiell viel sichereren Sprache verfaßten GUI zu ermöglichen.
Das Konzept ist logisch: GUI = extrem hohe Komplexität = viel Möglichkeiten für Programmierfehler. Sehr viele davon können allein durch das sehr viel sicherere Sprachkonzept der der .net-Sprachen gefangen werden. Dazu kommt dann noch, dass GUI-Entwicklung in einer .net-Umgebung sehr viel komfortabler ist.
Ich persönlich nutze den Kram allerdings auch nicht. Nur (zähneknirschend) den umgekehrten Weg. Also ausgehend von .net und dann Import und Wrapping dieser immanent unsicheren C/C++ -Scheiße. Allein am Aufwand, der dazu oft nötig ist, kann man mühelos erkennen, wie schlecht dieser Code oft ist, allein schon vom Design her...
Wenn man zum Programmieren zu doof ist, dann muss man sich so ausdrücken. Ist man das nicht, braucht man auch keine Programmiersprache, die einem beim Aufs-Töpfchen-Gehen an die Hand nimmt und nett Bubu zu einem sagt.
Wenn man zum Programmieren zu doof ist, dann muss man sich so
ausdrücken. Ist man das nicht, braucht man auch keine
Programmiersprache, die einem beim Aufs-Töpfchen-Gehen an die Hand nimmt
und nett Bubu zu einem sagt.
Tja, so sagte der C/C++ -"Programmierer" und verfasste die nächste Sicherheitslücke...
Man braucht sich doch nur die Statistik der Sicherheitslücken anschauen, um es ganz klar zu erkennen: die übergroße Mehrheit davon resultiert ALLEIN aus dem schwachen bis nicht vorhandenen Schutz vor Programmierfehlern in C/C++.
Dabei muß man dann noch etwas differenzieren. C++ hätte theoretisch zumindest das Potential gehabt, deutlich sicherer zu werden als C. Hat bloß nicht geklappt, weil eben auch C-Code "adaptiert" werden sollte. Und damit alle Schweinereien, die C ungestraft erlaubt. Das war das vorgeburtliche AUS für die Sicherheit von C++.
Dazu kommt dann noch die "UB"-Thematik. Wenn etwas "UB" ist, dann hat der Compiler zuverlässig zu warnen. Alles andere ist systematisch falsch. Menschen machen nunmal Fehler. Ein Compiler/eine Sprache muss diesem Sachverhalt Rechnung tragen, sonst taugt er/sie nix.
Zumal bei einer Sprache wie C++, deren Dokumentation sich über TAUSENDE Seiten erstreckt.
Dabei muß man dann noch etwas differenzieren. C++ hätte theoretisch
zumindest das Potential gehabt, deutlich sicherer zu werden als C. Hat
bloß nicht geklappt, weil eben auch C-Code "adaptiert" werden sollte.
Und damit alle Schweinereien, die C ungestraft erlaubt. Das war das
vorgeburtliche AUS für die Sicherheit von C++.
Hätte nicht, denn C++ war von Anfang als Erweiterung von C gedacht. Also hat man den ganzen Kram aus C adaptiert. Von C++ kommt man auch nicht mehr weg. In 40 Jahren C++ ist eine Abhängigkeit entstanden. Haufenweise Code Bases sind in C++ geschrieben, rewrites - zu teuer. Stattdessen wird C++ regelmäßig geupdated auf Verlangen der Industrie. Der Nachwuchs ist auch nicht wirklich da für C++ - zu kompliziert, zu umfangreich. Lieber Python lernen und den nächsten KI-Wichs zusammenkopieren.
Tja, so sagte der C/C++ -"Programmierer" und verfasste die nächste
Sicherheitslücke...
Wären C und C++ so schlecht, wie Du glaubst, dann gäbe es deutlich mehr Sicherheitslücken. Die Sprachen legen nur halt etwas höhere Messlatten an die Programmierer, wenn man da billige Deppen frisch von der Uni ranlässt, dann kann dabei halt Murks rauskommen.
Millionen von stabil und zuverlässig laufenden in C und C++ entwickelten Anwendungen beweisen, daß es anders geht als Du Dir zusammenreimst.
Wieso liest man entsprechendes Gekreische von Dir eigentlich nicht über Assembler?
Wären C und C++ so schlecht, wie Du glaubst, dann gäbe es deutlich mehr
Sicherheitslücken.
Unsinn. Die existierenden und immer wieder neu aufpoppenden reichen wohl völlig aus, um meine Einschätzung eindrucksvoll zu beweisen.
Zumal: bei genauerer Betrachtung würden sich wohl auch noch mehr finden lassen...
Millionen von stabil und zuverlässig laufenden in C und C++ entwickelten
Anwendungen beweisen, daß es anders geht als Du Dir zusammenreimst.
Welche? Nenne auch nur eine einzige!
Wieso liest man entsprechendes Gekreische von Dir eigentlich nicht über
Assembler?
Weil reiner Assembler natürlich konzeptionell vollkommen unsicher ist. Aber: da C Assembler-Teile als integralen Bestandteil enthält, erbt es natürlich auch noch deren Unsicherheit! Und C++ wiederum erbt das von C.
Sprich: Wenn man was Sicheres will, sind Assembler, C und C++ tabu.
Wenn man hingegen was Schnelles und Effizientes will (und Sicherheitsaspekte eher eine untergeordnete Rolle spielen oder Probleme durch die Umgebung (OS) gefangen werden können), ist Assembler das Mittel der Wahl.
Was man eigentlich niemals wirklich braucht, ist: C und C++. Es sei denn, man will (meistens eher: muss) vorhandenen Code verwenden, der in diesen Sprachen geschrieben wurde. Leider ist das aber der Normalfall. Mit den bekannten Folgen bezüglich der Sicherheit...
Hach, es ist immer wieder schön, Deine Beiträge zu lesen, die von gründlicher Ahnungslosigkeit zeugen. Wärest Du Papst, Du würdest ähnlich detailliert Stellungen aus dem Kamasutra kritisieren ...
Ich experimentiere weiter... Ich wollte gerne in der Visual Studio
klassische Elemente von C++ verwenden. Das brachte eine Menge
von Fehlermeldungen:
#include <string.h>
#include <stdlib.h>
#include <iostream>
namespace std;
...
{
string s=“ggg“;
….
Also ohne: „namespace std;“ aber explizit (Beispiel…) mit dem präfix
std:: geht das!
Weil "namespace std;" keinen Sinn ergibt. Du meinstest vermutlich "using namespace std;", was man allerdings in der Regel vermeiden sollte, weil es dem Sinn von Namespaces widerspricht. Das wurde hier eigentlich alles schon erklärt.
Der Compiler sagt aber nicht einfach nur "Fehler", sondern sagt dir,
was der Fehler
Es sind so viele Fehler! Und das sind auch verschiedene Fehler, die
auf die #include Standard Files zeigen. Das muss man verstehen,
dass Visual Studio nicht alles von C++ akzeptiert. Nur manche
Sachen die man mit dem Präfix std:: gekennzeichnet.
Das ist kein C und auch kein C++, sondern die von MS verwürgste
Pseudo-C++-Variante "Managed C++" bzw. "C++/CLI".
Von Freiheit ist das mit Abstand am weitestens entfernt.
Na ja, ECMA-Standard isses ja, gibt halt nur wenig freie Compiler, die es können - müsste ja wohl quasi irgendwie über Mono laufen, wenn es denn gehen sollte.
Prinzipiell geb ich dir recht: GUI-Elemente würde ich auch nicht unbedingt in C++/CLI bauen wollen, da gibts bessere .net-Sprachen für sowas.
Zum Zweck der Adaptierung von nativem Code in managed Code, isses ok und sogar teilweise eine gute Alternative, weil du eben auch C/C++-spezifische Sachen wie Bitfields oder templates damit ansteuern kannst. Solche gemangelten Sachen über p/invoke zu machen fände ich noch viel schlimmer. Man kann zwar sagen: gut, dann design halt ne gescheite C-Export-API für die DLL, die solchen Mist gar nicht erst zulässt. Dafür sieht dann dein p/invoke-Wrapper auf C#-Seite auch wieder schrottig aus und ist meistens so ein häßliches Konstrukt aus einer statischen Klasse - die aber trotzdem dann über das von C aus exportierte void*-Handle irgendwo noch Zustand hat. D.h. man frickelt dann 2 Wrapper-Layer in C# um eine popelige DLL objektorientiert anzusteuern... (eigentliche Klasse + statische p/invoke-Klasse drunter)
Grosser Nachteil sehe ich allerdings für C++/CLI auch, sobald sowas wie CMake ins Spiel kommt - mit dem MSVC hat man zwar wohl theoretisch ne Chance und .net Nugets/Referenzen gehen wohl auch mittlerweile, aber so richtig geil ist das glaub ich noch nicht.
Der Compiler sagt aber nicht einfach nur "Fehler", sondern sagt dir,
was der Fehler
Es sind so viele Fehler!
Es ist sinnvoll, mit dem ersten anzufangen, denn die anderen sind meist Folgefehler, weil der Compiler den Faden verloren hat, oder sie dienen der Erläuterung des vorherigen Fehlers, indem sie z.B. auf eine für den Fehler relevante Stelle im Code verweisen.
Und das sind auch verschiedene Fehler, die auf die #include Standard
Files zeigen.
Dann sind diese hoffentlich Tel der oben genannten Erläuterung, denn in den Standard-Headern sollten ja keine Fehler sein. Alternativ kann das auch durch eigene Header kommen, die vor den Standard-Headern eingebunden wurden.
Das muss man verstehen, dass Visual Studio nicht alles von C++
akzeptiert.
Das kommt darauf an, wie du es nutzt. Wenn es auf echtes C++ eingestellt ist, sollte es das schon auch akzeptieren. Hast du ein Beispiel, was da nicht geht?
Es sind so viele Fehler! Und das sind auch verschiedene Fehler, die
auf die #include Standard Files zeigen. Das muss man verstehen,
dass Visual Studio nicht alles von C++ akzeptiert. Nur manche
Sachen die man mit dem Präfix std:: gekennzeichnet.
Na ja, die <string.h> sollte eigentlich ja auch was anderes als die <string>-Header sein. Im Normalfall sollte nach üblicher C++-Notation die <string.h> die <cstring> sein (die solches Zeug wie strcmp, strcat, strtok, usw. hält), während <string> und <wstring> halt eben die C++-STL-strings in beiden Geschmacksrichtungen verfügbar macht. Lustig wirds bei deinem obigen C++/CLI-Beispiel, wo System::String und glaube System::SecureString noch dazukommen kann.
U.a. mal noch folgender Tipp: sowas lieber nicht machen:
Soll heißen: nicht native Klassen .net Membervariablen halten lassen, besser umgekehrt. Begründung: man hat oft keine Möglichkeit, aus den .net Klassen native Informationen rauszuziehen. Zusätzlich noch dazu kommend: die weniger günstige Variante von oben hat potentiell den Nachteil, dass du MemoryLeaks beim Aufruf durch .net kriegen kannst, wenn das .net den !Foo-Finalizer aufruft und der nicht gescheit implementiert ist. Das Problem mit diesem Disposing haste aber in C# wohl auch, C++/CLI hin oder her - ist scheinbar ne übliche .net-Interop-Problematik.
Um sowas wie ein Pointer zu bekommen muesstest du das pinnen, macht aber auf ein Objekt wie System::String kein Sinn.
Wozu meinst du soll ein Zeiger gut sein? Was fuer ein Problem hast du mit der .NET referenz?
Hat es einen speziellen Grund warum Du C++/CLI verwendest?
Falls du keinen alten C++ code in der WinForms GUI verwenden musst -> kipp das Ganze und wechsle auf C#.
Na ja, die <string.h> sollte eigentlich ja auch was anderes als die
<string>-Header sein. Im Normalfall sollte nach üblicher C++-Notation
die <string.h> die <cstring> sein
Jein. string.h wäre nicht im namespace std gekapselt und bei cstring schon.
Man sollte cstring bevorzugen sonst gibts schnell böse Überraschungen.
Aber warum kein normaler C++ String? string.h ist die C Bibliothek für strings :D
Wie kann ich Pointer auf Pointer i Visual Studio definieren:
1
>//Pointer auf System::String
2
>//Das funktioniert ohne Fehler
3
>System::String^SysStringPoint;
4
>SysStringPoint=MinimumPixelAbstandE->Text;
5
>
Ja, SysStringPoint ist initial ein nicht initialisiertes Handle. Quasi eine null-Zuweisung in .net. Durch die Zuweisung drunter übergibst du dem Handle SysStringPoint das Handle von MinimumPixelAbstandE->Text, was seinerseits ein .net-Objekt zu sein scheint (wenn dieser Code bei dir so kompiliert - ich kenn ja den Datentyp von MinimuPixelAbstandE nicht, nehme aber an, das ist eine Art Textfeld).
1
>//Pointer auf Pointer von System::String
2
>System::String^*SysStringPPoint;
3
>SysStringPPoint=MinimumPixelAbstandE->Text;
4
>//Diese Zuweisung wird
5
>//nicht akzeptiert.Was muss ich hier ändern
6
>//(Zusatz für Wandlung...)
7
>
Das wird nicht funktionieren - niemals ein .net-Handle und einen nativen Pointer gleichsetzen. Du kannst keinen Pointer (*) auf ein vom .net-Framework verwaltetes Objekt bekommen, weil Pointer unter der Kontrolle der C/C++-Runtime sind (z.B. MSVCRT), .net-Gedönse aber halt eben im CommonLanguageInterface drinne sind. D.h. soviel wie: es wird aus dem .net-Objekt eine Intermediate-Language (IL) wie bei Java erzeugt und von einem .net-'VirtualMachine' ausgeführt, welche die IL eben selber in nativen Code übersetzt. Und weil du da auch nicht auch nicht drumrum kommst, dafür gibst ja C++/CLI - damit du beide Welten verbinden kannst.
Was du ja eigentlich bezwecken scheinst, ist es ja, den Text aus dem Steuerelement auszulesen. Und dafür musste halt mit Mitteln von C++/CLI aus dem .net-Objekt System::String das raus-'marshallen'. Beim Visuellen Studio sollte es wohl so ähnlich ausschauen:
Ich teste Programmierung in C++/CLI mit Forms. Jetzt mache
ich einen Versuch mein altes Programm, das ich unter
C++ Builder geschrieben habe, in Visual Studio
mit Forms zu umschreiben. Am Anfang alle Steuerelemente
von Form (CheckBox ComboBox, TextBox…) sind in einem Array
von diesem Typ angemeldet:
Abspeicherung von dem Inhalt von diesen Steuerelementen in
einem File läuft das in einer for-Schleife. Genauso ist es
beim Laden aus einem File.Im C++ Builder brauchte ich sogar
nur DWORD Pointer, weil ich könnte alle Pointertypen von
Steuerelementen in DWORD durch cast umwandeln.
Ich kenne mich absolut nicht mit .NET. Also ^ ist kein
Pointer sondern nur Handle? Könnte man dieses Handle (das
ist auch nur eine Zahl...? ) nicht abspeichern
z.B. in meiner VarIno_typ Structur? Und das später
abzurufen? Vielleicht geht das auch anders...
Genauso ist es
beim Laden aus einem File.Im C++ Builder brauchte ich sogar
nur DWORD Pointer, weil ich könnte alle Pointertypen von
Steuerelementen in DWORD durch cast umwandeln.
Warum sollte man das machen? Das ist grauenvoll. Es hat schon seinen Grund, warum es Pointertypen gibt. Abgesehen davon reicht - wie schon gesagt wurde - auf einer 64-Bit-Plattform ein DWORD nicht aus, um einen Zeiger zu speichern.
Ich kenne mich absolut nicht mit .NET. Also ^ ist kein
Pointer sondern nur Handle? Könnte man dieses Handle (das
ist auch nur eine Zahl...? ) nicht abspeichern
z.B. in meiner VarIno_typ Structur? Und das später
abzurufen? Vielleicht geht das auch anders...
Das weiß jeder. Die Aussage bringt nichts zur Lösung.
Ich habe schon eine Idee im Kopf, wie ich das lösen kann...
Mit Fehler muss man sich arrangieren...
Am Anfang alle Steuerelemente
von Form (CheckBox ComboBox, TextBox…) sind in einem Array
von diesem Typ angemeldet:
Wenn du das willst, dann musst du das in ein ref class/struct packen und in einen CLR/.NET container ablegen. Aber wozu soll man das wollen?
Ich kenne mich absolut nicht mit .NET. Also ^ ist kein
Pointer sondern nur Handle? Könnte man dieses Handle (das
ist auch nur eine Zahl...? ) nicht abspeichern
z.B. in meiner VarIno_typ Structur? Und das später
abzurufen? Vielleicht geht das auch anders...
Die moeglichkeit besteht mit GCHandle.Alloc() und GCHandle.ToIntPtr().
Das gibt dir ein Zeiger (ein IntPtr, kein DWORD, IntPtr.ToPointer gibt dir ein native Zeiger) auf ein beliebiges .NET Objekt. mittels GCHandle.FromIntPtr() kommst du vom Zeiger wieder zum .NET Objekt. Ob du damit Gluecklich wirst?
Mein Tip an dich:
Willst du bei C++ bleiben dann schau dir QT an.
Gefaellt dir WinForms, wechsle zu C#
Scheust du dich nicht von einer steilen Lernkurve, dann C# mit WPF oder Avalonia
Was du dir auf jeden Fall anschauen solltes ist 'data binding'. Das koenenen alle genannten GUI frameworks. Ueber Steuerelemente zu iterieren und befuellen macht man eigentlich nicht mehr.
Das frage ich mich im Bezug auf die ganzen dubiosen Dinge, die er hier versucht, schon die ganze Zeit. Dazu sagt er aber nichts. Das ist ungefähr so, als ob einer fragt, wie man am geschicktesten mit dem Kopf ein Loch in die Wand schlägt.
Ich teste Programmierung in C++/CLI mit Forms. Jetzt mache
ich einen Versuch mein altes Programm, das ich unter
C++ Builder geschrieben habe,
Du wechselst also die Programmiersprache, dessen musst Du Dir sehr deutlich bewusst sein.
Der "C++ Builder" verwendete echtes C++, "C++/CLI" ist kein C++, sondern eine Microsoft-Speziallösung, um optisch ähnliches wie C++ auf den .Net-Unterbau draufzuflanschen.
Meine Übersetzung von Borland Builder in Microsoft Visual
Studio von Microsoft macht Fortschritte. Mein altes Borlands
Projekt ist hier: Beitrag "PCB von BMP drucken"
MyForm mit allen Steuerelementen ist schon fertig. Als erste
habe ich die Abspeicherung und Laden von Daten (Parameter)
von Steuerelementen (TextBox, ComboBox, CheckBox) in Angriff
genommen. Nach dem Start vom Programm werden alle Steuerelemente
mit den Initialisierungswerten vorbesetzt:
1
Breite->Text="3.05";
2
...
3
RundungsModusVertikal->SelectedIndex=2;
4
...
5
Dreh90Grad->Checked=1;
Danach werden Informationen von allen Steuerelementen über eine
Funktion in VarInfo_typ* VarInfo eingespeichert:
Na ja, lass doch einfach den * und den & weg und schon geht's.
Warum? Aktuell deklarierst du die Variable als vom Datentyp Pointer-auf-.net-Handle. Wie oben schon mal geschrieben ist das halt nicht so sonderlich große Idee, weil eben .net das eine (verwaltet übers .net-Framework) und C++-Code halt ne andere Sportart ist (nativ übersetzt).
Wenn du unbedingt deine Steuerelemente in ne Klasse packen willst, dann kannste deinen VarInfo_Typ halt so ändern. Btw. typedefs für structs ist in C++ eigentlich nicht unbedingt nötig, du kannst den Namen auch hinter's 'struct' schreiben (und das typedef weglassen).
structSteuerelemente/* immer noch ungeeigneter Name, aber besser als oben das */
2
{
3
char*Name=nullptr;
4
DWORDPointer=0;
5
System::Windows::Forms::TextBox^TextBoxPointer;
6
System::Windows::Forms::CheckBox^CheckBoxPointer;
7
System::Windows::Forms::ComboBox^ComboBoxPointer;
8
charArt='\0';
9
};
Ist nicht unbedingt direkt jetzt 'schön' weil's ne normale struct ist und keine .net-ref-struct, sollte aber gehen. Die Initialisierung deiner Steuerelemente (TextBoxPointer, usw.) machste wie oben geschrieben ohne & und *.
Meine Übersetzung von Borland Builder in Microsoft Visual
Studio von Microsoft macht Fortschritte. Mein altes Borlands
Projekt ist hier: Beitrag "PCB von BMP drucken"
MyForm mit allen Steuerelementen ist schon fertig.
Wuerde sagen: Hat sich gelohnt, 50% Groessenersparnis mit der neuen Technologie...
Wobei, mich wundert jetzt auch nicht mehr die Wahl von WinForms mit C++/CLI.
Bist Du zufrieden damit? Moechtest Du ein beispiel wie man das moderner gestalten koennte?
Um das fehlendes Zugriff über Pointer auf Steuerelemente
umzugehen, habe ich eine Funktion mit switch/case mit der ich Korrespondiere von meinen for schleifen zum save und load von
Daten. Manche Teile von Meinem Programm unter Borland Builder
sind fast gleich und nach kleiner Anpassung direkt
zum Übernehmen. Beispiel:
Ich lese das ganze File in Puffer und arbeite nur mit Bytes.
Alle Variablen werden mit ASCII Namen (in Klammer [])
abgespeichert. Beim lesen von File wird nur nach diesen
Namen gesucht.Mit diesem Wirrwarr von tausenden Klassen will
ich nichts zu tun haben. Die Sache ist zu weit gelaufen.
Niemand wagt sich sagen dass der König nackt ist.
Hallo B.P.,
darf ich Dich noch mal fragen wieso Du Dir diese Mühe machst ?
Es gibt die C++ Builder Community edition for free. Du darfst halt kein Geld damit verdienen bzw Max 5000$.
Hast Du schon mal probiert Deine Projekte/Projekt dort mit der neuen IDE zu laden?
Pointer auf Felder (TextBox, ComboBox, CheckBox…) könnte ich
in einer Structur speichern.Bei dem Wiederverwenden von
Pointer (im Debug)kommt jedoch zum Fehler. Sehe das Bild.
Hat jemand einen Rat...
Das ist so unter C++ Builder von Borland gegangen. Mit Visual
Studio geht das so nicht.Im Visual Studio bekommt man
(intuitives Denken…)nur eine Kopie von Pointer auf einen
Formsfeld auf dem Stack.Zwischenspeicherung vom Pointer auf
Formsfelder in einer Funktion bringt nichts, weil nach dem
Verlassen der Funktion Stack ändert sich.
Im „for“ Block werden alle Formsfelder angemeldet. Nach erstem
Durchlauf wird maximale Anzahl von Felder berechnet (==i) und
wird Speicher allokiert für VarInfo. Danach werden alle notwendige
Daten in der Funktion VarBesch()in die VarInfo geschrieben.
Jedes Feld bekam jetzt auch eine Nummer(ErsatzPointer...)
In der Funktion VarBesch() sind die Pointer auf Formsfelder
aktuell und ich Kommuniziere mit diesem „for“ mit Befehlen
zum Lesen oder Beschreiben von Formsfelder. Bei einem neuen
Formsfeld zum Save oder Load wird nur eine neue Meldungszeile
eingeführt.Das alles wäre auch mit „case“ möglich, aber mit viel Handarbeit.
Das ist so unter C++ Builder von Borland gegangen. Mit Visual
Studio geht das so nicht.
Doch, das geht selbstverständlich auch "mit Visual Studio" so. Auf genau diese Art und Weise.
Wenn man es schafft, den C++-Compiler zu verwenden, und nicht auf die Glitzer-Vorgaukel-Welt des .Net-Geraffels 'reinzufallen, das eine Pseudoprogrammiersprache mit dem irreführenden Namen "C++/CLI" anbietet.
Mit Visual Studio kann man natives C++ verwenden, und das verhält sich wie natives C++. "WinForms" aber braucht den .Net-Unterbau, und kann daher nicht mit C++ genutzt werden.
Wie oft muss man das hier eigentlich noch wiederkäuen?