Creare DLL

Aperto da Birbante, 12 Novembre 2012, 22:57:24

Discussione precedente - Discussione successiva

0 Utenti e 2 Visitatori stanno visualizzando questa discussione.

Birbante

Salve a tutti sono nuovo del forum e avrei bisogno di una mano su C++ come creare una DLL con Code Blocks.
Questa DLL deve avere queste caratteristiche poichè poi dovrò richiamarla da un'altro software.
Le caratteristiche che mi chiede il tipo di software che sto usando sono queste:


This component offers a programming interface, which makes it possible to create your own ProfiLab components, for example to control self-made hardware devices, etc.
For that purpose you need a programming language, that allows you to compile DLL-files
(Dynamic Link Libraries), and you need some programming experience, as well.
Programming your own component, you have to meet some requirements of ProfiLab.
For example your DLL must export certain functions, that define the numbers of component inputs and outputs, the pin names and the internal function of the component.
  The following function are necessary for a component. The modified C++ versions use DOUBLE instead of EXTENDED and PCHAR instead of STRING.
  Delphi: function NumInputs: Byte;
C++: unsigned char _stdcall NumInputs()
alternative:
Delphi: function NumInputsEx(PUser: PDLLParams): Byte;
C++: unsigned char _stdcall CNumInputsEx(double *PUser)
The result of this function must return a byte value that defines the number of inputs of your component. The extended function type NumInputsEx is useful, if the number of inputs depends on configuration data stored in PUser.
  Delphi: function NumOutputs: Byte;
C++: unsigned char _stdcall NumOutputs()
alternative:
Delphi: function NumOutputsEx(PUser: PDLLParams): Byte;
C++: unsigned char _stdcall CNumOutputsEx(double *PUser)
The result of this function must return a byte value that defines the number of outputs of your component. The extended function type NumOutputsEx is useful, if the number of outputs depends on configuration data stored in PUser.
  Delphi: function InputName(Channel: Byte): ShortString;
void _stdcall GetInputName(unsigned char Channel, unsigned char *Name)
The result of this function must deliver a short text for the pin description for each input pin (channel) of your component. ProfiLab calls this function for each input pin, to request the corresponding description. The parameter CHANNELS identifies the pin and runs from 0 to NumInputs-1.
  Delphi: function OutputName(Channel: Byte): ShortString;
C++: void _stdcall GetOutputName(unsigned char Channel, unsigned char *Name)
The result of this function must deliver a short text for the pin description for each output pin (channel) of your component. ProfiLab calls this function for each output pin, to request the corresponding description. The parameter CHANNELS identifies the pin and runs from 0 to NumOutputs-1.
  Delphi: Procedure Calculate(PInput,POutput,PUser: PDLLParams);
C++: void _stdcall CCalculate(double *PInput, double *POutput, double *PUser)
This is the main calculation procedure of your component, which defines how your component works. The procedure parameters PINPUT, POUTPUT and PUSER offer three pointer variables with the following function:
 
  • The pointer PINPUT points to a memory area, in which input values are stored, so that the DLL can access the input values of the component.
  • The pointer POUTPUT points to a memory area, in which output values are stored, so that the DLL can set the output values of the component.
  • The pointer PUSER points to a memory area, where the DLL can store its own (local) values. Background: Variables defined in the DLL are global variables. Values stored to global variables will overwrite each other, if a DLL component is used more than once in a ProfiLab project. To have local variables available, ProfiLab hands out the pointer PUSER to the DLL, so that the DLL can store local data in the memory area that PUSER points to.
If you don´t want to use PUSER, but you need to declare variables in the DLL that are meant to be local (for components that are used more than once in a ProfiLab project), you can rename the DLL file and import it in ProfiLab with different filenames, as well.
  Each of the three pointers PINPUT, POUTPUT and PUSER points to an array of 100 EXTENDED variables. All three pointer are declared as type PDLLParams. The declaration in Delphis is as follows:
  type TDLLParams = array[0..100] of extended;
    PDLLParams = ^TDLLParams;
  C++ function types hand out this kind of memory pointer as (double *PInput) parameter for example.
  The array of PINPUT offers the input values of the component. The input values can be accessed as follows:
  PInput^[0] contains the numeric value of the first input,
PInput^[1] contains the numeric value of the second input, and so on...
  The array of POUTPUT offers the output values of the component. The output values can be set as follows:
  POutput^[0] must be set with the numeric value for the first output,
POutput^[1] must be set with the numeric value for the second output, and so on...
  PUser^[0] to PUser^[99] can be used to store numeric user values. The values of these variables are saved in the ProfiLab project file, so that values are available agein, when the project is loaded next time. The variable PUser^[100] is set by ProfiLab and contains the number of the DLL component: 1 fo DLL1, 2 for DLL2, and so on.
  The procedure CALCULATE is called repeatedly while ProfiLab is in RUN mode, to hand out new input values to the DLL and to request new output values from the DLL. This means that this procedure must be programmed as short as possible, and must not contain any pauses (WAIT loops or SLEEP commands) that waste time. After reading input values and setting new output vaues this routine should be terminated as soon as possible. The time spent in this procedure will directly influence the simulation frequency of ProfiLab.
  Delphi: Procedure CalculateEx(PInput,POutput,PUser: PDLLParams; PStrings: PStringParams);
C++: void _stdcall CCalculateEx(double *PInput, double *POutput, double *PUser; StringParam PStrings)
This method was introduced to allow string processing with DLL´s. It may be used as alternative for CALCULATE. Parameter PSTRINGS were added for interfacing string data. Its Delphi delclaration is as follows:
  type TStringParams = array[0..100] of PChar;
    PStringParams = ^TStringParams;
  Each input/output (max. 100) has a null-terminated character pointer (PChar) assigned, which points to a memory space that is provided by ProfiLab. Right before ProfiLab enters the method, data is fetched from the $inputs. After leaving the method data is handed out through the $outputs. It is not distinguished between inputs and outputs. This means that Input 0 and Output 0 for example share the same PChar. To make a pin become a string input or string output its pin name must be declared with a leading '$' character. Examples for string processing with DLL´s and ProfiLab are available.
  Delphi: Procedure SimStart(PInput,POutput,PUser: PDLLParams);
C++: void _stdcall CSimStart(double *PInput, double *POutput, double *PUser)
This procedure is called once, when the ProfiLab project enters the RUN mode, and can be used to initialize DLL variables, etc. The parameters have been explained before.
  Delphi: Procedure SimStop(PInput,POutput,PUser: PDLLParams);
C++: void _stdcall CSimStop(double *PInput, double *POutput, double *PUser)
This procedure is called once, when RUN mode is terminated, and can be used to close open files, etc. The parameters have been explained before.
  Delphi: Procedure Configure(UserValues: PDLLParam);
C++: void _stdcall CConfigure(double *PUser)
As soon as your DLL exports this procedure, the button CONFIGURE... in the property dialogue of the component is enabled. With a click on this button, ProfiLab will jump to your CONFIGURE procedure, where you can add your own setup dialogue for your DLL.
  These very few routines make it possible to program any ProfiLab component you have in mind. For example you could program hardware components that control special hardware devices, or create components that execute complex calculations.
If you want to program a component with digital outputs, simply set the numeric output vaules to 5 for HIGH levels, or to 0 for LOW levels. Numeric inputs higher than 2.5 should be interpreted as HIGH levels, numeric inputs lower then 2,5 as LOW leves.
  Your compiled DLL file can be loaded in the property dialogue of the component. All imported functions and procedures are listed in the dialogue. The component will then appear in the circuit as it is defined in the DLL. To be conform with C-Compiler conventions, names of functions and procedure may begin with an underline character _ as well. For example _SimStart instead of SimStart.
  Compiling your own DLL project make sure that the linker option "Dynamic RTL" is disabled. Otherwise the DLL can not be loaded on systems without installed C++ environment.


Questo è un esempio di programma realizzato con tali caratteritiche, ma ci sto capendo ben poco e vorrei che qualcuno possa darmi delle spiegazioni su come creare come prova una semplice somma DLL con le caratteristiche sopra menzionate.

Ecco un esempio:


//DLL as example
//created with DEV-CPP 4.9.9.2
// definition of inputs
unsigned char num_inputs=4;
const unsigned char I0=0;
const unsigned char I1=1;
const unsigned char I2=2;
const unsigned char I3=3; nm
// definition of outputs
unsigned char num_outputs=4;
const unsigned char Q0=0;
const unsigned char Q1=1;
const unsigned char Q2=2;
const unsigned char Q3=3;
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <math.h>
#include <errno.h>
using namespace std;
//Extern &quot;C&quot; declare to compile external
#define DLLEXPORT extern&quot;C&quot; __declspec(dllexport)
int WINAPI DLLMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szComdLine, int iCmdShow);
// Function PROFILAB, read num inputs
DLLEXPORT unsigned char _stdcall NumInputs()
{
  return num_inputs;
}
 
// Function PROFILAB, read num outputs
DLLEXPORT unsigned char _stdcall NumOutputs()
{
  return num_outputs;
}
 
// Function PROFILAB, read names of inputs
DLLEXPORT void _stdcall GetInputName(unsigned char Number, char *Name)
{
  switch(Number)
  {
     case I0: {strcpy(Name,&quot;I0&quot ;); break;} // name input 0
     case I1: {strcpy(Name,&quot;I1&quot ;); break;} // name input 1
     case I2: {strcpy(Name,&quot;I2&quot ;); break;} // name input 2
     case I3: {strcpy(Name,&quot;I3&quot ;); break;} // name input 3
     // case 4,5 ... : next names ...
     default:;
  }
}
 
// Function PROFILAB, read names of outputs
DLLEXPORT void _stdcall GetOutputName(unsigned char Number, char *Name)
{
  switch(Number)
  {
     case Q0: {strcpy(Name,&quot;Q0&quot ;); break;} // name output 0
     case Q1: {strcpy(Name,&quot;Q1&quot ;); break;} // name output 1
     case Q2: {strcpy(Name,&quot;Q2&quot ;); break;} // name output 2
     case Q3: {strcpy(Name,&quot;Q3&quot ;); break;} // name output 3
     // case 4,5 ... : next names ...
     default:;
  }
}
 
// Function PROFILAB, called at simulation start
DLLEXPORT void _stdcall CSimStart(double *PInput, double *POutput, double *PUser)
{
  // no function in this DLL
}
 
// Function PROFILAB, called cyclic during simulation, must be time optimized
DLLEXPORT void _stdcall CCalculate(double *PInput, double *POutput, double *PUser)
{
  // operation with digital input/output
  if (PInput[I0]>2.5) POutput[Q0]=0; else POutput[Q0]=5; // e.g. inverter
  if (PInput[I1]>2.5) POutput[Q1]=5; else POutput[Q1]=0; // e.g. non inverter
 
  // operation with analog inputs/outputs
  POutput[Q2]=PInput[I2]+PInput[I3]; // e.g. sum
  POutput[Q3]=PInput[I2]*PInput[I3]; // e.g. multiplication
}
 
// Function PROFILAB, called at simulation stop
DLLEXPORT void _stdcall CSimStop(double *PInput, double *POutput, double *PUser)
{
  // no function in this DLL
}
// Function PROFILAB, called in configuration menu
DLLEXPORT void _stdcall CConfigure(double *PUser)
{
  MessageBox(NULL,TEXT(&quot;no function&quot ;),TEXT(&quot;configuration&quot ;), MB_OK);
}
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
 }
 return TRUE;
}

 

 
 
 
Ringrazio tutti per l'attenzione

Glide

Birbante, la domanda non è chiara!

Ci stai chiedendo lo sviluppo di un software che faccia cosa??? :que:

Ciao ciao