DLL für ProfiLab erstellen !?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
The_Dark_Zim-.-
Beiträge: 372
Registriert: 18.03.2008 16:53

DLL für ProfiLab erstellen !?

Beitrag von The_Dark_Zim-.- »

Hey Ho
ich muss eine DLL erstellen für die Software ProfiLab. Die will ein paar Sachen haben die ich nicht so ganz hin bekomme.
Hier die Beschreibung aus der Hilfe:
  • Delphi: Procedure Calculate(PInput,POutput,PUser: PDLLParams);
    C++: void _stdcall CCalculate(double *PInput, double *POutput, double *PUser)
    Die ist die zentrale Berechnungsroutine Ihres DLL-Bauteils, die die Funktion des Bauteils
    definiert. Mit den Parametern PINPUT, POUTPUT und PUSER bekommt die Routine drei
    Zeigervariablen (Pointer) übergeben die folgende Funktion haben:
    l
    Der Pointer PINPUT zeigt auf einen Speicherbereich, der dazu dient die Eingangswerte des
    mk:@MSITStore:C:\Programme\ProfiLab-Expert40\ProfiLab40.CHM::/Dllimport.html 20.08.2010
    DLL-Import
    l
    l
    Seite 2 von 4
    Bauteils an die DLL zu übergeben.
    Der Pointer POUTPUT zeigt auf einen Speicherbereich, der dazu dient die berechneten
    Ausgangswerte der DLL an das Bauteil zurückzugeben.
    Der Pointer PUSER stellt einen Pointer auf einen Speicherbereich zur Verfügung, in dem
    die DLL eigene (lokale) Werte speichern kann. Hintergrund: Variablen, die die DLL selbst
    deklariert sind globale Variablen. Werte die in diesen Variablen gespeichrt werden,
    würden sich gegenseitig überschreiben, wenn man dieselbe DLL mehr als einmal in einem
    ProfiLab-Projekt verwendet. Um lokale Werte speichern zu können, stellt ProfiLab der DLL
    den lokalen Speicherbereich zur Verfügung, auf den PUSER zeigt. (Alternativ kann man
    auch Variablen in der DLL selbst deklarieren. Dann muß man die DLL aber mehrfach unter
    verschiedenen Dateinamen speichern und importieren, um sie mehrfach in einem
    ProfiLab-Projekt verwenden zu können.)
    Alle drei Pointer PINPUT, POUTPUT und PUSER zeigen jeweils auf einen Speicherbereich in dem
    100 Variablen vom Typ EXTENDED in einem Array abgelegt sind. Die Pointer sind vom Typ
    PDLLParams, dessen Deklaration in Delphi so aussieht:
    type TDLLParams = array[0..100] of extended;
    PDLLParams = ^TDLLParams;
    In C++ wird dieser Speicherbereich z.B. als (double *PInput) übergeben.
    Die Extended-Variablen des Pointers PINPUT enthalten die Eingangszustände des Bauteils. Auf
    den Wert eines Eingangs des Bauteils können Sie wie folgt zugreifen:
    PInput^[0] enthält den numerischen Eingangswert des 1. Eingangs,
    PInput^[1] enthält den numerischen Eingangswert des 2. Eingangs, usw.
    Die Extended-Variablen des Pointers POUTPUT nehmen die Ausgangszustände des Bauteils auf.
    Um den Wert der Ausgänge des Bauteils zu setzen, benutzen Sie:
    POutput^[0] nimmt den numerischen Ausgangswert des 1. Ausgangs auf,
    POutput^[1] nimmt den numerischen Ausgangswert des 2. Ausgangs, usw.
    Entsprechend können Sie mit PUser^[0] bis PUser^[99] frei verwenden um eigene Werte zu
    speichern. Die Werte in diesen Variablen werden von ProfiLab mit in der Projektdatei
    abgespeichert, und sind so beim nächsten Laden des Projekts wieder verfügbar. Die Variable
    PUser^[100] wird von ProfiLab gesetzt, und enthält die Nummer des DLL-Bauteils in Ihrem
    Projekt: 1 für DLL1, 2 für DLL2, usw.
    Die Routine Calculate wird im RUN-Modus ständig von ProfiLab aufgerufen, um neue
    Eingangswerte zu übergeben und neue Ausgangswerte für das Bauteil abzurufen. Diese Routine
    muss daher unbedingt zeitoptimiert programmiert werden, und sollte auf keinen Fall Pausen (in
    Form von SLEEP-Befehlen oder Warteschleifen) enthalten. Nach dem Abfragen der
    Eingangswerte und dem Setzen der Ausgangswerte sollte die Routine so schnell wie möglich
    wieder verlassen werden. Die Rechenzeit für die Routine wirkt sich unmittelbar auf die
    Simulationsfrequenz von ProfiLab aus.
Und hier ein Beispiel in C++
  • Beispiel DLL-Quelltext (C++)
    Die compilierte DLL finden Sie im Order BEISPIELE (C_COUNTER.DLL).
    // Defines a simple 8 bit binary counter component for ProfiLab
    #include <windows.h>
    //---------------------------------------------------------------------------
    #pragma argsused
    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    {
    return 1;
    }
    //---------------------------------------------------------------------------
    #include <string.h>
    #include <stdio.h>
    #include <stddef.h>
    //Index for input variables
    const CLK = 0;
    const RST = 1;
    //Index for user variables
    const CLK_OLD = 0;
    const RST_OLD = 1;
    const COUNT = 2;
    unsigned char inputs = 2; //two inputs
    unsigned char outputs = 8; //eight outputs
    //Exported functions...
    extern "C" __declspec(dllexport)
    extern "C" __declspec(dllexport)
    extern "C" __declspec(dllexport)
    Channel, unsigned char *Name);
    extern "C" __declspec(dllexport)
    Channel, unsigned char *Name);
    extern "C" __declspec(dllexport)
    *POutput, double *PUser);
    extern "C" __declspec(dllexport)
    *POutput, double *PUser);
    extern "C" __declspec(dllexport)
    *POutput, double *PUser);
    extern "C" __declspec(dllexport)
    unsigned char _stdcall NumOutputs();
    unsigned char _stdcall NumInputs();
    void _stdcall GetInputName(unsigned char
    void _stdcall GetOutputName(unsigned char
    void _stdcall CCalculate(double *PInput, double
    void _stdcall CSimStart(double *PInput, double
    void _stdcall CSimStop(double *PInput, double
    void _stdcall CConfigure(double *PUser);
    //return number of input channels...
    unsigned char _stdcall NumInputs()
    {
    return inputs;
    }
    //return number of output channels...
    unsigned char _stdcall NumOutputs()
    {
    return outputs;
    }
    //return name for each input...
    void _stdcall GetInputName(unsigned char Channel, unsigned char *Name)
    {
    if (Channel == 0)
    strcpy(Name, "CLK"); //Name input 0
    else
    mk:@MSITStore:C:\Programme\ProfiLab-Expert40\ProfiLab40.CHM::/BeispielDllq...
    20.08.2010
    Beispiel DLL-Quelltext (C++)
    Seite 2 von 3
    strcpy(Name, "RST"); //Name input 1
    }
    //return name for each output...
    void _stdcall GetOutputName(unsigned char Channel, unsigned char *Name)
    {
    sprintf(Name, "Q%i", Channel); // Name outputs Q0..Q7
    }
    //reset counter on start...
    void _stdcall CSimStart(double *PInput, double *POutput, double *PUser)
    {
    int i;
    PUser[COUNT] = 0;
    for (i = 0; i < outputs; i++)
    POutput = 0;
    //RESET counter
    //All outputs low
    }
    //check inputs and set outputs while running...
    void _stdcall CCalculate(double *PInput, double *POutput, double *PUser)
    {
    int i, iCount;
    if (PInput[RST] < 2.5)
    // RST input LOW?
    {
    if (PUser[RST_OLD] > 2.5) //Falling edge of RST?
    {
    PUser[COUNT] = 0; //RESET counter
    for (i = 0; i < outputs; i++) //all outputs low
    POutput = 0;
    }
    }
    PUser[RST_OLD] = PInput[RST]; //remember RST for next call
    if (PInput[CLK] > 2.5) //clock input high?
    {
    if (PUser[CLK_OLD] < 2.5) //rising edge of CLK?
    {
    PUser[COUNT] += 1; //increase counter
    if (PUser[COUNT] > 255)
    PUser[COUNT] = 0; //check
    overflow, byte limit!
    iCount = PUser[COUNT]; //convert double to integer
    (byte)
    //Set corresponding outputs with bits set in byte
    iCOUNT...
      if ((iCount & 1))   POutput[0] = 5; else POutput[0] = 0;
                            if ((iCount & 2))   POutput[1] = 5; else POutput[1] = 0;
                            if ((iCount & 4))   POutput[2] = 5; else POutput[2] = 0;
                            if ((iCount & 8))   POutput[3] = 5; else POutput[3] = 0;
                            if ((iCount & 16))  POutput[4] = 5; else POutput[4] = 0;
                            if ((iCount & 32))  POutput[5] = 5; else POutput[5] = 0;
                            if ((iCount & 64))  POutput[6] = 5; else POutput[6] = 0;
                            if ((iCount & 128)) POutput[7] = 5; else POutput[7] = 0;
                }
          }
          PUser[CLK_OLD] = PInput[CLK]; // remember CLK for next call
    }
     
    // called when project is stopped...
    void _stdcall CSimStop(double *PInput, double *POutput, double *PUser)
    {
    //nothing to do...
    }
     
    //called when button CONFIGURE is pressed in dialogue...
    void _stdcall CConfigure(double *PUser)
    {
          MessageBox(0,"Nothing to configure", "Configure", 0);
    }
     
    //DONE!!!


Danke an jeden der hilft ;)
PB: 5.xx LTS x86/x64 | WIN: 10 Pro x64, Linux Mint x64
Benutzeravatar
DrShrek
Beiträge: 1970
Registriert: 08.09.2004 00:59

Re: DLL für ProfiLab erstellen !?

Beitrag von DrShrek »

Ho Hey,

Dir ist sicher klar warum Dir keiner antwortet, gell?
Übrigends... Da gibt es auch sowas wie Format Knöpfe: Ich glaube es steht was drauf was sich liest wie: 'Code'.

Auch immer dankbar für jede Hilfe.
Shrek
Siehste! Geht doch....?!
PB*, *4PB, PetriDish, Movie2Image, PictureManager, TrainYourBrain, ...
- chris -
Beiträge: 195
Registriert: 24.08.2005 19:52
Wohnort: Stadtallendorf

Re: DLL für ProfiLab erstellen !?

Beitrag von - chris - »

Hier mein erster Versuch, eine DLL für ProfiLab:

Code: Alles auswählen


; test01.pb

EnableExplicit

#Inputs  = 2
#Outputs = 2

Structure sDLLParams
  DLLParam.d[100]
EndStructure

; return number of input channels...
ProcedureDLL.b NumInputs()

  ProcedureReturn #Inputs
EndProcedure

; return number of output channels...
ProcedureDLL.b NumOutputs()

  ProcedureReturn #Outputs
EndProcedure

; return name for each input...
ProcedureDLL GetInputName(Channel.b, *Name.i)

  Protected GetInputName.s

  If Channel = 0
    GetInputName = "E1"
  ElseIf Channel = 1
    GetInputName = "E2"
  Else
    GetInputName = "U"
  EndIf

  PokeS(*Name, GetInputName, -1, #PB_Ascii)

EndProcedure

; return name for each output...
ProcedureDLL GetOutputName(Channel.b, *Name.i)

  Protected GetOutputName.s

  If Channel = 0
    GetOutputName = "A1"
  ElseIf Channel = 1
    GetOutputName = "A2"
  Else
    GetOutputName = "U"
  EndIf

  PokeS(*Name, GetOutputName, -1, #PB_Ascii)

EndProcedure

; check inputs and set outputs while running...
ProcedureDLL CCalculate(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  Protected in1.d, in2.d, out1.d, out2.d

  in1 = *PInput\DLLParam[0]
  in2 = *PInput\DLLParam[1]
  
  out1 = in1
  out2 = in2
  
  *POutput\DLLParam[0] = out1
  *POutput\DLLParam[1] = out2

EndProcedure

; called when project is started...
ProcedureDLL CSimStart(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  ; nothing to do...

EndProcedure

; called when project is stopped...
ProcedureDLL CSimStop(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  ; nothing to do...

EndProcedure

; called when button CONFIGURE is pressed in dialogue...
ProcedureDLL CConfigure(*PUser.sDLLParams)

  MessageRequester("Configure", "Nothing to configure")

EndProcedure

Zuletzt geändert von - chris - am 24.08.2010 19:25, insgesamt 3-mal geändert.
PB v5.72 x86/x64
Windows 10 Pro 64bit
- chris -
Beiträge: 195
Registriert: 24.08.2005 19:52
Wohnort: Stadtallendorf

Re: DLL für ProfiLab erstellen !?

Beitrag von - chris - »

Hier mein zweiter Versuch, eine DLL für ProfiLab mit EINSTELLUNGEN..:

Code: Alles auswählen


; test02.pb

EnableExplicit

#Inputs  = 1
#Outputs = 6

Structure sDLLParams
  DLLParam.d[100]
EndStructure

; return number of input channels...
ProcedureDLL.b NumInputs()

  ProcedureReturn #Inputs
EndProcedure

; return number of ouput channels...
ProcedureDLL.b NumOutputs()

  ProcedureReturn #Outputs
EndProcedure

; return name for each input...
ProcedureDLL GetInputName(Channel.b, *Name.i)

  Protected GetInputName.s

  If Channel = 0
    GetInputName = "E1"
  Else
    GetInputName = "U"
  EndIf

  PokeS(*Name, GetInputName, -1, #PB_Ascii)

EndProcedure

; return name for each output...
ProcedureDLL GetOutputName(Channel.b, *Name.i)

  Protected GetOutputName.s

  If Channel = 0
    GetOutputName = "A1"
  ElseIf Channel = 1
    GetOutputName = "A2"
  ElseIf Channel = 2
    GetOutputName = "A3"
  ElseIf Channel = 3
    GetOutputName = "A4"
  ElseIf Channel = 4
    GetOutputName = "A5"
  ElseIf Channel = 5
    GetOutputName = "A6"
  Else
    GetOutputName = "U"
  EndIf

  PokeS(*Name, GetOutputName, -1, #PB_Ascii)

EndProcedure

; check inputs and set outputs while running...
ProcedureDLL CCalculate(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  Protected in1.d
  Protected out1.d, out2.d, out3.d, out4.d, out5.d, out6.d

  in1 = *PInput\DLLParam[0]

  out1 = in1 * 1.0
  out2 = in1 * 2.0
  out3 = in1 * 3.0
  out4 = in1 * 4.0

  out5 = *PUser\DLLParam[0]
  out6 = *PUser\DLLParam[1]

  *POutput\DLLParam[0] = out1
  *POutput\DLLParam[1] = out2
  *POutput\DLLParam[2] = out3
  *POutput\DLLParam[3] = out4

  *POutput\DLLParam[4] = out5
  *POutput\DLLParam[5] = out6

EndProcedure

; called when project is started...
ProcedureDLL CSimStart(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  ; nothing to do...

EndProcedure

; called when project is stopped...
ProcedureDLL CSimStop(*PInput.sDLLParams, *POutput.sDLLParams, *PUser.sDLLParams)

  ; nothing to do...

EndProcedure

; called when button CONFIGURE is pressed in dialogue...
ProcedureDLL CConfigure(*PUser.sDLLParams)

  ;MessageRequester("Configure", "Nothing to configure")

  Protected Event.i, EventGadget.i, EventType.i, EventWindow.i
  Protected quit.i, out5.d, out6.d

  If OpenWindow(0, 434, 196, 205, 170, "Configure", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)

    StringGadget(0, 40, 20, 125, 30, "")
    StringGadget(1, 40, 60, 125, 30, "")
    ButtonGadget(2, 40, 105, 50, 40, "OK")
    
    out5 = *PUser\DLLParam[0]
    out6 = *PUser\DLLParam[1]
    
    SetGadgetText(0, StrD(out5))
    SetGadgetText(1, StrD(out6))
    
    Repeat

      Event       = WaitWindowEvent()
      EventGadget = EventGadget()
      EventType   = EventType()
      EventWindow = EventWindow()

      Select Event

        Case #PB_Event_Gadget

          If EventGadget = 0

          ElseIf EventGadget = 1

          ElseIf EventGadget = 2

            out5 = ValD(GetGadgetText(0))
            out6 = ValD(GetGadgetText(1))
            
            *PUser\DLLParam[0] = out5
            *PUser\DLLParam[1] = out6

            quit = 1

          EndIf

        Case #PB_Event_CloseWindow

          quit = 1

      EndSelect

    Until quit = 1

    CloseWindow(0)

  EndIf

EndProcedure

PB v5.72 x86/x64
Windows 10 Pro 64bit
Antworten