ist es möglich aus nem string
string text = "hallo";
einen IntPtr zu machen?
schicke grad mit Messages zwischen zwei prog. hin und her jedoch hab ich bisher nur ints hin und her geschickt!
Was ist ein IntPtr eigentlich genau ? hat das Int am anfang des Wortes was mit dem int Datentyp zu tun?
hoffe das das nicht ne zu noobhafte frage ist aber eine antwort würde mir sehr helfen!
Ein IntPtr ist ein Pointer auf ein Objekt..... und wird nur gebraucht um Objekte für unmanaged Code bereit zu stellen, oder um unmanaged Objekte in managed Objekte zu verwandeln.
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
danke für die flotte antwort blos muss ich zugeben das mir das etwas zu hoch war 😉
public int ModemCall(string tel)
{
signal = -1;
sollResult = Communicate.mw_Commands.notSet;
Message msg = Message.Create(ziel,
(int)Communicate.mw_Commands.modemss,(IntPtr)tel,IntPtr.Zero);
MessageWindow.SendMessage(ref msg);
if (sollResult == Communicate.mw_Commands.modemss)
{
return signal;
}
else
return -1;
}
dabei bekomm ich nun die Fehlermeldung :
Cannot convert type 'string' to 'System.IntPtr'
es gibt dann nat. ein entsprechendes prog das die message auch empfängt!
Wie bereits geschrieben wurde, wird IntPtr nur zu einem Zweck genutzt, nämlich Speicheradressen (Pointer) zu speichern.
Speicheradressen gibt es in .NET sonst nicht, es handelt sich bei .NET-Programmen um sogenannten mananged Code, der keinen Zugriff auf den Speicher erlaubt. Um aber mit Windows kommunizieren zu können, welches selbst nicht in .NET geschrieben ist (unmanaged Code), muss man eben doch manchmal mit Pointern hantieren. Dazu gibt IntPtr.
Um einen String in ein unmanagend Speicher zu kopieren und eine IntPtr zu erhalten, gibt es mehrere Funktionen. Du wirst brauchen:
using System.Runtime.InteropServices;
...
IntPtr pointerToUnmanagedString = Marshal.StringToHGlobalUni(myManagedString); // gibts auch für Ansi)
Das zurückwandeln geht via
string myManagedString = Marshal.PtrToStringUni(myPointer);
Aber aufpassen: bei Hinwandeln (string -> IntPtr) wird Speicher allokiert, den du explizit mit
Marshal.FreeHGlobal(pointer);
freigeben musst.
nun gut aber Microsoft.WindowsCE.Forms.Message.Create fordert IntPtr!
Was kann ich da dagegen machen?
wie lös ich mein Problem?
wie schick ich nun nen string mit? ne telefonnummer passt nicht in ein int 😉
thx für die flotten antworten!
Ah... CF, sowas musst du IMMER dazu sagen. Da gibt es diese Funktionen nicht. Besorge dir das OpenNETCF-Framework, da gibt es unter MarshalEx diese Funktionen, oder kopiere dir den Sourcecode raus und verwende nur den.
sorry 🙁
hab ich mir auch gedacht als ich den letzten post geschrieben hab!
na mal sehn ob ich ne codepassage finde!
Hier der Code:
public static IntPtr StringToHGlobalUni(string s)
{
if(s == null)
return IntPtr.Zero;
int i = (s.Length + 1) * System.Text.UnicodeEncoding.CharSize;
IntPtr ptr = LocalAlloc(LPTR,(uint)i);
byte[] data = Encoding.Unicode.GetBytes(s);
Marshal.Copy(data, 0, ptr, data.Length);
return ptr;
}
Wie du siehst, gibts da aber noch LocalAlloc, was es wieder nur im OpenNETCF gibt. Am besten du verwendest die ganze Bibliothek, sonst musst du vermutlich noch nen Rattenschanz an Klassen und Typdefinitionen aus dem Framework auslösen.
FreeHGlobal() und PtrToStringUni() gibts auch unter dem CF in der Marshal-Klasse.
FreeHGlobal() und PtrToStringUni() gibts auch unter dem CF in der Marshal-Klasse.
wofür ich FreeHGlobal() brauch weis ich nicht so recht 😉
hab jetzt mal die umwandlung von string zu pointer vollzogen:
aus string "+42763874637" wurde der pointer "23378"
wenn ich aber jetzt das ganze mit PtrToStringUni zurückwandeln will kommt entweder gar nix oder blödsinn!
mann muss dabei nämlich int ofs und int len angeben und ich weis nicht recht was er da wissen will 🤔
hab schon einige ints ausprobiert aber wie gesagt kein zufriedenstellendes ergebniss 😉
ofs (Offeset) ist der Start, len die Zahl der Zeichen. Aber es gibt auch eine Überladung nur mit String, der kopiert alles um.
Ich hab aber den Eindruck, dass du dich nochmal mit den Grundlagen von .NET in Sachen managed und unmanaged Code beschäftigen solltest. Offenbar hast du bisher noch nicht mit unmanaged Sprachen (C/C++) gearbeitet, wenn dir die Bedeutung von Speicherfreigabe nicht klar ist.
ja da hast du sicher recht das ich noch nichts mit unmanaged code zu tun hatte!
tja die überlagerung nur mit string hab ich auch schon ausprobiert aber da kommt auch nichts brauchbares raus!
ja ok Speicherfreigabe sagt mir eigentlich schon ein wenig was blos was ich damit hier anfangen soll weis ich nicht wirklich 😭
naja ich denke fast das ich das abschreiben kann!
Wenn du deinen managed string zu einem InPtr "konvertierst", ist das keine Cast, sondern es wird wirklich ein Stück Speicher ausserhalb von .NET angelegt un der String umkopiert damit eine "normale" Windows-Anwendung darauf zugreifen kann. In .NET wird Speicher automatisch freigegeben, wenn er nicht mehr benutzt wird. Nicht-.NET-Speicher muss dagegen explizit freigegeben werden wenn er nicht mehr benutzt wird. Nachdem du also den umgewandelten string (als IntPtr) in deine Funktion gesteckt hast und diese zurückkehrt, dann musst du den Speicher mit der genannten Funktion wieder freigeben.
ok ist mir klar!
ich hab den string dieser wird so einer speicheradresse zugewiesen:
string ser = mainForm.ModemSerial();
IntPtr test = MarshalEx.StringToHGlobalUni(ser);
msgAnswer.LParam = (IntPtr)(test);
und so von dem andren programm abgeholt:
modserial = MarshalEx.PtrToStringAuto(msg.LParam);
MarshalEx.FreeHGlobal(msg.LParam);
die speicheradresse kommt auch korrekt an hab die zahl überprüft aber das abholen funkt anscheinend nicht!
hab übrigens schon PtrToStringAuto,Ansi,uni probiert genauso auch beim senden
Den Code hier hab ich mal von einer MS-Seite, sieht genauso auis wie vorgeschlagen....
//allocate temporary native buffer
IntPtr stringptr = MarshalEx.StringToHGlobalUni(url + '\0');
//send message to native control
Win32Window.SendMessage(ChildHandle,(int)DTM.NAVIGATE, 0, (int)stringptr);
//free native memory
MarshalEx.FreeHGlobal(stringptr);
Der Int-Cast des IntPtr ist übrigens sinnlos, daran liegt es auch nicht.
@svenson: ich danke dir für deine hilfsbereitschaft! gibst nicht auf! erlebt man selten!
ich werde dieses problem vorerst auf eis legen da ich mir das prob leider nciht erklären kann! wenn unser chef-programmierer wieder vom urlaub zurück ist werd ich ihn mal fragen mal sehn was der dazu sagt! der hat ja den vorteil meinen ganzen code zu begutachten!
falss noch jemanden was einfällt darf er das trotzdem noch posten vielleicht geht mir ja selber übers wochenende ein licht auf!
Nur so als tipp:
Du scheinst da ja irgendetwas mit einem Modem zu machen, oder?
In der von Svenson am Anfang erwähnten opennetcf.org Bibliotek
gibt es schon fertige klassen zur kommunikation per modem oder "blauzeh".
Hallo FZelle,
du meinst bestimmt 'blauzahn'. 🙂
herbivore
Wollte nur mal schaun, ob jemand überhaupt weis was ich meine 😉
@FZelle: das ist ja gut und schön das es die bibliothek gibt 😉 jedoch ist nicht die kommunikation mit dem modem mein problem! das hab ich schon erledigt! das macht ein seperates programm ! nur ist es so das das separate programm nur die aufgaben die es bekommt erledigt und dann eine antwort an das Aufgabenstellende Programm zurücksendet! dieses Senden mach ich über SendMessage!
jedoch kann man so nir IntPtr schicken! das funkt bei ints tadellos blos wenn ich ne zahl in dem format hab: 545687833452145668745
komm ich mit ints nicht weit =)
darum will ichs als string weiterleiten! und da wurde die MarshalEx in einsatz gebracht nur bringt das nicht das ergebnis!
also das problem ist nicht kommunikation prog-modem sondern prog-prog!
Danke trotzdem für den Versuch!
Hallo!
Ich möchte mich hier einklinken, wenns recht ist?
Allerdings ist mein Problem etwas anders gelagert, ich sehe aber in bin in fähigen Händen 😎
Diese Methode kommt aus einer DLL:
I16 __stdcall DO_ReadPort (U16 CardNumber, U16 Port, U32 *Value);
Ich muss nun im Aufruf referenzieren:
DO_ReadPort(cardID, DOPort, &DORbVal);
Ich habe einfache Typen bereits erfolgreich übersetzt, lediglich bei den Pointern komme ich auf keine Lösung!
Codesample:
// PCI-7230 registrieren
[DllImport("PCI-Dask.dll", SetLastError = true, CharSet = CharSet.Auto)]
public unsafe static extern short Register_Card
(
ushort PCI_7230,
ushort wCardNumber
);
--> klappt
// DO lesen
[DllImport("PCI-Dask.dll", SetLastError = true, CharSet = CharSet.Auto)]
public unsafe static extern short DO_ReadPort //(cardID, DOPort, DOValue)
(
short cardID, // U16
ushort DOPort, // U16
uint *DORbValue // U32
);
--> klappt nicht!
Hoffe du/ihr könnt mir weiterhelfen!
regards,
Michael
Programmierung mit PHP, ASP.net, C# and more...
Hallo brainbug,
was heißt klappt nicht? Compilerfehler? Exception? Anderes? Bitte genaue Meldung. Danke!
herbivore
Hi!
Sorry, ich dachte es wäre klar, was dann passiert😉
\Form1.cs(265): Sie können nur die Adresse von einem ungebundenen Ausdruck innerhalb einer festen Anweisungsinitialisierung abrufen
und
\Form1.cs(265): Zeiger können nur in einem nicht sicheren Kontext verwendet werden
Ich verzweifle gr
Grüße,
Michael
Programmierung mit PHP, ASP.net, C# and more...
Hallo brainbug,
hm, wie hätte das klar sein sollen? Na egal. Kommen da keine Fehlernummern?
Der zweite Fehler ist jedenfalls CS0214: Siehe http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cscomp/html/vcerrCompilerErrorSC0214.asp
Hi!
Danke für den Tip, ich bin weiter gekommen.
Grüße,
Michael
Programmierung mit PHP, ASP.net, C# and more...
wollte nur mal mitteilen das ich mein problem anders gelöst hab!
gibt 2 methoden:
den string in ne datei schreiben und vom andren prog wieder auslesen oder den string in die registry schreiben und von dort wieder auslesen!
@ brainbug: kein problem das du den thread weiterverwendest leider kann ich dir nicht weiterhelfen!
Hallo!
Habe, denke ich, das gleiche Problem wie du damals hattest. Wenn ich kompilieren möchte erscheint bei mir folegende Fehlermeldung:
...AOSystem.cs(455): Sie können nur die Adresse von einem ungebundenen Ausdruck innerhalb einer festen Anweisungsinitialisierung abrufen
Wie hast du das damals gelöst?
PS: Ich nutze ein C-dll und im speziellen folgende fkt:
[DllImport("AnySIMServerDLL", EntryPoint="AoGetObjID"), System.Security.SuppressUnmanagedCodeSecurity]
unsafe private static extern uint AoGetObjID(uint layout_id,byte *name );
Der Fehler wird in diesem Block erzeugt:
unsafe public static uint GetObjID(uint layout_id, string name )
{
byte[] str = StrToByteArray(name);
byte *strpntr;
strpntr = &str[0];
return AoGetObjID(layout_id, strpntr );
}
Vielen Dank im Voraus!
Philipp
Warum nutzt du denn unsafe Code? Geht doch auch völlig ohne!?
[DllImport("AnySIMServerDLL", EntryPoint="AoGetObjID")]
private static extern uint AoGetObjID(uint layout_id,string name );
Ggf. noch den Unmanaged Type für den Namen angeben, da es sich hier ja um ANSI handelt.
Die Fehlermeldung kann du glaub ich mit fixed auf dem Byte-Array wegbekommen.
Geht das denn? Ich meine statt byte * einfach string verwenden?
Das hatte ich vorher schonmal gemacht, aber dann hat mir die fkt nichts mehr zurückgegeben. Habe leider auch nicht die möglichkeit in die dll zu schauen, kenne die implementierung der fkt also nicht.
Bei einfachen Geschichten wie Strings geht das vollautomatisch. Auch bei einfachen Strukturen oder Arrays ist das kein Thema. Dieser Automatismus heisst in .NET Marshalling. Das funktioniert sowohl in Hin- als auch in Rückrichtung. Es gibt allerdings schon Fälle, wo der Automatismus versagt (Rückrichtung ist tendenziell kritischer) und man Hand anlegen muss.
In diesem Fall musst du beim DLLImport nur noch
CharSet = CharSet.Ansi angeben (hinter EntryPoint).
So weiss .NET, dass string auf char* abgebildet wird.
Auf Pointer und all den Kram kannst du dann verzichten und dein Code läuft ist voll managed, was wegen der CodeSecurity ein Vorteil ist.
Generell ist die Verwendung von unsafe Code in dem Zusammenhang niemals notwendig. Es gibt eine Marshal-Klasse (System.Interop), die alles bereit hält, um unmanaged Speicher auszulesen oder zu füllen (und sogar zu allokieren und freizugeben). Alles ohne Pointer.
Original von svenson
Generell ist die Verwendung von unsafe Code in dem Zusammenhang niemals notwendig. Es gibt eine Marshal-Klasse (System.Interop), die alles bereit hält, um unmanaged Speicher auszulesen oder zu füllen (und sogar zu allokieren und freizugeben). Alles ohne Pointer.
Ich habe sogar TWAIN (Scanner-Schnittstelle) ohne unsafe implementiert.... und dort muss ich teilweise sogar per offset aus unmanaged-Memory lesen um den Type des Objektes zu erfahren bevor ich das objekt in managed zurückmarshallen kann.
Einzig wenn es hoch - performant sein muss und extrem viel "pointer-arithmetik" drin ist musst du auf unsafe switchen. .. (also z.B: unmanaged-Memory Megabyteweise byte für byte auslesen.. und nach jedem Read den neuen Leseort relativ zum Pointer berechnen)
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Genauso ist es. Unsafe code ist nur deswegen schneller, weil Sicherheitsprüfungen des Frameworks wegfallen. Die kosten beim Übergang zu unmanaged Code viel Zeit um eben sicherzustellen, dass der unmanaged Speicher oder Code in keinen Fall die managed Anwendung kompromitiert und somit "unsicher" macht.
Bei einem einfachen Funktionsaufruf fällt das nicht ins Gewicht, aber wenn tatsächlich millionenfach ein solcher Aufruf erfolgen muss, oder ein Callback in den managed Code so oft gemacht wird, dann kann das richtig teuer sein und um Faktoren langsamer als eine unsafe-Lösung. Das sind aber Ausnahmen. Mir ist bisher nur ein einziger Fall vorgekommen, wo ich unsafe aus Performancegründen einsetzen musste. Also erstmal vernachlässigen.
Danke!
So vereinfacht sich für mich das arbeiten mit der bibliothek selbstverständlich erheblich...