Laden...

C-Funktion

Erstellt von Joerg vor 18 Jahren Letzter Beitrag vor 18 Jahren 6.788 Views
J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren
C-Funktion

Hallo,
ich muss die nachstehende C-Funktionen mittels DLLAufruf in C# benutzen.

long Msg_GPSPositionGet(void *pMsg, double &dLat, double &dLon, double &dHeading, double &dSpeed, long &UTCDate, long &UTCTime, long &lAltitude, double &dPDOM, short &sFixMode, short &sSatelliteCount);

Kann mir jemand helfen bei der Umsetzung?

[DllImport("Alksdk_dotNet.dll",EntryPoint="Msg_GPSPositionGet",CallingConvention=CallingConvention.Winapi)]
public static extern int Msg_GPSPositionGet(???????);

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren
 
[DllImport("Alksdk_dotNet.dll")]
public static extern long Msg_GPSPositionGet(IntPtr msg, ref double dLat, ref double dLon, ref double dHeading, ref double dSpeed, ref long UTCDate, ref long UTCTime, ref long lAltitude, ref double dPDOM, ref short sFixMode, ref short sSatelliteCount);

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Joerg,

ansonsten http://www.pinvoke.net

herbivore

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo,
Danke für die schnelle Hilfe.Eine Frage noch.

Was muss ich bei (IntPtr msg,.......) übergeben?
Laut C-Funktion ist das doch ein Zeiger auf eine Funktion.,oder?

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

IntPtr ist die Entsprechung von "void*". Das ist einfach ein untypisierter Zeiger.

Bei dir ist das der Zeiger auf eine Message-Struktur (vermutlich ein NMEA-Datenblock), die du von irgendwoher bekommst. Offenbar puzzelt die Funktion dann die einzelnen Werte aus der Struktur.

Bei C/C++ ist das anhand der Typen manchmal schwer zu erkennen. Es wäre auch denkbar, dass "void*" eine leer Struktur ist, die erst von der Funktion gefüllt wird. Es ist also nicht zu erkennen, ob es sich um einen "out" oder "in"-Parameter handelt.

In der Praxis werden Pointer aber eher als In-Parameter verwendet, Referenzen (&) als out (daher auch ref).

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Danke
ich versuch es mal!

Gruß Joerg

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo,
leider hatte hat das ganze noch nicht geklappt.
nachstehend habe ich mal die Doku zu dieser Funktion mitgeliefert.
Es geht mir hauptsächlich um den Parameter "void *pMsg".

Gruß und Danke Joerg

//API Reference------------------------------
Msg_GPSPositionGet
Decode and retrieve current position information from a MSG_ID_GPSPosition message
Syntax (Prototyped in ALKMsg.h)
long Msg_GPSPositionGet(void *pMsg, double &dLat, double &dLon,
double &dHeading, double &dSpeed,
long &UTCDate, long &UTCTime, long &lAltitude,
double &dPDOP, short &sFixMode,
short &sSatelliteCount)
Parameters
pMsg: Raw pointer to the buffer received by your callback function (previously set
using Msg_SetCallback).
dLat: Current latitude (in millionths of a degree). Divide this number by
1,000,000 to obtain degrees Latitude.
dLon: Current longitude (in millionths of a degree). Divide this number by
1,000,000 to obtain degrees Longitude.
dHeading: Current heading in degrees.
dSpeed: Current speed in Miles per Hour.
UTCDate: Current UTC date.
UTCTime: Current UTC time.
lAltitude: Current altitude in feet above sea level.
dPDOP: Percent Dilution of Precision (a measure of GPS accuracy)
sFixMode: Type of GPS Fix (2D or 3D)
sSatelliteCount: The number of satellites used to compute the last position
Return Value
MSG_OK Success
MSG_ERROR Failure
//-------------------------------------------------

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hier noch die andere Funktion wie sie über DllImport aufgerufen werden soll.

[DllImport("Alksdk_dotNet.dll",EntryPoint="Msg_SetCallback",CallingConvention=CallingConvention.Winapi)]
public static extern int Msg_SetCallback(int msgID, IntPtr pCallback);

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Für Callbacks musst du bei der DLLImport-Deklaration ein Delegate mit der richtigen Signatur angeben. Wenn du die mir verrätst, kommen wir weiter.

Also: Wie genau sieht der Callback aus (welche Parameter, welcher Returnwert)?

Was den Message-Parameter angeht: Auch hier brauchen wir die struct-Definition der Message. Aber ich vermute mal, dass du diesen Message-Pointer in der Callback-Funktion als Parameter reinbekommst. Wie der genau aussieht kann dir egal sein, weil du die Message ja mit der anderen Funktion auseinandernimmst. Beides einfach als IntPtr definieren.

Hängt also allles an der Callback-Definition.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo,
so ist die Funktion in der Header für C definiert.

long Msg_SetCallback(unsigned long MsgID, void *pfnProcessMsg, char *pDescription = NULL, callingConvention convention = convention_default);
Ich hoffe das war gefragt.?

Ich habe noch nie mit Callbackfunctionen oder Delegaten gearbeitet.
Bin also im Moment etwas überfordert.

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Kein Problem, aber es fehlt noch die Definition von CallingConvention. Dürfte ein Enum sein.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

ist so angegeben:
enum callingConvention {convention_default, convention_cdecl, convention_stdcall};

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Den ersten Teil haben wir schon:

 
[DllImport("Alksdk_dotNet.dll"]
long Msg_SetCallback(ulong MsgID, MessageDelegate msgCallback, string pDescription, uint callingConvention);

Als Calling-Convention musst du immer "2" angeben. cdecl-Callback berherrscht .NET nur mit Tricks.

Leider hab ich mich wohl schlecht ausgedrückt. Der zweite Parameter von Msg_SetCallback() ist ein Funktionszeiger. Dummerweise untypisiert. Irgendwo muss in der Hilfe stehen wie die Funktion aussehen darf, die man hier angeben kann.

Danach entscheidet sich, wie MessageDelegate definiert wird.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Das steht in der API Reference zu Msg_SetCallback

Msg_SetCallback
Sets the address of a function to receive control when a message arrives. Not required for all
messages. Must be called once for each message type that should receive a confirmation.
Syntax (Prototyped in ALKMsg.h)
long Msg_SetCallback(unsigned long MsgID, void *pfnProcessMsg, char
*pDescription = NULL);
Callback Function Syntax
void (*pfnProcessMsg)(const char *pBuf, const unsigned long lBufLen)
Parameters
MsgID: Identifier for Message
pfnProcessMsg: Address of function to call when message arrives
pDescription: For example “Response” for response message ID
Return Value
0 failed, else success

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren
delegate void MessageDelegate(IntPtr buffer, ulong buffLen);

Und zusammen:

private void MyMessageCallback(IntPtr buffer, ulong buffLen)
{
   // vermutlich hier irgendwo:
   Msg_GPSPositionGet(buffer,......);    
}


// irgendwo ander....

Msg_SetCallback(myMessageID, new MessageDelegate(MyMessageCallback),"meineBeschreibung",2);

Aus der Beschreibung geht allerdings nicht hervor, ob der Buffer, der über den Callback reinkommt der "Message" entspricht..... vermutlich aber schon.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo svenson,

erstmal Danke für Hilfe.
Versuche jetzt das gelesene umzusetzen.
Hoffentlich klappt's! Ist das letzte Teil in meinem Puzzel.

Gruß Joerg

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Noch eine Frage.

Muss ich irgendwo die beiden Variablen vorher füllen?

private void MyMessageCallback(IntPtr buffer, ulong buffLen)

Bis jetzt war das Ergebnis eine Fehlermeldung
"NotSupportedException".

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Zeig mir doch mal den relevanten Code von dir.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Noch eine Frage: Das ist kein Compact Framework oder?

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Doch,sorry, ist für'n PDA.

public delegate void MessageDelegate(IntPtr buffer, ulong buffLen);

[DllImport("Alksdk_dotNet.dll")]
public static extern long Msg_SetCallback(ulong MsgID, MessageDelegate msgCallback, string pDescription, uint callingConvention);

public bool GPRSDatenErstellen(.....)
{
.....
try
{
Msg_SetCallback(ALK.Msg.MSG_ID_GPSPosition, new MessageDelegate(MyMessageCallback),"meineBeschreibung",2);
}
catch(Exception ex)
{
MsgSpeichern("über Nav " + ex.Message);
}
......
}

private void MyMessageCallback(IntPtr buffer, ulong buffLen)
{
long gps = ALK.Msg.Msg_GPSPositionGet(buffer,
ref dLat,
ref dLon,
ref dHeading,
ref dSpeed,
ref lUTCDate,
ref lUTCTime,
ref lAltitude,
ref dPDOM,
ref sFixMode,
ref sSatelliteCount);
}

In der Funktion GPRSDatenErstellen erstelle ich DatenPakete die ich dann verschicke.Genau hier brauche die GPSdaten der Navigationssoftware.

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Au weia, schlechte Nachricht: CF 1.0/1.1 unterstützt keine Callbacks von unmanaged in managed Code.

Nur CF 2.0 kann das. Brauchst also VS.2005 beta und CF 2.0.

Ein andere Möglichkeit wäre es, eine weitere unmanaged DLL zu schreiben, die den Callback entgegen nimmt, die Daten in einen gemeinsamen Speicher packt und der Hauptapplikation via Synchronisationsobjekten mitteilt, dass was da ist (oder via Windows Messages).

Genau einen solchen Workaround musste ich auch für eine CF-App machen.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Schei......
Eigentlich sollte das ganze schon "gestern" fertig gewesen sein!
Ich habe keine Ahnung wie ich vorgehen soll um eine

unmanaged DLL zu schreiben, die den Callback entgegen nimmt

Könnte ich da einen Tip bekommen.
Welche Nachteile kann es bringen,wenn ich jetzt auf VS 2005 und CF2.0 wechsle?

Gruß Joerg

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Übrigens ist mein Chef nicht gearde begeistert von C#(ist ein alter C-Programmierer)und steht dem neuem sehr skeptisch gegenüber.
Am liebsten sollte alles in C gemacht werden.
Das kann ich aber leider nicht!
Wenn ich ihm jetzt auch noch erzählen muss,daß dieses und jenes nicht unterstützt wird ist "Polen offen!"

Gruß Joerg

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Joerg,

dann hat dein Chef aber wohl schon länger nicht mehr programmiert.

herbivore

S
8.746 Beiträge seit 2005
vor 18 Jahren

Dann "verkaufe" das geschickt. CF 2.0 ist tatsächlich um einiges besser als das 1.1. Es unterstützt auch die neuen Auflösungen besser.

Erzähle ihm einfach, dass es 2.0 sein muss, weil ihr sonst bald Probleme bekommt.

Was anderes fällt mir nicht ein. Der "Workaround" wird bei dir mangels C-Kenntnissen scheitern.

Wenn ich jetzt eine CF-App beginnen würde, würde ich auch gleich 2.0 nehmen.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Original von herbivore
dann hat dein Chef aber wohl schon länger nicht mehr programmiert.
herbivore

Ist das nicht ein Problem aller Chefs? Haben mal vor Urzeiten nen paar Zeilen C gecodet und denken nun, sie wüßten alles und vor allem besser... 🙂

Meine sind genauso. In unserem Kern-Bereich wird immer noch mit C gearbeitet, angeblich weil es besser "portierbar" sei. Als wenn das die Probleme wären.... 🙂

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

ja,es stimmt er programmiert schon eine Weile nicht mehr!
Ist im Prinzip der Außendienstler der Fima.

Erzähle ihm einfach, dass es 2.0 sein muss, weil ihr sonst bald Probleme bekommt.

Kann aber auch sein das ich bald ein Problem habe mit meinem Arbeitsplatz.
Bin noch nicht lange in der Firma.Auch noch nicht so lange in der Branche.
Alle anderen Kollegen machen nur C, wollen und können kein C#.

Nochmal zu den Nachteilen von VS 2005 und CF 2.0.
Laufen alte Programme weiterhin?
CF ist mit 4,5 MB recht groß.
Kann es da Speicherprobleme auf dem PDA geben?
Bei Windows Mobile 5.0 ist CF 2.0 im ROM integriert-laufen ältere BS (2003,2002)?

Gruß Joerg

S
8.746 Beiträge seit 2005
vor 18 Jahren

Vorher war das CF 3 MB groß, also nur 1.5 MB mehr.

Normalerweise hat ein PDA heutzutage 64 MB. Für Anwendung stehen dann zwischen 20 und 35 MB zur Verfügung, je nach Platz, dem man dem Filesystem spendiert.

Die Größe ist also kein wirkliches Argument.

Die ROM-Installation ist aber tatsächlich ein Problem. Wenn der PDA im ROM nur mit dem alten CF daherkommt, dann musst du 2.0 mitinstallieren... auch bei jedem Hardware-Reset (macht man zwar selten, aber immerhin).

Gehen tut das, macht aber die Installation ein wenig zeitraubender. Technisch allerdings kein Problem.

Generell ist aber die BS-Vielfalt bei den PDA ein ein problem. Was ist mit alten CE 4.0-PDAs? Was ist mit der kleinen Auflösung (320*200)? Man muss hier einiges mehr beachten als auf dem PC, das gilt aber unabhängig von .NET.

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo
Habe mir jetzt die Testversion von VS 2005 mal auf mein Notebook aufgespielt.
BS Windows Home,VS 2003 ist parallel noch installiert.

Leider gibt's ne Fehlermeldung wenn ich den Code aus dem VS raus direkt auf dem PDA starten will.
(The operation could not be completed)
In der Error List steht dann:
The current version of ActiveSync is not supported....
Habe mir vorher allerdings die neueste Version runtergeladen(3.7 ger).
Die Geräte die ich auswählen kann sind:
Pocket PC 2003 Device,Pocket PC 203 SE Emulator,Pocket PC 2003 SE VGA Emulator.

Welche Möglichkeiten habe ich um CF 2.0 auf den PDA zu bekommen?
Müssen noch andere Sachen installiert werden? Oder Einstellungen gemacht werden?

Gruß Joerg

PS.: Chef hat die "Aufrüstung" gelassen aufgefasst.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Bei ActiveSync ist die aktuelle Version mindestens 3.8, für CE 5.0 sogar 4.0 (hier bin ich mir nicht sicher).

Es gibt aber Probleme bei der Installation von ActiveSync und VS. Wichtig ist, dass das eine (ich glaube ActiveSync) _vor _VS installiert wird. Hat mich neulich einen ganzen Tag Arbeit gekostet......

J
Joerg Themenstarter:in
152 Beiträge seit 2005
vor 18 Jahren

Hallo,
habe jetzt endlich cf 2.0 installiert und versuche mich wieder an den Callbackfunctionen.
Habe dazu ein beispiel aus dem Buch genommen.
leider bekomme ich auch hier eine fehlermeldung.
NotSupportException

hier der Code:
public delegate bool EnumWindowsCBdelegate(uint hWindow,uint Uservalue);

[DllImport("user32")]
public static extern int EnumWindows(EnumWindowsCBdelegate CB,uint UserValue);

	[DllImport("user32")]  
	public static extern void GetWindowText(uint CB,StringBuilder WindowCaption,int nMaxCount);  

private void button1_Click(object sender, System.EventArgs e)
{
EnumWindowsCBdelegate EnumCB = new EnumWindowsCBdelegate(EnumWindowsCB);

		listBox1.Items.Clear();  
		try  
		{  
			EnumWindows(EnumCB,0);  
		}  
		catch (Exception ex)  
		{  
			listBox1.Items.Add(ex.Message);  
		}  
	}  

	public bool EnumWindowsCB(uint hWindow,uint UserValue)  
	{  
		StringBuilder WindowCaption = new StringBuilder(256);  
		listBox1.Items.Add("in EnumWindowsCB");  
		GetWindowText(hWindow,WindowCaption,WindowCaption.Capacity);  
		if(WindowCaption.Length > 0) listBox1.Items.Add(WindowCaption.ToString());  
		return true;  
	}  

Gruß Joerg