Hallo zusammen, ich hab ein Problem mit C: Ich hab versucht aus der K8055D.dll eine Lib für den GCC zu basteln. Folgende DEF hab ich verwendet: LIBRARY k8055d.dll EXPORTS OpenDevice@4 CloseDevice@0 ReadAnalogChannel ReadAllAnalog OutputAnalogChannel OutputAllAnalog ClearAnalogChannel SetAllAnalog ClearAllAnalog SetAnalogChannel WriteAllDigital@4 ClearDigitalChannel ClearAllDigital SetDigitalChannel SetAllDigital ReadDigitalChannel ReadAllDigital ReadCounter ResetCounter SetCounterDebounceTime Danach hab ich mit dlltool die k8055d.a LIB gebaut und folgendes Testprogramm geschrieben: #include"k8055d.h" #include<unistd.h> #include<stdio.h> int main() { OpenDevice(0); long int value=0; long int dig=0; while(dig!=16) { dig=ReadAllDigital(); value=ReadAnalogChannel(1); printf("Wert: %i\n",value); sleep(1); } CloseDevice(); return 0; } Mit folgender Header: #define EXPORT extern __declspec(dllimport) EXPORT long int OpenDevice(long int CardAddress); EXPORT void CloseDevice(void); EXPORT long int ReadAnalogChannel(long int Channel); EXPORT void ReadAllAnalog(long int *Data1,long int *Data2); EXPORT void OutputAnalogChannel(long int Channel,long int Data); EXPORT void OutputAllAnalog(long int Data1,long int Data2); EXPORT void ClearAnalogChannel(long int Channel); EXPORT void SetAllAnalog(void); EXPORT void ClearAllAnalog(void); EXPORT void SetAnalogChannel(long int Channel); EXPORT void WriteAllDigital(long int Data); EXPORT void ClearDigitalChannel(long int Channel); EXPORT void ClearAllDigital(void); EXPORT void SetDigitalChannel(long int Channel); EXPORT void SetAllDigital(void); EXPORT long int ReadAllDigital(void); EXPORT long int ReadCounter(long int CounterNr); EXPORT void ResetCounter(long int CounterNr); Nun tritt folgendes Problem auf: Sobald ich versuche mit WriteAllDigital() einen Wert in den Digitalausgang zu schreiben hängt sich das Programm nach wenigen Ausgaben auf. Der Stackdump: Exception: STATUS_ACCESS_VIOLATION at eip=00000000 eax=00000000 ebx=00000004 ecx=01010101 edx=FFFFFFFF esi=00401050 edi=610E21A0 ebp=0022EEEC esp=0022EEF0 program=C:\cygwin\k8055\test.exe, pid 1368, thread main cs=001B ds=0023 es=0023 fs=0038 gs=0000 ss=0023 Stack trace: Frame Function Args End of stack trace Hat jemand ne Idee, wo der Fehler liegt. Tausend Dank im Vorraus und Gruß, SIGINT
Lass Dein Programm doch mal in einem Debugger laufen, der sollte etwas mehr Informationen ausgeben als die paar Prozessorregister. eip=0 lässt darauf schließen, daß -auf welchem Wege auch immer- das Programm durch einen Nullpointerzugriff komplett ins Nirvana gelaufen ist. Du könntest die DLL auch ohne Importlibrary ansprechen, wie das geht, habe ich hier http://www.mikrocontroller.net/forum/read-8-263818.html#264093 mal beschrieben. Viel Erfolg!
Hey cool, deine Methode hat Funktioniert... jetzt muss ich nur noch genau verstehen wie das Funktioniert,aber das ist ne andere Sache. Wenn ich das richtig verstehe, dann kann ich "LoadLibrary" auch dazu verwenden, um DLLs dynamisch zu laden. Also etwa wie Plugins bei Winamp. Vielen Dank für den Link Gruß, Bastian
ARGHHHH, manchmal Frage ich mich,wie es möglich ist Programme zu schreiben, die auf einem anderen Rechner laufen: Ich hab mir jetzt ein kleines Winamp-Plugin zusammengschustert,daß das K8055 in eine VU-Anzeige verwandelt... funktioniert auf meinem Rechner auch ganz gut. Mein Problem ist nun, daß ich es nicht schaffe das Programm auf einem anderen Rechner ans laufen zu bringen. Ich vermute,daß das irgendwas mit den notwendigen DLLs zu tun hat: $ cygcheck vis_k8055.dll Found: C:\cygwin\winamp\vis\vis_k8055\vis_k8055.dll C:/cygwin/winamp/vis/vis_k8055/vis_k8055.dll C:\WINNT\System32\KERNEL32.dll C:\WINNT\System32\NTDLL.DLL C:\WINNT\System32\USER32.dll C:\WINNT\System32\GDI32.DLL $ cygcheck K8055D.DLL Found: C:\cygwin\winamp\vis\vis_k8055\K8055D.DLL C:/cygwin/winamp/vis/vis_k8055/K8055D.DLL C:\WINNT\System32\ADVAPI32.DLL C:\WINNT\System32\NTDLL.DLL C:\WINNT\System32\KERNEL32.DLL C:\WINNT\System32\RPCRT4.DLL C:\WINNT\System32\GDI32.DLL C:\WINNT\System32\USER32.DLL C:\WINNT\System32\OLE32.DLL C:\WINNT\System32\OLEAUT32.DLL C:\WINNT\System32\SETUPAPI.DLL C:\WINNT\System32\MSVCRT.DLL C:\WINNT\System32\USERENV.DLL C:\WINNT\System32\HID.DLL Sieht jemand das Problem, warum das Plugin nicht auf den anderen Rechnern läuft (einmal Win98 und WinXP)? Das Demoprogramm des K8055 läuft unter Win98 und XP ohne Prob... also kann es eigentlich kein Problem mit der K8055d.DLL sein... obwohl die die NTDLL.dll benötigt (seltsam). Danke für jeden Hinweis. Gruß, Bastian Schmelzer
Wo läuft was nicht? Laufen überhaupt von dir mit GCC/cygwin kompilierte Programme/Plugins auf den beiden Rechnern? Ich meine reine "Hello world" Programme ohne Zugriff auf K8055?
Hallo Stefan, eigentlich sollten mit "-mno-cygwin" übersetzte Programme keine Cygwin-DLLs benötigen. Und das "Hello World" Programm läuft ohne Probleme,also glaube ich, es ist ein Problem mit den DLLs. $ cygcheck.exe hallo.exe Found: C:\cygwin\hallo.exe C:/cygwin/hallo.exe C:\WINNT\System32\msvcrt.dll C:\WINNT\System32\KERNEL32.dll C:\WINNT\System32\NTDLL.DLL Auf meinem Rechner funktioniert der Zugriff auf die K8055D.dll ohne Probleme. Gruß, Bastian
Wenn du möchtest, kann ich auf meinem Rechner versuchen, das Problem nachzuvollziehen. Das Board habe ich auch und Cygwin wollte ich sowieso schon länger installieren. Mit meinem brandneuen DSL kann ich das jetzt auch wagen... Gruß Stefan
Jo, das wäre super. Ich hab die Sources mal angehängt. Aber eins vorweg: Ich hab nicht wirklich Ahnung in C-Programmierung, deshalb dürfte das extrem Buggy sein, ausserdem ist die Ausgabe auf dem K8055 Board nicht wirklich sehenswert... daran muss ich noch mal rumspielen. Übersetzen musst du das Teil leider auch von Hand,da ich mich nicht mit makefiles auskenne. :( Die notwendigen LIBs hab ich im makefile vom Winamp Plugin SDK rausgesucht und getestet,welche ich weglassen kann. Viel Erfolg beim übersetzen. Gruß, Bastian
So kurze Rückmeldung... Das Cygwin-Paket ist inzwischen auf der Platte. Das Winamp-Plugin-SDK auch und deine Quellen auch. Am Wochenende oder heute nacht wird alles installiert und getestet. Ich hoffe, nächste Woche was zum Verhalten auf Windows 98SE schreiben zu können. Auf welchem Rechner läuft es bei dir? Gruß Stefan
Ich nutze Win2000... ich hoffe aber,daß die Header von Cygwin auch unter Win89SE funktionieren. Mit der Win32API kenn ich mich aber nicht aus, es kann also auch sein,daß es nicht funktioniert. Gruß, SIGINT
Es funktioniert nicht. Das hängt aber nicht an deinem Code bzw. bin ich gar nicht so weit gekommen, um den zu testen. Ich habe mir das komplette Winamp SDK geholt und daraus das Beispiel VIS_TEST mit Cygwin kompiliert. Das entstehende VIS_TEST Plugin stürzt beim Konfigurieren ab. Daraufhin habe ich das Beispiel mit der Original-Makedatei unter Visual C++ 6 übersetzt. Das entstehende VIS_TEST Plugin stürzt auch beim Konfigurieren ab. Änliche Position wie oben irgendwo in KERNEL32. Dein Beispiel baut auf dem VIS_TEST Beispiel auf... wenn das SDK Beispiel schon nicht läuft... und DLL Debuggen ist kein angenehmer Job, schon gar nicht unter Cygwin. Ich werde an der Programmierung der Karte "weiterspielen", irgendwas in Richtung Flugsimulator-Controls ;-) Das Cygwin gefällt mir sehr gut, allein dafür hat es sich schon gelohnt, etwas Zeit reinzustecken. Den Winamp Kram lasse ich mal weg, solange es noch notwendig ist, das SDK selbst zu debuggen ;-) Gruß Stefan
Das ist seltsam: Das VIS_TEST Plugin hat bei mir ohne Probleme funktioniert.Ich werd mal testen, ob das auf dem anderen Rechner läuft... wenn nicht,dann weiss ich zumindest,daß es am Winamp SDK liegt. Gruß, Bastian P.S.: Zum Thema Flightsim: Schau dir lieber das hier an: http://www.mindaugas.com/projects/MJoy/Article.php
Danke für den sehr interessanten Link! Nächster Versuch... VIS_TEST funktioniert jetzt auch mit Visual C++ 6. Möglicherweise hatten die Crashs mit dem Cygwin Plugin gestern den Speicher so gründlich versaut, so dass danach nix mehr ging. Grosse Entschuldigung an Nullsoft!!! Dein Beispiel funktioniert auch mit Visual C++ 6. Ich habe paar Sachen geändert, um die Chance auf Nullpointer zu verringern (Anhang). Es ist noch kein sauberer Code, aber zum Testen langt es. Dein Beispiel mit Cygwin-GCC funktioniert noch nicht. Ich vermute, dass ich noch was grundsätzliches bei der DLL Erstellung mit Cygwin-GCC falsch mache. Winamp mag die neue DLL erst gar nicht laden. Wenigestens kommt jetzt der Crash nicht mehr. Das lag daran, dass ich eine Cygwin1.dll im Plugin-Ordner stehen hatte. Gruß Stefan
So... eine DLL mit Cygwin-GCC rennt jetzt auch und produziert eine Anzeige auf dem Board. Allerdings nur die -mno-cygwin gelinkte DLL. Die andere stürzt weiterhin ab, wenn die Initialisierung über Cygwin1.dll läuft. Das makefile habe ich im Anhang. Bei deinen Versuchen musst du noch das Verzeichnis anpassen, wo das Plugin hin soll... Gruß Stefan
...und noch der von meinen Hilfskonstruktionen gereinigte Quellcode. Beim Zusammenfassen der VU-Funktion hatte ich noch einen Fehler bei der Initialisierung eingebaut. Jetzt ist die Anzeige schöner. Anastasia singt gerade ;-) Gruß Stefan
Hi Stefan, ich werd mir deine Verbesserungen direkt mal anschauen. Ich hab aber noch eine Frage: Wo ist das Problem, wenn im Plugin-Verzeichniss eine Cygwin1.dll ist?? Ich hatte die immer dort liegen und nicht in c:\windows\system32... ich dachte immer,Windows sucht auch im Programmordner nach DLLs. Anscheinend sollte ich mir doch mal ein gutes Buch zum Thema "C Programmierung unter Windows" zulegen ;) Gruß, Bastian
Sooooo, ich hab eine gute und eine schlechte Nachricht. Die Gute zuerst: Es läuft perfekt... Die Schlechte: Ich hab nicht die geringste Ahnung warum ;) Deine Modifikationen sind echt nicht schlecht... ich vergesse immer die Fehlerbehandlung. Zum Glück mach ich das auch nur als Hobby und nicht als Beruf,sonst sollte ich den Job wechseln ;) Allerdings bin ich mit der Anzeige noch nicht zufrieden: Ich werd mal schauen, ob ich das noch schöner hinbekomme... der Quelltext vom originalen Plugin hat keine schöneren Muster erzeugt :( Gruß, Bastian
Ich hab jetzt mal mit einer logarithmischen Skala rumgespielt und es scheint zu funktionieren. Nur manchmal spinnt die Anzeige irgendwie... beim wechseln von Songs, oder ab und zu auch so. Gruß, Bastian
Das freut mich. Hast du mit oder wie ich im makefile ohne cygwin1.dll übersetzt? Ich habe es bisher nur ohne geschafft, also mit dem makefile und der Linkeroption -mno-cygwin, so dass eine mingw32 DLL und keine cygwin32 DLL entsteht. Nicht dass es wichtig wäre, aber sowas fuxt mich etwas. Das Thema Cygwin & DLL für andere Programme ist IMHO saumässig kompliziert. Durch das LoadLibrary werden ja mehrere DLLs geladen... die eigentliche Arbeits-DLL sowie die cygwin1.dll, die kernel32.dll usw.. Und wenn ich gegen die cygwin1.dll gelinkt habe, schmiert das LoadLibrary irgendwo mittendrin ab. Die richtige Debugger-Konfiguration um das genauer zu untersuchen, habe ich noch nicht gefunden. Gruß Stefan
Ich hab dein Makefile zum übersetzen genutzt... hat direkt funktioniert. Was mich noch ein wenig ärgert ist die Tatsache, daß ich es nicht hinbekomme direkt gegen die K8055D.dll zu linken... dann könnte ich mir die Sache mit LoadLibrary sparen. Daran werd ich noch etwas rumspielen müssen. Gruß, Bastian
So... ich hatte jetzt die Zeit und Muse das rauszupfriemeln. Also das implizite Linken geht auch. Man braucht eine DEF-Datei mit den exportierten Funktionen aus der DLL und eine LIB-Datei für den Linker. Die DEF Datei habe ich von Hand erstellt. Ich habe keinen Weg gefunden das automatisch machen zu lassen. Das "Problem" ist das Verwursten der Funktionsnamen durch den C-Compiler aufgrund der __stdcall Deklaration in der H-Includedatei. Der C-Compiler macht dann aus dem Aufruf OpenDevice() ein Symbol _OpenDevice@0 In der DLL sind die Namen dann unverwurstet drin... OpenDevice Daher gehe ich im Moment der DEF-Datei über die Ordinale (21) der Funktion... OpenDevice@0 @21 Zum Glück sind es nur 21 Funktionen. Man muss aber aufpassen, dass sich die Ordinale nicht ändern, wenn eine neue DLL herauskommen sollte! Es wäre nicht schlecht, wenn man mit der ersten Funktion in der DLL (Ordinale @1) die Versionsnummer abfragen könnte... Mit Hilfe der DEF-Datei kann man jetzt eine LIB-Datei für den Linker erstellen. Dazu eignet sich das LIB.EXE aus dem Microsoft Visual C++ Paket. Ich habe die LIB-Datei und die DEF-Datei im Anhang drin, falls du das VC-Tool nicht hast. Das war die "Hauptarbeit". Der Rest ist normale GCC Übersetzung und Linken und das ist wieder im makefile automatisiert. Gruß Stefan
Hi Stefan, sieht eigentlich nicht schlecht aus,aber bei mir funktioniert das nicht :( Wenn ich geben die k8055d.lib linke (ich verstehe nicht, warum ich für GCC nicht die k8055d.a brauche), dann bekomme ich immer: OpenDevice(0) = -2 sleep(0) Und wenn ich versuche mit dlltool die k8055d.a zu erstellen und die lib mit "-lk8055d" hinzulinken möchte, dann kommt: gcc -mno-cygwin -L./ -o calldll.exe calldll.o -lk8055d calldll.o:calldll.c:(.text+0x7a): undefined reference to `__imp__OpenDevice@4' calldll.o:calldll.c:(.text+0xa7): undefined reference to `__imp__ClearAllDigital @0' calldll.o:calldll.c:(.text+0xb4): undefined reference to `__imp__WriteAllDigital @4' calldll.o:calldll.c:(.text+0xdb): undefined reference to `__imp__CloseDevice@0' collect2: ld returned 1 exit status make: *** [calldll.exe] Error 1 An GCC verzweifel ich noch irgendwann.... Gruß, Bastian
OK. Da hat wohl Murphy wieder zugeschlagen ;-) OpenDevice(Kartenadresse) gibt bei erfolgreichem Aufruf die Kartenadresse (0,1,2,3) zurück. Andere Werte bedeuten, dass ein Fehler aufgetreten ist. Es ist aus der Doku nicht ersichtlich, welcher Fehler bei dem Rückgabewert -2 aufgetreten ist. Ich vermute (!), dass dein Programm in der DLL-Hölle (dll hell) steckst. Die mit Borland-Delphi erstellte Velleman-Software besteht aus der K8055D.DLL (4 verschiedene Versioen laut Erstellungsdaten auf der MiniCD) und den zugehörigen Treiberprogrammen K8055Ex.EXE (x 0,1,2,3 jeweils für die Kartenadresse). Ich schlage vor, dass du genau überprüfst, welche DLL und welche Treiberprogramme du verwendest. Ich habe zur Erstellung der Importlibrary die DLL von 4/2004 aus dem Rev.2 Ordner genommen. Dort stehen auch die passenden Treiberprogramme, die dann z.B. in den windows/system Pfad kopiert werden sollten. Das Unschöne beim impliziten Linken ist, dass man zur Laufzeit automatische Fehlermeldungen bekommen kann, dass Symbole fehlen. Beim expliziten Linken über Loadlibrary hat man da vom aufrufenden Programm aus mehr Kontrolle. Bei "meiner" Methode über die DEF-Datei mit den Verweisen auf die Funktionsnummern statt den Funktionsnamen ist ausserdem kritisch, wenn sich die Nummerierung der DLL-Funktionen z.B. bei einem Update der DLL ändert. Zwischen den "fetten" DLLs aus 2003 und den "schlanken" DLLs aus 2004 ist genau das passiert. Eine undokumentierte Funktion (ReadAll) ist in die DLL gewandert und die Nummer u.a. der OpenDevice Funktion hat sich um eins erhöht. Zur Linkzeit wurde dem Hauptprogramm über die Importlibrary (und der über die DEF-Datei) mitgeteilt, dass sich OpenDevice z.B. unter Nummer @20 in der DLL befindet. Wird nun zur Laufzeit eine (ältere) DLL verwendet, bei der unter Nummer @20 eine andere Funktion steht... Beim expliziten Linken über Loadlibrary und die Funktionsnamen mit GetProcAddress ist eine solche Verschiebung kein Problem. Dafür muss man beim expliziten Linken mit Funktionspointern hantieren und ggf. die Quelltexte anpassen. Ich bin an den Themen "wie kann ich trotzdem über die Funktionsnamen implizit linken" und "wie mache ich es mit gcc" dran, brauche aber noch etwas Zeit für eine ausführlichen Beschreibung. Stay tuned ;-)
Ich verstehe das Konzept nicht ganz: Warum gibt es mehrere Arten eine DLL zu linken?!? Wäre es nicht am einfachsten den Linker selbst über die Funktionsnamen in der DLL den Funktionspointer ermitteln zu lassen?!? Das könnte dann doch vom dynamischen Linker während der Laufzeit erledigt werden ... probleme gäbe es dann nur, wenn die Funktionsinterfaces geändert würden. Na egal, ich mach damit erstmal nicht weiter und besorg mir ein gutes C und C++ Buch. Gruß, Bastian
Ja es gibt zwei grundsätzliche Arten eine DLL ("shared library") an ein Hauptprogramm zu binden. Beim impliziten Linken kümmert sich der Linker darum die Symbole aus dem Hauptprogramm mit den Symbolen aus der DLL in Einklang zu bringen und trägt diesen Zusammenhang plus den Namen der DLL ins Hauptprogramm ein. Zur Laufzeit wird dann automatisch die DLL geladen. Das ist genau das, was dir so vorschwebt. Beim expliziten Linken muss sich der Programmierer im Hauptprogramm selbst darum kümmern, wo die DLL steckt (LoadLibrary) und wie er über die Funktionspointer an die Funktionen kommt (GetProcAddress). Zu dem impliziten Linken habe ich jetzt einen längeren Text geschrieben und im Anhang untergebracht. Gruß Stefan
Um das jetzt abzuschliessen noch ein paar Infos: 1) Aus wenn OpenDevice einen Fehler gemeldet hat, muss beim Programmende ein CloseDevice durchgeführt werden. Macht man das nicht, sammeln sich Treiberleichen im Rechner. 2) Es scheint ein ernster Bug in den K8055D-Treibern vorzuliegen. Nach 100 bis 250 Aufrufen von OpenDevice/CloseDevice-Paaren, innerhalb eines Programms oder von getrennten Programmen, liefert Windows keine ("FAST")-Timer mehr an das Treiberprogramm. Daraufhin stürzt das Treiberprogramm K8055Ex.EXE ziemlich tief ab. Ein Neustart des Rechners ist sehr empfehlenswert. Möglicherweise ist dieser Bug erst mit der Umstellung auf die schlanken DLLs 2004 eingeschleppt worden. 3) Es gibt eine neue, superschlanke Treiber-DLL mit dem Releasedatum 10/2005 auf der Supportseite von Velleman http://www.velleman.be Da ist auch eine DLL für VC dabei, bei der der Aufwand fürs Erstellen einer Importlibrary geringer sein müsste (_funktionsname@x vorhanden). 4) In der neuen Treiber-DLL scheint der Bug 1+2 behoben zu sein. Der Aufruf von K8055Ex.EXE ist Geschichte. 5) In der neuen DLL sind zwei Funktion hinzugekommen. Erfreulicherweise auch eine Funktion zum Abfragen der Version. Und alle Ordinale ("Funktionsnummern") haben sich geändert. Was oben in der Diskussion als "worst case" fürs implizite Linken mit der Microsoft-Methode angegeben wurde, ist also eingetroffen. 6) Mit der GNU Methode erstellte Programme sind ohne Neuübersetzen kompatibel mit der neuen Treiber-DLL. Ebenso explizit gelinkte Programme (LoadLibrary/GetProcAddress Methode). Frohes Schaffen ;-) Stefan
Ich bin's, der Stefan von oben ;-) Weitere Links zu K8055 sammele ich auf meiner Benutzerseite.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.