wxDev-C++ 7.3.1.3: DLL in C (oder C++) erstellen; DLL-Funktion einbinden

BeFu

Grünschnabel
Hallo an alle Kundigen des Compilers wxDev-C++.

Ich möchte mit dem Compiler wxDev-C++ 7.3.1.3 DLL-Funktionen erstellen, die ich dann in anderen C(++) Programmen aufrufen kann.

Bis jetzt habe ich vergebens versucht eines der älteren DLL-Beispiele für den wxDec-C++ nach zu programmieren. Die brechen das Compilieren teilweise mit Syntax-Error ab; eventuell wurden MAKRO im Laufe der Entwicklung des wxDev-C++ geändert?

Ich würde mich freuen, wenn einer der Kundigen alle C- und Header-Dateien von einem einfach nach zu programmierendes DLL-Beispiel (DLL erstellen und DLL einbinden) hier ins Forum stellen würde. Das versuche ich dann mit dem wxDev-C++ 7.3.1.3 nach zu programmieren und nach zu vollziehen.

So ein aktualisiertes Beispiel mit allen C- und Header-Dateien ist sicher hilfreich für viele "Unkundige".

Ich freue mich auf Eure Antwort.

Schöne Grüße,


BeFu
P.S.: Die DLL-Funktion, z.B. double sub(double a, double b); , sollte möglich in ein Konsolenanwendung eingebunden werden, da ich ziemlich unerfahren in Windows-Programmierung bin. - Danke.

P.P.S.: C(++)-DLL-Funktionen sind teilweise als Wrapper-Funktionen für DLL-Funktionen von Anwendungen nötig, deren Parameter in LabVIEW weiter bearbeitet werden ... LabVIEW-Tutorien findet Ihr z.B. unter http://www.fu-net.de/lv/
 
Hallo Sheel,

sagst Du mir bitte, wie ich hier Dateien mit Quell-Code oder Screenshots davon hochladen kann?

Meine eben getippte Antwort ist im Nirwana gelandet. :-(

Schöne Grüße,

BeFu
 
Hi.

Da dein Quellcode wohl kaum sehr umfangreich ist, wäre es das einfachste und beste den Quellcode sowie die Fehlermeldungen einfach in deine Nachricht innerhalb von [code]...[/code], [c]...[/c] bzw. [code=cpp]...[/code] Tags einzubinden.

Gruß
 
Hallo deepthroat,

danke für Deinen Hinweis zur Einstellung "meines" C-Code. Im den Kommentaren des Code habe ich meine Fragen nummeriert. Nehmt bei Euren Antworten bitte Bezug auf diese Nummerierung.

Der Code von DLL und DLL Aufruf liegen bei mir in den Verzeichnissen

...\projects\DLL_test\ :

Code:
/* dll.h */
#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */


DLLIMPORT void HelloWorld (void);

/* 3.2. Muss nicht hier in dll.h die Deklaration von add2num() stehen? */
DLLEXPORT extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b);

#endif /* _DLL_H_ */

Code:
/*dllmain.c */
#include "dll.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

DLLIMPORT void HelloWorld ()    /* Standardmäßig von wxDev-C++ angelegt */
{                               /* 1. Wozu dient das? MassgeBox nur auf Windows-API möglich, oder? */          
    MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}

/*----- eigene DLL - Funktion aus CPPDLL-Tutorial von VitalDragon ---*/

BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
    /* Standardmäßig von wxDev-C++ angelegt */
    /* 2. Wozu dient der switch-Konstrukt? Müssen in den Switch-Cases DLL-Funktionen aufgerufen werden? */
    switch (reason)
    {
      case DLL_PROCESS_ATTACH:
        break;

      case DLL_PROCESS_DETACH:
        break;

      case DLL_THREAD_ATTACH:
        break;

      case DLL_THREAD_DETACH:
        break;
    }

    /* Returns TRUE on success, FALSE on failure */
    return TRUE;
}

extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b);
/* 3.1. Warum steht Deklaration von add2num() in Quellcode C-Datei, und nicht nur in dll.h? */
/* 3.2. steht in dll.h */
extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b)
{
    return a+b;
}; /* 4. Eigentlich ist ";" nach abschließender "}" doch nicht notwendig, oder? */




...\projects\DLL_Aufruf\ :

Code:
#include <stdio.h>
#include <stdlib.h>

/* #include "..\DLL_test\dll.h" */ 
/* Auskommentiert, da sonst DLL_Aufruf nicht startet mit Message "Invalid argument"     */
/* Das ist eigentlich klar, da ja das Compilieren der DLL mit Fehlermeldung abbricht    */
int main(int argc, char *argv[])
{
  double num1, num2, erg;
  
  num1= num2= erg= 0,0;
  printf("Bitte zwei Zahlen eingeben; diese werden addiert\n");
  printf("Bitte Zahl1 eingeben: ");
  scanf("%lf", &num1);
  printf("Bitte Zahl2 eingeben:");
  scanf(" %lf", &num2);
  /* 5. Wie rufe ich die DLL-Funktion "double add2num(double, double);" auf?            */
  /* 5.1. Da gibt es ja die Möglichkeit des so genannten statischen Aufrufs oder        */
  /* 5.5  des dynamischen Aufruf, oder?                                                 */
  /* erg= add2num(num1, num2);  <-- wo muss der Code mit __declspec (dllimport) stehen? */
  printf(" %lf + %lf= %lf\n\n", num1, num2, erg);
  system("PAUSE");	
  return 0;
}

Mein Code ist recht dürftig; die Programmierung von DLL und deren Einbindung in C bzw. C++ ist für mich eben noch ein große Frage.

Danke für Eure Hilfe.

Ich freue mich auf Eure Antwort.

Schöne Grüße,

BeFu
 
Hi

3.1 und 3.2: Man schreibt sowas normalerweise in die .h, ist aber in .c und .cpp auch möglich.
4: ; ist hier normalerweise nicht nötig, aber auch kein Fehler.

5, 5.1, 5.2: Der (auskommentierte) Aufruf ist schon in Ordnung.
Das declspec sollte wie gesagt normalerweise in der .h stehen,
du kannst es vor dem main aber auch einfügen.

Dynamisches Laden von bestimtmen Funktionen ist umständlicher,
hier aber wirklich nicht nötig.
 
Hallo sheel,

danke für Deine Antwort.

3.1. und 3.2: Funktions-Deklarationen
Code:
extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b);
stehen also auch bei DLLs in header-Dateien.

Die Funktionsdefinitionen wie
Code:
extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b)
{
    return a+b;
}
stehen dann in dllmain.c, oder?
6.1. Ist es bei DLL-Funktionen auch möglich, dass diese in jeweils eigenen *.c und *.h -Dateien definiert und deklariert werden?
6.2 Diese Funktionen müssen dann in dllmain.c aufgerufen werden, oder?

Mein Problem, dass der wxDev-C++ 7.3.1.3 das Compilieren der dllmain.c mit Syntax-Error in
Code:
extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b);
besteht noch immer. :-(
Daher habe ich in DLL_Aufruf.c
Code:
/* erg= add2num(num1, num2);  <-- wo muss der Code mit __declspec (dllimport) stehen? */
auskommentiert.

Ich würde mich freuen, wenn jemand hier C-Code (mit "meinen" Beispiel-Funktionen) hochlädt, der von wxDev-C++ 7.3.1.3 fehlerlos compiliert und gelinkt wird, so dass ich das richtige Programmieren von C-DLL mit dem Compiler wxDev-C++ 7.3.1.3 programmiert wird.

Danke für Eure Hilfe.

Schöne Grüße,

BeFu
 
Hi.

Bitte poste die vollständigen Fehlermeldungen.

Außerdem wäre es besser du postest deinen konkreten Code ohne Kommentare (die stehen doch jetzt nur hier und nicht in deinen Dateien drin, richtig?). Dann kann man auch besser erkennen welche Zeile der Compiler anmeckert.

Der Fehler dürfte wohl sein, das du das Makro DLLEXPORT nirgends definiert hast, du hättest DLLIMPORT schreiben müssen (dll.h Zeile 15).

Und das BUILDING_DLL Makro hast du in dem DLL Projekt definiert, ja?

Gruß

PS: wxDevC++ ist kein Compiler, es ist eine IDE. Du verwendest den MinGW GCC als Compiler.
 
Zuletzt bearbeitet:
Hallo deepthroat,

danke für Deinen Hinweis, dass
1. wxDEVC++ die IDE für den Compiler MinGW GCC ist und
2. ich BUILDING_DLL am Ende von dll.h definiere, damit der Compiler weiss, dass die Definition der DLL-Funktionen abgeschlossen ist.

Nachfolgend der Code der DLL-Funktion ad2num(), der nun fehlerlos compiliert wird. Das DLL-Projekt habe ich als C-Projekt definiert; somit ist ist das casten auf "C" überflüssig, und verursacht SYNTAX ERROR.

..\projects\dll_test\dll.h:
Code:
#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */

DLLIMPORT void HelloWorld (void); 

/* Deklaration der DLL-Funktion add2num() :*/
extern __declspec(dllexport) __stdcall double add2num(double a, double b);

#define BUILDING_DLL 1  /* All functions in DLL are created */
#endif /* _DLL_H_ */

..\projects\dll_test\dllmain.c:
Code:
/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

DLLIMPORT void HelloWorld ()    /* Standardmäßig von wxDev-C++ angelegt */
{                               /* 1. Wozu dient das? MassgeBox nur auf Windows-API möglich, oder? */          
    MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}

/*----- eigene DLL - Funktion aus CPPDLL-Tutorial von VitalDragon ---*/

BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
    /* Standardmäßig von wxDev-C++ angelegt */
    /* 2. Wozu dient der switch-Konstrukt? Müssen in den Switch-Cases DLL-Funktionen aufgerufen werden? */
    switch (reason)
    {
      case DLL_PROCESS_ATTACH:
        break;

      case DLL_PROCESS_DETACH:
        break;

      case DLL_THREAD_ATTACH:
        break;

      case DLL_THREAD_DETACH:
        break;
    }

    /* Returns TRUE on success, FALSE on failure */
    return TRUE;
}

/* extern "C" __declspec(dllexport) __stdcall double add2num(double a, double b);   */
/* extern "C" ergibt Syntax Error, da ich in wxDevC++ eingestellt habe, eine DLL    */
/* in C zu programmieren; 
/* 3. "C" ist nur notwendig,wenn DLL in C++ programmiert werden, damit Compiler die */
/* Funktionsnamen nicht verstümmelt, oder?                                          */

/* Hier die Definition der DLL-Funktion add2num() */
extern __declspec(dllexport) __stdcall double add2num(double a, double b)
{
    return a+b;
}

Und hier der Code von main.c; darin ist die DLL-Funktion add2num() nicht bekannt und Da der Compiler liefert folgende Fehler:
[Linker Error] undefined reference to `add2num@16'
ld returned 1 exit status
C:\Program Files\Dev-Cpp\projects\DLL_Aufruf\Makefile.win [Build Error] [Output/MingW/DLL_Aufruf.exe] Error 1

..\projects\dll_Aufruf\main.c:
Code:
#include <stdio.h>
#include <stdlib.h>

#include "..\DLL_test\dll.h" /* 4. Damit müsste in main.c doch die DLL-Funktion         */
                             /* double add2num(double a, double b) bekannt sein?        */

int main(int argc, char *argv[])
{
  double num1, num2, erg;
  
  num1= num2= erg= 0,0;
  printf("Bitte zwei Zahlen eingeben; diese werden addiert\n");
  printf("Bitte Zahl1 eingeben: ");
  scanf("%lf", &num1);
  printf("Bitte Zahl2 eingeben:");
  scanf(" %lf", &num2);
  /* 4. Wie rufe ich die DLL-Funktion "double add2num(double, double);" auf?            */
  /* In dll.h habe ich ja BUILDING_DLL definiert, so dass in main.c DLLIMPORT aktiv     */
  /* sein müsste                                                                        */
  
erg= add2num(num1, num2); 
  printf(" %lf + %lf= %lf\n\n", num1, num2, erg);
  system("PAUSE");	
  return 0;
}

Bezieht Euch bei Euren Antworten bitte wieder auf die Nummern meiner im Quellcode gestellten Fragen.

Viele Grüße,

BeFu
 
Hi.
2. ich BUILDING_DLL am Ende von dll.h definiere, damit der Compiler weiss, dass die Definition der DLL-Funktionen abgeschlossen ist.
Das ist unsinnig. Du prüfst den Wert von BUILDING_DLL in dll.h Zeile 4, da spielt es keine Rolle ob du den Wert später noch änderst.

So wie du es machst (mit #if) mußt du in dem DLL Projekt den Wert von BUILDING_DLL (z.B. in den Projekteinstellungen) auf einen Wert verschieden von 0 setzen. Und in dem Projekt wo du die DLL nutzen willst mußt du den Wert auf 0 setzen.
Nachfolgend der Code der DLL-Funktion ad2num(), der nun fehlerlos compiliert wird. Das DLL-Projekt habe ich als C-Projekt definiert; somit ist ist das casten auf "C" überflüssig, und verursacht SYNTAX ERROR.
Jetzt exportierst du die Funktion in jedem Fall. Du solltest mit DLLIMPORT arbeiten, damit die Funktion exportiert wird wenn du die DLL baust und importiert wird wenn du die DLL nutzt.
..\projects\dll_test\dllmain.c:
Code:
DLLIMPORT void HelloWorld ()    /* Standardmäßig von wxDev-C++ angelegt */
{                               /* 1. Wozu dient das? MassgeBox nur auf Windows-API möglich, oder? */          
    MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}

/*----- eigene DLL - Funktion aus CPPDLL-Tutorial von VitalDragon ---*/

BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
    /* Standardmäßig von wxDev-C++ angelegt */
    /* 2. Wozu dient der switch-Konstrukt? Müssen in den Switch-Cases DLL-Funktionen aufgerufen werden? */
    switch (reason)
    {
      case DLL_PROCESS_ATTACH:
        break;

      case DLL_PROCESS_DETACH:
        break;

      case DLL_THREAD_ATTACH:
        break;

      case DLL_THREAD_DETACH:
        break;
    }

    /* Returns TRUE on success, FALSE on failure */
    return TRUE;
}
zu 1) es ist ein Beispiel damit du siehst wie man DLL Funktionen implementieren kann.
zu 2) es ist ein Beispiel damit man sieht wie man die spezielle DllMain Funktion verwenden kann. Das switch demonstriert die verschiedenen Gründe wann/warum die DllMain aufgerufen wurde. Man muss keine DllMain definieren.

Und hier der Code von main.c; darin ist die DLL-Funktion add2num() nicht bekannt und Da der Compiler liefert folgende Fehler:
[Linker Error] undefined reference to `add2num@16'
ld returned 1 exit status
C:\Program Files\Dev-Cpp\projects\DLL_Aufruf\Makefile.win [Build Error] [Output/MingW/DLL_Aufruf.exe] Error 1

..\projects\dll_Aufruf\main.c:
Code:
#include <stdio.h>
#include <stdlib.h>

#include "..\DLL_test\dll.h" /* 4. Damit müsste in main.c doch die DLL-Funktion         */
                             /* double add2num(double a, double b) bekannt sein?        */
zu 4) nein, hab ich ja schon erklärt. Hast du denn die Import-Bibliothek auch zu deinem Projekt hinzugelinkt?

Bitte verwende für C Code die [c]..[/c] Tags. Danke.

Gruß

PS: wxDev-C++ erzeugt doch ein prima Gerüst für eine DLL. Du mußt doch nur den Namen und Parameter der Funktion HelloWorld ändern und alles ist gut. Evlt. solltest du das einfach nochmal probieren.
 

Neue Beiträge

Zurück