Laden...

StringToIntPtr

Erstellt von Nomak vor 18 Jahren Letzter Beitrag vor 18 Jahren 14.304 Views
N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren
StringToIntPtr

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!

4.221 Beiträge seit 2005
vor 18 Jahren

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...

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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!

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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!

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

sorry 🙁
hab ich mir auch gedacht als ich den letzten post geschrieben hab!

na mal sehn ob ich ne codepassage finde!

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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 😉

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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!

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

@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!

F
10.010 Beiträge seit 2004
vor 18 Jahren

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".

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo FZelle,

du meinst bestimmt 'blauzahn'. 🙂

herbivore

F
10.010 Beiträge seit 2004
vor 18 Jahren

Wollte nur mal schaun, ob jemand überhaupt weis was ich meine 😉

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

@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!

B
5 Beiträge seit 2005
vor 18 Jahren
Pointer mit c#

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...

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo brainbug,

was heißt klappt nicht? Compilerfehler? Exception? Anderes? Bitte genaue Meldung. Danke!

herbivore

B
5 Beiträge seit 2005
vor 18 Jahren
Pointer mit C#

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...

49.485 Beiträge seit 2005
vor 18 Jahren

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

B
5 Beiträge seit 2005
vor 18 Jahren

Hi!

Danke für den Tip, ich bin weiter gekommen.

Grüße,

Michael

Programmierung mit PHP, ASP.net, C# and more...

N
Nomak Themenstarter:in
40 Beiträge seit 2005
vor 18 Jahren

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!

C
3 Beiträge seit 2005
vor 18 Jahren

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

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

C
3 Beiträge seit 2005
vor 18 Jahren

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.

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

4.221 Beiträge seit 2005
vor 18 Jahren

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...

S
8.746 Beiträge seit 2005
vor 18 Jahren

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.

C
3 Beiträge seit 2005
vor 18 Jahren

Danke!

So vereinfacht sich für mich das arbeiten mit der bibliothek selbstverständlich erheblich...