Initalisierung einer USB-Karte in Unterprogramm "auslagern"



  • Hallo,

    ich hoffe, Ihr könnt mir helfen.
    Ich möchte über C++ und die Win-API eine CNC-Steuerung bauen.
    Hierfür habe ich mir bereits ein USB-Board (Velleman K8055) und passende Schrittmotoren gekauft.
    Die Ansteuerung der USB-Karte geht soweit auch einwandfrei, die von Velleman gegebene Initialisierung + .dll-Dateien funktionieren.
    Allerdings habe ich das Problem, dass ich die Initialisierung der USB-Karte immer in meiner Main-Funktion tätigen muss. Ich möchte diese gerne auslagern.
    Ich stoße dabei leider auf das Problem, dass ich hier immer wieder Fehlermeldungen bekomme, egal wie ich die Initialisierung ausserhalb der Main-Datei mache.

    Ich habe in meinem Programm 4 Funktionen:

    Testerling.hpp = Funktionsprototyp von Testerling.cpp
    USBInit.hpp = Typdefinitionen der USB-Karte
    Main.cpp = Hauptprogramm
    Testerling.cpp = Funktion zum Testen eines Befehls über „Unterprogramm“

    Testerling.hpp
    ______________________________________

    //Funktionsprototyp fuer Testerling
    int Testerling();
    

    ______________________________________

    USBInit.hpp
    ______________________________________

    typedef void(CALLBACK* t_func)(int );
    typedef void(CALLBACK* t_func0)();
    typedef int(CALLBACK* t_func1)();
    typedef void(CALLBACK* t_func2)(int *, int *);
    typedef void(CALLBACK* t_func3)(int , int );
    typedef int(CALLBACK* t_func4)(int );
    typedef bool(CALLBACK* t_func5)(int );
    
    t_func4 OpenDevice;
    t_func0 CloseDevice;
    t_func0 Version_;
    t_func4 ReadAnalogChannel;
    t_func2 ReadAllAnalog;
    t_func3 OutputAnalogChannel;
    t_func3 OutputAllAnalog;
    t_func ClearAnalogChannel; 
    t_func0 ClearAllAnalog;
    t_func SetAnalogChannel; 
    t_func0 SetAllAnalog;
    t_func WriteAllDigital;
    t_func ClearDigitalChannel;
    t_func0 ClearAllDigital;
    t_func SetDigitalChannel;
    t_func0 SetAllDigital;
    t_func5 ReadDigitalChannel;
    t_func1 ReadAllDigital;
    
    HINSTANCE hDLL;
    int foundDLL = 0;
    

    ______________________________________

    Main.cpp
    ______________________________________

    #include <cstdlib>
    #include <windows.h>
    #include <iostream>
    #include "Testerling.hpp"	//Als Test fuer Unterprogramme
    #include "USBInit.hpp"		//Typedefs für USB-Karte
    
    using namespace std;
    
    //Funktionsprototypen
    LRESULT CALLBACK WindowProc (HWND hWnd, UINT message,
    							 WPARAM wParam, LPARAM lParam);
    HWND ErstelleHauptfenster (HINSTANCE hInst);
    void ErstelleSteuerelemente (HWND hWnd, HINSTANCE hInst);
    
    //IDs der Child-Fenster
    	//Button
    #define ID_ButtonBeenden		4049
    #define ID_ButtonInitialisieren	4050
    #define ID_ButtonTest			4051
    #define ID_ButtonTestAus		4052
    	//Button
    
    //Globale Variablen
    //EIGENTLICH NICHT SO ZU MACHEN
    
    HWND hButtonBeenden;
    HWND hButtonInitialisieren;
    HWND hButtonTest;
    HWND hButtonTestAus;
    
    //Hauptprogramm
    //
    int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst,
    					LPSTR lpcmdline, int ncmdshow)
    {
    
    	HWND hWnd;					//Fenster-Handle
    	MSG message;				//Nachricht
    
    	//Hauptfenster erstellen
    	hWnd = ErstelleHauptfenster (hInst);
    
    	//Pruefen, ob alles glattging
    	if (hWnd == NULL)								//Wenn der zurueckgegebene Wert 0 ist, dann Programm beenden
    		return(0);									//also return (0);
    
    	//Alle Steuerelemente erstellen
    	ErstelleSteuerelemente(hWnd, hInst);
    
    	//Der "Herzschlag" des Programms
    	//Hier werden alle Nachrichten abgeholt,
    	//uebersetzt und weitergeleitet
    	while (GetMessage (&message, NULL, 0,0))
    	{
    		TranslateMessage (&message);
    		DispatchMessage (&message);
    	}
    
    	//Programm beenden
    	return (int)(message.wParam);
    
    } //WinMain
    
    //Erstelle Hauptfenster
    //Hauptfenster erstellen und Handle zurueckliefern
    
    HWND ErstelleHauptfenster(HINSTANCE hInst)
    {
    	HWND hWnd;					//Fenster-Handle
    	WNDCLASSEX windowclass;		//Nachricht
    
    	//Der Klassenname des Fenstes ist frei wählbar
    	const TCHAR szClassName[] = TEXT ("CNC-Steuerung");
    
    	//Struktur mit gewuenschten Eigenschaften fuellen
    	//
    
    	//Groesse der Struktur zwischespeichern
    	windowclass.cbSize = sizeof(WNDCLASSEX);
    
    	//Fenster soll beim Verschieben neu gezeichnet werden
    	windowclass.style = CS_HREDRAW | CS_VREDRAW;
    
    	//Zeiger auf Callback-Funktion
    	windowclass.lpfnWndProc = WindowProc;
    
    	//Keine erweiterten Einstellungen
    	windowclass.cbClsExtra = 0;
    	windowclass.cbWndExtra = 0;
    
    	//Instanz Speichern
    	windowclass.hInstance = hInst;
    
    	//Icons und Cursor festlegen
    	windowclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    	windowclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    	windowclass.hCursor = LoadCursor (NULL, IDC_ARROW);
    
    	//Hintergrundfarbe festlegen
    	windowclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND+1;
    
    	//Ein Menue brauchen wir nicht
    	windowclass.lpszMenuName = NULL;
    
    	//Klassenname angeben
    	windowclass.lpszClassName = szClassName;
    
    	///Fensterklasse registrieren
    	if (!RegisterClassEx (&windowclass))
    		return (NULL);
    
    	//Das Fenster erzeugen
    	hWnd = CreateWindowEx (NULL,
    							szClassName,
    							TEXT("CNC-Steuerung"),
    							WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    							CW_USEDEFAULT, CW_USEDEFAULT,			// x-Position des Fensters - y-Position des Fensters
    							1200, 600,								//Fenstergroesse Breite und Hoehe
    							NULL,									//
    							NULL,
    							hInst,
    							NULL);
    
    	//Fensterhandle zurueckgeben
    	return (hWnd);
    } //Erstelle Hauptfenster
    
    //Erstelle Steuerelemente
    //
    //Alle Steuerelemente erstellen
    
    void ErstelleSteuerelemente(HWND hWnd, HINSTANCE hInst)
    {
    
    	//BUTTON	
    	 //Beenden-button als Child-Fenster erzeugen
    	 hButtonBeenden = CreateWindow (TEXT("BUTTON"),
    						TEXT("Beenden"),
    						BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,
    						1050, 500,
    						95, 40,
    						hWnd,
    						(HMENU)ID_ButtonBeenden,
    						hInst,
    						NULL);
    
    	 hButtonInitialisieren = CreateWindow (TEXT("BUTTON"),
    						TEXT("Initialisieren"),
    						BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,
    						100, 150,
    						95, 40,
    						hWnd,
    						(HMENU)ID_ButtonInitialisieren,
    						hInst,
    						NULL);
    
    	 hButtonTest = CreateWindow (TEXT("BUTTON"),
    						TEXT("Test"),
    						BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,
    						100, 200,
    						95, 40,
    						hWnd,
    						(HMENU)ID_ButtonTest,
    						hInst,
    						NULL);
    
    	 hButtonTestAus = CreateWindow (TEXT("BUTTON"),
    						TEXT("Test Aus"),
    						BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD,
    						100, 250,
    						95, 40,
    						hWnd,
    						(HMENU)ID_ButtonTestAus,
    						hInst,
    						NULL);
    
    	//BUTTON
    
    	}
    //Erstelle Steuerelemente
    
    	//Callback-Funktion zur Nachrichtenverarbeitung
    //
    LRESULT CALLBACK WindowProc (HWND hWnd, UINT message,
    							 WPARAM wParam, LPARAM lParam)
    {
    	//Messages auswerten
    	switch (message)
    	{
    		//Fenster schliessen (Auch Alt+F4)
    	case WM_DESTROY:
    		{
    			//Nachricht zum Beenden schicken
    			PostQuitMessage(0);
    			return (0);
    		}
    
    		//Ab hier die Nachrichten unserer Child-Fenster bearbeiten
    	case WM_COMMAND:
    		{
    			switch (wParam)
    			{
    
    				//Wurde Initialisieren angeklickt?
    			case ID_ButtonInitialisieren:
    				{
    		hDLL = LoadLibrary("k8055d");
    		if (hDLL != NULL)
    			{
    				OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice");
    				if (!OpenDevice)		
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				CloseDevice = (t_func0) GetProcAddress(hDLL, "CloseDevice");
    				if (!CloseDevice)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ReadAnalogChannel = (t_func4) GetProcAddress(hDLL, "ReadAnalogChannel");
    				if (!ReadAnalogChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ReadAllAnalog = (t_func2) GetProcAddress(hDLL, "ReadAllAnalog");
    				if (!ReadAllAnalog)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				OutputAnalogChannel = (t_func3) GetProcAddress(hDLL, "OutputAnalogChannel");
    				if (!OutputAnalogChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				OutputAllAnalog = (t_func3) GetProcAddress(hDLL, "OutputAllAnalog");
    				if (!OutputAllAnalog)		
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ClearAnalogChannel = (t_func) GetProcAddress(hDLL, "ClearAnalogChannel");
    				if (!ClearAnalogChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ClearAllAnalog = (t_func0) GetProcAddress(hDLL, "ClearAllAnalog");
    				if (!ClearAllAnalog)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				SetAnalogChannel = (t_func) GetProcAddress(hDLL, "SetAnalogChannel");
    				if (!SetAnalogChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				SetAllAnalog = (t_func0) GetProcAddress(hDLL, "SetAllAnalog");
    				if (!SetAllAnalog)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				WriteAllDigital = (t_func) GetProcAddress(hDLL, "WriteAllDigital");
    				if (!WriteAllDigital)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ClearDigitalChannel = (t_func) GetProcAddress(hDLL, "ClearDigitalChannel");
    				if (!ClearDigitalChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ClearAllDigital = (t_func0) GetProcAddress(hDLL, "ClearAllDigital");
    				if (!ClearAllDigital)		
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				SetDigitalChannel = (t_func) GetProcAddress(hDLL, "SetDigitalChannel");
    				if (!SetDigitalChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				SetAllDigital = (t_func0) GetProcAddress(hDLL, "SetAllDigital");
    				if (!SetAllDigital)		
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ReadDigitalChannel = (t_func5) GetProcAddress(hDLL, "ReadDigitalChannel");
    				if (!ReadDigitalChannel)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				ReadAllDigital = (t_func1) GetProcAddress(hDLL, "ReadAllDigital");
    				if (!ReadAllDigital)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    				Version_ = (t_func0) GetProcAddress(hDLL, "Version");
    				if (!Version_)
    				{						// handle the error
    					FreeLibrary(hDLL);	
    					return -2;
    				}
    					OpenDevice(0);
    
    					return 0;				// ok
    			}       
    					return -1;					// error load DLL
    
    		return (0);
    
    				}
    
    			//Wurde Test angeklickt?
    			case ID_ButtonTest:
    				{
    					WriteAllDigital(1);
    					Sleep(100);
    					WriteAllDigital(2);
    					Sleep(100);
    					WriteAllDigital(4);
    					Sleep(100);
    					WriteAllDigital(8);
    					Sleep(100);
    					WriteAllDigital(0);
    					return (0);
    				}
    
    	//Wurde Test Aus angeklickt?
    	case ID_ButtonTestAus:
    		{
    			int Testerling();
    		}
    
    		//Wurde Beenden angeklickt?
    
    			case ID_ButtonBeenden:
    				{
    					int Resultat;		//Rueckgabewert der Messagebox
    
    					//Messagebox fuer Sicherheitsabfrage
    					Resultat = MessageBox (hWnd, TEXT("Wirklich Beenden?"),
    											TEXT("Programm beenden"),
    											MB_YESNO | MB_ICONQUESTION);
    
    					//Wurde Ja angeklickt?
    					if (Resultat == IDYES)
    					{
    						//Ja, also Programm beenden
    						ClearAllDigital();		//Alle Digitalen Ausgänge deaktivieren
    						CloseDevice();			//USB-Karte Beenden
    						FreeLibrary(hDLL);		//Library herunterfahren
    						PostQuitMessage(0);
    						return (0);
    					}
    
    					//Nein, also ganz normal weiter
    					return (0);
    				}
    
    			} break;
    		}break;
    	}
    
    	// Die Nachrichgt wurde nicht von uns verarbeitet, also 
    	// von Windows verarbeiten lassen
    	return (DefWindowProc (hWnd, message, wParam, lParam));
    } //Windowproc
    

    ______________________________________

    Testerling.cpp
    ______________________________________

    #include"Testerling.hpp"
    #include <windows.h>
    
    int Testerling(HWND hWnd, HINSTANCE hInst)
    {
     	int Resultat;		//Rueckgabewert der Messagebox
    		Resultat = MessageBox (hWnd, TEXT("Tester"),
    			TEXT("Test"),
    			MB_YESNO | MB_ICONQUESTION);
    
    			//Wurde Ja angeklickt?
    			if (Resultat == IDYES)
    			{
    			}
    			//Nein, also ganz normal weiter
    			return(0);
    }
    

    ______________________________________

    Wenn ich Initialisierungsbefehle (Alles, was beim Button "ID_ButtonInitialisieren:" ausgeführt wird in Testerling.cpp verschiebe, dann werden die Typdefinitionen nicht erkannt.

    Fehlermeldung (Beispiel, eine von Vielen):

    t_func5: nichtdeklarierter Bezeichner
    

    Wenn ich dann in die Datei Testerling.hpp die Typdefinitionen includiere kommt die Fehlermeldung, dass alles schon in der Main.obj definiert ist

    Wenn ich jetzt in der Main.cpp die #include „USBInit.hpp“ entferne, dann werden in der Main.cpp die USB-Karten-Befehle nicht mehr erkannt.

    Was muss ich tun, dass ich die Initialisierung der USB-Karte in ein Unterprogramm „auslagern“ kann, aber trotzdem noch von der Main.cpp die USB-Karten-Befehle verwenden kann?

    Vielen Dank vorab für eure Hilfe!!

    Gruß Robin Brenner



  • Ich habe keine Lust, Dein Programm zu analysieren.
    Aber ... Du hast in USBInit.hpp jede Menge Variablen definiert. Wenn Du USBInit.hpp nun in zwei cpp-Dateien (Testerling.cpp und main.cpp inkludierst, dann sieht der Linker natürlich, dass die alle doppelt definiert sind, das geht so nicht ...
    Die Frage ist, müssen die dort definierten Variablen in beiden cpp-Dateien existieren und wenn ja, sollen es dann dieselben oder diegleichen sein?
    Brauchst Du also projektglobale Variablen, oder brauchst Du sie vllt. dann nur in Testerling.cpp?

    Wenn sie nicht projektglobal sein sollen, gehören sie nicht in ein Headerfile, sondern in ein (das richtige) cpp-File.

    Ein Versuch ohne allzu großen Änderungsaufwand wäre, sie in einen anonymen Namespace einzubetten ...



  • Wie Belli schon geschrieben hat gehören Dinge wie

    t_func4 OpenDevice;

    so nicht in ein Headerfile.

    Lösungsmöglichkeit: Kopier diese Teile nach Testerling.cpp und mach im Header
    ein extern davor.

    Ich würde das ganze auch in eine Klasse packen, dann ist auch sichergestellt,
    das die Library einfach wieder geschlossen werden kann und nichts vergessen wird.



  • Hallo,

    Ok, vielen Dank für eure Antworten!

    Gruß Robin Brenner