In einer Headerdatei USB_Interface.h kommt bei den folgenden Zeilen:
#ifndef __AFXWIN_H__
#error include \'stdafx.h\' before including this file for PCH
#endif
folgender Fehler:
[C++ Fatal Error] USB_Interface.h(12): F1003 Error directive: include \'stdafx.h\' before including this file for PCH
Hab dann die stdafx.h eingebunden! Hat nichts gebracht kommt trotzdem noch der selbe Fehler!?
Was muß ich denn da machen!?
Programmieren - alles kontrollieren 4.941 Themen, 20.715 Beiträge
stdafx.h per include-statement vor dem ifndef inklusieren.
davon ab kannst du auch precompiled header abschalten (pch.)
aus den paar inf_ormationen die du hier weitergegeben hast sieht es fuer mich aber so aus, als sei der quellcode den du da hast offenbar quellcode fuer vc++ - und nicht fuer den borland c++ builder.
WM_HOPETHISHELPS
ja das wurde in VC++ pogrammiert!
geht das nicht daß, das irgendwie im Borland läuft!?
wenn ich ihm borland c++ builder ne DLL über den DLL Wizard ne DLL erstell kann ich doch auch zwischen VCL, CLX und VCC++ Style DLL!
dann müsst doch Der Borland builder die VC++ Datei lesen können!?
.. das ich keine borland builder habe.
ich weiss zum beispiel nicht, ob der precompiled header unterstuezt. das ist das, was bei dir angemeckert wird.
nur weil es sich um c++ code handelt bedeutet das nicht, das in dem vc++ code nicht irgendwas drin ist, das eben vc++ spezifisch ist.
prinzipiell kann der borland natuerlich 'reinen' c++ code lesen. ob er aber auch mit dingen klarkommt die evt. in dem c++ file drin sind, das du da hast - das ist eine andere frage.
WM_FYI
es gibt beim compiler zwei Einstellungen:
- use precompiled headers
- cache precompiled headers
meinst du das? könnts damit klappen?
Hi!
Ich möchte an der Stelle mal einhaken. Zwar hab' ich weder grossartige Erfahrung mit Dem C++ Builder (meiner ist zu dem seit >2 Jahren dauerverliehen und auch mit VC++ hab' ich mich noch nicht beschäftigt. Trotzdem fallen mir ein paar Dinge auf, die auch mit der ersten frage zusammen hängen.
Erst mal zu den Wahlmöglichkeiten des DLL-Wizards: da geht es natürlich nur um die Art der zu erzeugen DLL. Klartext: dort kann man festlegen, dass eine mit dem C++ Builder erzeugte DLL den MS-spezifischen Anforderungen genügt, so dass man sie mit VC++ nutzen kann.
Daraus kann man nicht shcliessen, dass der C++ Builder VC++ Header verarbeiten können muss...
Wenn ich mir die erste Frage ansehe, geht es doch eigentlich darum eine Fremd-DLL in Borland C++ Builder Quelltexten zu nutzen. OK, die DLL bringt offenbar Headerdateien für VC++ mit, aber ich halte es für warscheinlich, dass die DLL eine ganz normale Windows-DLL ist. Hat man sie im system registriert, dann sollte man sie in den Programmen auch wie eine normale Fremd-DLL nutzen können.
Die Methode um die Funktionen der DLL nutzen zu können hat mr.escape in der ersten Frage beantwortet, bleiben noch die Headerdateien.
Um eine DLL in Windows anzumelden wird das Programm C:\Windows\System\Regsvr32.exe genutzt, das zum Lieferumfang von Windows gehört. Mich wundert allerdings, dass nichts dazu in der Doku zur USB-Interface-Platine steht.
Leider verlassen mich an dieser Stelle meine Praxiskenntnisse, aber wenn ich das zusammenkratze, was ich noch im Hinterkopf, habe, was hier bereits geschrieben wurde und was ich auf die schnelle gelesen habe, dann sollte das Ganze in etwa so ablaufen:
- die DLL muss registriert werden
- man benötigt einer Header-datei für den C++-Builder mit der Deklaration der in der DLL nutzbaren Funktionen
- man kann die Funktionen so aufrufen bzw. einbinden, wie das von mr. escape beschrieben wurde
Wenn der mitgelieferte Header nicht passt, dann wird man ihn für den C++-Builder anpassen müssen. Falls Borlander mitliest, kann er evtl. in diese Richtung weiterhelfen.
Gut zur schnellen Auffrischung fand ich diese von Google gefundene Seite: http://www.inigraphics.net/ini-sc/mswin/awfcsem/kap8.htm
Da geht's gegen Ende um Einbindung von vorhandenen DLLs in eigene Programme.
Gut scheint mir auch diese Fundstelle zu sein: Link
Oder besser noch diese: Link2
Die Suche dahinter ist diese: Link3
Die halte ich allerdings noch für verbesserungswürdig. ;-)
Bis dann
Andreas
Normale DLLs braucht man nicht zu registrieren (lediglich gemeinsam genutzte für den verwendungszähler im SharedDLLs eintrag in der registry, das aber nur für die problemvermeidung beim deinstallieren, nicht aber bei solcher privater anwendung wie hier), sondern nur "ActiveX-DLLs und OCX-Dateien (sog. "COM-Server", da sie ihre Funktionalität über COM-Schnittstellen bereitstellen)" .
Fehlt die importlib oder hat sie das falsche format, geht die dynamische variante aber immer noch, solange die headerdatei vorhanden ist. Ist sogar der quellcode vorhanden, kann diese (mit gewissen änderungen) auch komplett in das projekt integriert werden, so dass der inhalt als obj-datei vollinhaltlich dazugelinkt wird.
Also:
-loadtime: passende *.lib, *.h und *.dll
-runtime : *.h und *.dll
-linktime: *.h und *.cpp
mr.escape
Die Headerdatei ist zwar vorhanden ist jedoch in vc++ programmiert!
Wollt die DLL dynamisch einbinden:
- über Add to Project hab ich die .cpp Datei dem Projekt
hinzugefügt(sie ist ja die Schnittstelle zwischen C++ und der
DLL)
- Dann hab ich die Headerdatei mit #include .... hinzugefügt
(Headerdatei in vc++ programmiert)
Headerdatei ist zwar vorhanden hat aber probleme damit die sie in vc++ programmiert wurde!
Hab hier mal den quellcode der Headerdatei:
(Hab die Funktionen die drin sind weggelassen da die ok sind)
// USB_Interface.h : Haupt-Header-Datei für die DLL USB_INTERFACE
//
#if !defined(AFX_USB_INTERFACE_H__8B60BDB3_653D_48BE_8E0A_9E37291AE876__INCLUDED_)
#define AFX_USB_INTERFACE_H__8B60BDB3_653D_48BE_8E0A_9E37291AE876__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // Hauptsymbole
class CUSB_InterfaceApp : public CWinApp
{
public:
CUSB_InterfaceApp();
}
#endif
Thanks @ all
D.h., dass die funktionen der DLL wenigstens z.t. als MS C++ klasse vorliegen!
Ich frage mich, ob das mit etwas anderem als MS C++ überhaupt verwendbar ist!
Gibt es da nicht eine saubere version der DLL, d.h. mit einfachen C-funktionen? Wer unbedingt eine eigene klasse dafür möchte, könnte das ja als zwischenschritt extra kapseln, ohne alle zu MS C++ zu zwingen!
Bei MS bin ich mir nicht mal sicher, ob sich zwischen versch. Visual-Studio-versionen keine inkompatibilitäten (aligment der datenstrukturen, aufbau der virtuellen funktionstabelle, etc.) bezüglich der klassenbehandlung ergeben. Wie eine verwendung von so etwas in anderen entwicklungsumgebungen funktionieren soll, bleibt mir ein rätsel!
mr.escape
Die Funktionen der DLL sind C++ Funktionen z.B:
int __declspec(dllexport) __stdcall OpenDevice(BYTE DevNumber, LPCSTR DriverName, LPCSTR ID, LPCSTR KeyWord);
die DLL komuniziert doch dann mit den WIN API Funktionen damit man den Microcontroller den ich am USB angeschlossen hab ansprechen kann!?
Ist die *.cpp datei die quelle der DLL oder ist das nur eine kapselung in eine/mehrere VC++ MFC klasse(n)?
Anders gefragt, kann (bzw. könnte) man aus der *.cpp die DLL erzeugen, oder nur eine andere form der kommunikation (instanzieren von MFC basierenden klassen und aufruf der entspr. methode statt direkt die __stdcall C-funktionen der DLL zu verwenden) mit dieser.
mr.escape
Echt gehat das aus der cpp die DLL zu erzeugen!? Ich denk schon das die cpp die Quelle für die DLL ist da alle möglichen Funktionen in der cpp stehen z.B.
int __declspec(dllexport) __stdcall OpenDevice(BYTE DevNumber, char* DriverName, char* ID, char* KeyWord)
{
WORD (_stdcall *function)(BYTE, char *, char *, char *);
if (!(function = (WORD (_stdcall *)(BYTE, char *, char *, char *))GetProcAddress(m_hLibInstance, "OpenDevice")))
{
m_LastSystemError = GetLastError();
return FALSE;
}
char *s0 = ConvertStringToPascalDLL(DriverName);
char *s1 = ConvertStringToPascalDLL(ID);
char *s2 = ConvertStringToPascalDLL(KeyWord);
WORD retval = (*function)(DevNumber, PascalString(s0), PascalString(s1), PascalString(s2));
delete [] s0;
delete [] s1;
delete [] s2;
return (m_LastSystemError == 0);
}
Wie kann ich denn aus der cpp die DLL erzeugen?
Wenn tatsächlich alles erforderliche vorhanden ist (und nicht andere externe libs nötig sind, die binär in der bestehenden DLL vorhanden sind, aber nicht als source oder lib zur verfügung stehen), muss ein DLL-projekt angelegt und die *.cpp (wie auch die *.h) datei als bestandteil importiert werden (bei VC++ wäre das "Hinzufügen", "Vorhandenes Element hinzufügen ...").
Damit bekommt man auch die kleine import-lib für die DLL.
Wenn das möglich ist, ist aber auch eine direkte verwendung im eigentlichen projekt möglich, d.h. ohne DLL sondern direkt gelinkt (aka statisch).
mr.escape
Wenn das möglich ist, ist aber auch eine direkte verwendung im eigentlichen projekt möglich, d.h. ohne DLL sondern direkt gelinkt (aka statisch).
Wie geht das denn ohne DLL? wie kann ich dann die Funktionen ansprechen? Muß ich dann nur die cpp dem Projekt hinzufügen(Headerdatei benötige ich dann auch nicht oder?)? Hab hier nochmal den Code der cpp vieleicht kannst mir ein Beispiel machen!
// USB_Interface.cpp : Legt die Initialisierungsroutinen für die DLL fest.
//
#include "stdafx.h"
#include "USB_Interface.h"
//#include "CUSBInterface.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define BORLNDMM_DLL_NAME "borlndmm.dll"
#define AN21XX_DLL_NAME "an21xx.dll"
#define PascalString(s) (s+4)
static HINSTANCE m_hLibInstance = NULL;
static HINSTANCE m_hLibInstance2 = NULL;
static DWORD m_LastSystemError;
char *ConvertStringToPascalDLL(LPCSTR s)
{
UINT len = strlen(s);
char *s1 = new char[len+5];
memset(s1, '\0', len+5);
strcpy(s1+4, s);
*((DWORD *)s1) = len;
return s1;
}
BEGIN_MESSAGE_MAP(CUSB_InterfaceApp, CWinApp)
//{{AFX_MSG_MAP(CUSB_InterfaceApp)
// HINWEIS - Hier werden Mapping-Makros vom Klassen-Assistenten eingefügt und entfernt.
// Innerhalb dieser generierten Quelltextabschnitte NICHTS VERÄNDERN!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
int __declspec(dllexport) __stdcall OpenLib(void)
{ int success = 0;
CString LibName;
/*
LibName=BORLNDMM_DLL_NAME;
if ((m_hLibInstance2 = LoadLibrary(LibName)) == NULL)
{ AfxMessageBox("Error: Loading Library borlndmm.dll failed");
}
else
{ success +=1;
}
*/
LibName=AN21XX_DLL_NAME;
if ((m_hLibInstance = LoadLibrary(LibName)) == NULL)
{ AfxMessageBox("Error: Loading Library an21xx.dll failed");
}
else
{ success +=2;
}
return success; // 0:fail, 1/2: only 1st/2nd DLL loaded, 3: ok
}
int __declspec(dllexport) __stdcall CloseLib(void)
{ int success = 0;
CloseAllDevices();
if(m_hLibInstance != NULL)
{ if (FreeLibrary(m_hLibInstance)) // returs 0 if it fails
success += 1; // success !!
}
if(m_hLibInstance2 != NULL)
{ if (FreeLibrary(m_hLibInstance2))
success += 2;
}
return success; // 0:fail, 1/2: only 1st/2nd DLL unloaded, 3: ok
}
int __declspec(dllexport) __stdcall ReOpen(void)
{ int success = 0;
CloseLib();
success = OpenLib();
return success;
}
/////////////////////////////////////////////////////////////////////////////
// CUSB_InterfaceApp Konstruktion
CUSB_InterfaceApp::CUSB_InterfaceApp()
{
// ZU ERLEDIGEN: Hier Code zur Konstruktion einfügen
// Alle wichtigen Initialisierungen in InitInstance platzieren
OpenLib();
}
/////////////////////////////////////////////////////////////////////////////
// Das einzige CUSB_InterfaceApp-Objekt wird hier konstruiert
CUSB_InterfaceApp theApp;
int __declspec(dllexport) __stdcall OpenDevice(BYTE DevNumber, char* DriverName, char* ID, char* KeyWord)
{
WORD (_stdcall *function)(BYTE, char *, char *, char *);
if (!(function = (WORD (_stdcall *)(BYTE, char *, char *, char *))GetProcAddress(m_hLibInstance, "OpenDevice")))
{
m_LastSystemError = GetLastError();
return FALSE;
}
char *s0 = ConvertStringToPascalDLL(DriverName);
char *s1 = ConvertStringToPascalDLL(ID);
char *s2 = ConvertStringToPascalDLL(KeyWord);
WORD retval = (*function)(DevNumber, PascalString(s0), PascalString(s1), PascalString(s2));
delete [] s0;
delete [] s1;
delete [] s2;
return (m_LastSystemError == 0);
}
int __declspec(dllexport) __stdcall SetInterrupt (BYTE DevNumber,BYTE IntNum,BYTE STATE)
{
void (_stdcall *function)(BYTE,BYTE,BYTE);
if (!(function = (void (_stdcall *)(BYTE,BYTE,BYTE))GetProcAddress(m_hLibInstance, "SetInterrupt")))
{
m_LastSystemError = GetLastError();
return FALSE;
}
(*function)(DevNumber, IntNum, STATE);
m_LastSystemError = 0;
return (TRUE);
}
int __declspec(dllexport) __stdcall SetRefreshTime (long RefreshTime)
{
void (_stdcall *function)(LONG);
if (!(function = (void (_stdcall *)(LONG))GetProcAddress(m_hLibInstance, "SetRefreshTime")))
{
m_LastSystemError = GetLastError();
return FALSE;
}
(*function)(RefreshTime);
m_LastSystemError = 0;
return (TRUE);
}
Thanks
serc
Soweit ich das erkennen kann, dient dieser quellcode dazu, um die datei "an21xx.DLL" dynamisch (LoadLibrary/FreeLibrary/GetProcAddress) zu verwenden
int OpenDevice(BYTE DevNumber, char* DriverName, char* ID, char* KeyWord);
int SetInterrupt (BYTE DevNumber,BYTE IntNum,BYTE STATE);
int SetRefreshTime (long RefreshTime);
etc.
Zusätzlich ist noch eine stringübersetzung zwischen pascal und C für die parameterübergabe eingebaut (ConvertStringToPascalDLL/PascalString) die verwendung ist aber rätselhaft (strdup/free, new[]/delete[] ohne das voranstellen der länge o.ä. hätte es auch getan).
Die klasse CUSB_InterfaceApp dient dem "loadtime"-anbinden von "an21xx.dll" im konstruktor von "theApp". Eine freigabe im destruktor scheint aber zu fehlen und ein misserfolg kommt wohl auch nicht in frage (feedback nur visuell durch AfxMessageBox, was durch eine vorhandene variante ersetzt werden müsste).
Alle dies funktionen kann man auch direkt in seinem projekt unterbringen (u.a. durch weglassen von "__declspec(dllexport) __stdcall"), dafür eine extra mini-DLL zu erzeugen ist etwas merkwürdig.
Mit diesem link (unter "msvcrt.lib missing" einfach msvcrt durch AN21xx ersetzen) lässt sich aus der AN21xx.dll die fehlende datei AN21xx.lib (sowie *.exp) erzeugen. Ähnliches sollte auch für "Borland C++ Builder" möglich sein. Dann ist dieser wrapper (USB_Interface.cpp) nicht mehr nötig.
Hier steht z.b. beschrieben, wie man mit "dem Borland-Tool IMPLIB" eine passende import-lib für borland aus der vcc-import-lib (herstellung oben beschrieben, selbst probiert, scheint zu gehen) erzeugt.
mr.escape
Du schreibst, daß man alle diese Funktionen direkt in seinem Projekt ansprechen kann! Wie geht das denn? Kannst mal ein Beispiel machen!?
Ohne DLL? Muß ich da dann noch was einbinden?
Wenn das gehen würde mach ich am besten das, da ich mit dem anderen nicht klar komm!
Alle dies funktionen kann man auch direkt in seinem projekt unterbringen (u.a. durch weglassen von "__declspec(dllexport) __stdcall"), dafür eine extra mini-DLL zu erzeugen ist etwas merkwürdig.
Statt "USB_Interface.h" und "USB_Interface.dll" zu verwenden, kann man auch "USBDLL.h" und "AN21xx.dll" verwenden (mit einem
extern "C"
wie in "USB_Interface.h" "verfeinert" um C++ dekorationen zu vermeiden und der verwendung von "dllimport" statt "dllexport").
Was fehlt, ist eine import-lib, die aber für "USB_Interface.dll" ebenfalls fehlt. Da aber mit "USB_Interface.cpp" diese DLL nachbildbar ist, lässt sich die lib einfach erzeugen. Für "AN21xx.dll" lässt sich das mit den genannten mitteln (link1 und link2) erzeugen oder evtl. direkt (weil das eine borland DLL ist) aus "AN21xx.dll" mit borland-tools (hierzu kann ich nicht viel sagen).
Der aufruf der funktionen ist jeweils identisch, außer für "SetAllDisabled". Das taucht aber außer in "USB_Interface.h" nirgendwo auf und ist somit vermutlich überflüssig. Die funktionen "ReOpen" und "CloseLib" sind unnötig, denn diese betreffen das dynamische (runtime) laden der DLL und das wäre durch die loadtime anbindung per import-lib schon erledigt.
Eine probeweise verwendung der generierten import-lib in VC++ war nicht erfolgreich, weil bei der (erforderlichen) deklaration __stdcall der linker den importnamen so verändert, dass die funktion nicht gefunden wird, bei "_cdecl" hingegen der stackpointer beim aufruf falsch gesetzt wird. Hierzu näheres hier.
mr.escape
Hi!
Danke , erstmal, dass du aus meinem nicht ganz sinnvollem Geschwafel noch etwas herausgeholt hast (ich sollte nachts keine längeren beiträge mehr schreiben...). ;-)
Was mir durch den Kopf ging, ist gar nicht mehr in meiner Antwort gelandet: das ist doch eine USB-USB_Interface-Platine. Bei solchen Gerätn vermute ich, dass sie unter Windows mit Treibern geleifert werden, damit man sie nicht nur über eine bestimmte Entwicklungsumgebung ansteuern kann. Möglich, dass es spezielle DLLs für einzelne Umgebungen gibt, die das Ansteuern der auf der Platine untergebrachten Hardware erleichtern, aber ich frage mich, ob man das nicht auch mit den Standard,öglichkeiten (nachdem die notwendigen Treiber installiert sind) abwickeln kann.
Evtl. liegt der Fokus der Frage falsch: mir scheint es eher um das Problem "wie kann ich mit dem Borland C++ Builder die Interface-Platine ansteuern?", statt sich auf die allgemeine Frage zu beschränken "wie binde ich eine VC++ DLL in C++ Builder Projekte ein?" .
Wir wissen ja immer noch nicht, um was für Hardware es genau geht, möglicherweise gibt es spezialisierte Resourcen im Netz (Supportforen des Herstellers?), die hier wesendlich effektivere Unterstützung bieten können.
Bis dann
Andreas
Es handelt sich dabei um nen Controller von Cypress AN2131( befindet sich auf der USB-Inerface Platine) diesen will ich ansteuern!
Die Firma braintechnology bietet dazu Platinen an jedoch die Software DLL usw. vertreibt ein Karsten Böhme!
Die ganzen Funktionen für den Controller sind ja schon in der DLL mit diesen würd ich halt gern arbeiten!