Autor Beitrag
jam176
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 13:08 
Ich verwende eine DLL deren C source ich erhlaten habe. da gibt es eine ganz simple Prozedur drinnen, die ich in meinem Delphi Programm nützen möchte:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:

Const OK           = 0 
Const MEM_ERROR    = &H1 
Const DLL_NOTINIT  = &H2 
   . 
   . 
   . 
}


ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
VOID EXPENTRY netErrorStr (USHORT errCode, USHORT maxLen, PVALUE errStr) 

  switch (errCode) 
  { 
    case  OK         : 
          strncpy(errStr, "O.K."                                  , maxLen); 
          errStr[maxLen] = '\0'; 
          break; 

    case  DLL_NOTINIT: 
          strncpy(errStr, "DLL noch nicht initialisiert"          , maxLen); 
          errStr[maxLen] = '\0'; 
          break; 

    case  MEM_ERROR  : 
          strncpy(errStr, "Speicherfehler"                        , maxLen); 
          errStr[maxLen] = '\0'; 
          break; 

    case  ADR_ALRUSED: 
          strncpy(errStr, "Adresse bereits verwendet worden"      , maxLen); 
          errStr[maxLen] = '\0'; 
          break; 

  
    default          : 
          strncpy(errStr, "Unbekannter Fehler"                    , maxLen); 
          errStr[maxLen] = '\0'; 
  } 
}


Ich hab also in Delphi7 diese Prozedur wie folgt dekalriert:

ausblenden Delphi-Quelltext
1:
procedure netErrorStr(errNo, MaxLen: Integer; ErrorText: PChar); cdecl;  external 'waagen.dll';					

und dann so verwendet:
[delphi]procedure TForm1.Button1Click(Sender: TObject);
var
pValue: PChar;
sValue: String;
begin
netErrorStr(0,80,pValue);
sValue:= strpas(PChar(pValue);
showmessage(sValue);
end;[/dephi]
Dann sollte "O.K." im meiner Messagebox angezeigt werden. Allerdings erhalte ich einen Programmabsturz, statt meiner Messagebox. Wenn ich mit dem Debugger die Variableninhalte auslese sehe ich schon, dass in pValue "O.K." drinsteht.

Warum also der Absturz???

danke für jede Hilfe
jam176

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.
derDoc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 623

Win Vista Prof
D2007 Prof
BeitragVerfasst: Mo 28.07.03 15:00 
Wie ist denn die typedef von PVALUE?

_________________
MfG derDoc
There are only 10 types of people: those who understand binary and those who don't.
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 15:18 
es tut mir leid, ich bin ein C nackerbatzl! könnte das die deklaration sein?

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
/*******************/
/* Typdefinitionen */
/*******************/

#ifdef __DEV__
  typedef PVOID HWCNTXT;
  typedef PSZ   PVALUE;
#else
  typedef LONG  HWCNTXT;
  typedef PVOID PVALUE;
#endif
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 15:45 
und das hab ich noch in der global.h gefunden

ausblenden Quelltext
1:
typedef char *PSZ;					



ich habe alle .h und .c filed durchsucht! mehr kreig ich nicht raus.
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Mo 28.07.03 16:15 
Zitat:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
   pValue: PChar; 
   sValue: String
 begin 
   netErrorStr(0,80,pValue);

Und wo reservierst du den Speicher für pValue? Das zeigt irgenwohin und die Funtion netErrorStr überschreibt somit irgendwelche Daten. Das das zum Absturz führt ist doch klar.

_________________
Ist Zeit wirklich Geld?
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 16:17 
hab mich noch nie mit solchen dingen auseinandergesetzt. alles was über einen simplen string hinausgeht ist schon neuland.

ich hab mal ein char array definiert, aber das bringt auch nix. wie reserviere ich denn den spreicher richtig?
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 16:30 
aha, danke für den tipp! ich glaube ich hab jetzt verstanden. hab jetzt ein array definiert und dort das ergebins reingeschreiben.

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.Button2Click(Sender: TObject);
var
  pNet, pErr: PChar;
  caErr: array[0..81] of char;
begin

  pErr:= caErr;
  netErrorStr(iErr, 81, pErr);
  showmessage(caErr);

end;


und wie soll ich sagen, kaum macht man's richtig, schon geht's!
danke für den hinweis!
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Mo 28.07.03 17:52 
Titel: ???
jetzt kenn ich mich aba nimmer aus!

wenn ich die ausgabe des rückgabestrings in ein memo schreiben will, stürzt das programm wieder ab!!!

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button2Click(Sender: TObject); 
var 
  pErr: PChar; 
  caErr: array[0..81] of char; 
begin 
  pErr:= caErr; 
  netErrorStr(0, 81, pErr); 
  memo1.lines.add(caErr); 
end;



was passt d'n jetzt wieder nicht???
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 28.07.03 17:53 
Warum definierst du nicht gleich
ausblenden Delphi-Quelltext
1:
pErr : array[0..81]of char					

?

Und von Null bis 81 sind es 82 Zeichen. Sprich, "maxlen" ist also nicht 81 sondern 82:
ausblenden Delphi-Quelltext
1:
netErrorStr(082, pErr);					
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Mo 28.07.03 18:30 
MathiasSimmack hat folgendes geschrieben:
Und von Null bis 81 sind es 82 Zeichen. Sprich, "maxlen" ist also nicht 81 sondern 82:

"maxlen" ist sehrwohl 81. "maxsize" wäre 82. Das #0-Zeichen muss ja auch noch Platz haben. :wink:

_________________
Ist Zeit wirklich Geld?
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 28.07.03 19:36 
Geändert von mir:

Zwar sind leicht bekleidete Mädchen wirklich höchst ablenkend, aber in dem Fall habe ich mich völlig unnötigerweise entschuldigt. 82 ist in dem Fall die korrekte max. Länge, denn die Null hat Platz.

Da ist ein Schreibfehler im C-Code:
ausblenden Quelltext
1:
strncpy(errStr, "O.K.", maxLen);					

was natürlich strcpyn heißen muss. Der letzte Parameter ist die Anzahl der Zeichen, die kopiert werden sollen. Und das PSDK sagt dazu:
PSDK hat folgendes geschrieben:
cchMax
[in] Number of characters to be copied, including the terminating NULL character.

Du kannst also die 82 guten Gewissens angeben, @Andy. :)
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Di 29.07.03 09:56 
Titel: naja
Das ist ja alles ganz gut, und ich hab's jetzt wirklich schön programmiert. Dabei funktioniert
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
const
  MAXLEN = 81;
var
  acErr: array[0..MAXLEN] of char;
begin
  netErrorStr(iErr, MAXLEN, acErr);
  showmessage(acErr);
end;

ganz herrvorragend, während das
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button2Click(Sender: TObject);
const
  MAXLEN = 81;
var
  acErr: array[0..MAXLEN] of char;
begin
  netErrorStr(iErr, MAXLEN, acErr);
  memo1.Lines.add(acErr);
end;

ganz einfach abstürzt. könntet ihr mir noch sagen, was ich da falsch mache?
Cyrus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56



BeitragVerfasst: Di 29.07.03 11:10 
du könntest auch die DLL dynamisch oder statisch einbinden und dann so deine Funktion verwenden:

ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:

  There are two possibilities to load a dll: 

  1. Static loading of a DLL means that the DLL is loaded when the application is executed. 
     This is the easier option to dynamic loading, as you'll see, however it means that if the DLL 
     is missing, your program will not run. 

  {Examples:} 

  {a. Import a function called MYImportFunction from MYLIBRARY.dll} 

  procedure MYImportFunction; external 'MYLIBRARY.dll'; 

  {b. Import a routine under a different name from the one it has in the library. } 
  procedure MYImportFunction; external 'MYLIBRARY.dll' name 'MyNewImportFunctionName'; 

  {c. By ordinal value: Has to be the same value as when using the exports 
      keyword when making the DLL} 
  procedure MYImportFunction; external 'MYLIBRARY.dll' index 10; 



  2. Dynamic loading 

  By dynamically loading a DLL you decide at runtime which DLL to use. 
  This means you can give your program different functionality depending on which 
  DLL's are present (freeware or shareware versions of a program). 
  Or also if you want to load a library whose name or path must be computed at 
  run time or generated from user input. 

  Dynamic loading of a DLL loads the DLL in your application when 
  it is needed and unload it once you its work is done. 
  It requires more code to use, 
  however it more resource friendly than static loading. 


{**********************************************************} 


  Es gibt zwei Möglichkeiten, eine DLL zu laden. 

  1. Statisches Laden 

  Beim statischen Laden wird die zu importierende Prozedur/Funktion mit "external" deklariert. 
  Die Datei 'MYLIBRARY.DLL' wird dann beim Programmstart geladen. 


  {Beispiele:} 

  {a. Importiert eine Funktion MYImportFunction aus der Dll MYLIBRARY.dll } 
  procedure MYImportFunction; external 'MYLIBRARY.dll'; 

  {b. Man kann auch eine Routine unter einem anderen Namen importieren als der in der dll. } 
  procedure MYImportFunction; external 'MYLIBRARY.dll' name 'MyNewImportFunctionName'; 

  {c. Einen Index angeben: } 
  procedure MYImportFunction; external 'MYLIBRARY.dll' index 10; 


  // 2. Dynamisches Laden 


  Beim Dynamischen Laden erfolgt der Zugriff auf die Routinen mit 
  direkten Windows-API-Aufrufen (LoadLibrary, FreeLibrary, GetProcAddress). 
  Die importierten Routinen werden über prozedurale Variablen referenziert. 

  Die importierten DLLs werden erst bei der Ausführung des Quelltextes geladen. 
  Somit wird Speicherplatz eingespart und das Programm wird auch ausgeführt, 
  wenn einige DLLs fehlen. 


{**********************************************************} 

// Example for dynamically loading a DLL 
// Beispiel um eine Dll dynamisch zu laden: 


type 
  TDLLFunction = function(someParam: TSomeType): TSomeOtherType; 


  To execute such a function by name from a named DLL one could use a 
  "caller" function like 


function CallDLLFunction(const dllname, functionname: string; 
  theParameter: TSomeType): TSomeOtherType; 
var 
  hDLL: THandle; 
  theFunction: TDLLFunction; 
  buf: array [0..144] of Char; 
begin 
  // Get a handle to the DLL module. 
  // das Handle zum DLL Modul ermitteln. 
  hDLL := LoadLibrary(StrPCopy(buf, dllname)); 
  // If the handle is valid, try to get the function address. 
  // Wenn das Handle gültig ist, versuche die Adresse der Funktion zu ermitteln 
  if hDLL <> 0 then 
  begin 
    // Return the address of the specified exported (DLL) function. 
    // Adresse der Dll-Funktion ermitteln 
    try 
      @theFunction := GetProcAddress(hDll, StrPCopy(buf, functionname)); 
      // If the function address is valid, call the function. 
      // Wenn die Funktion gefunden wurde... 
      if @theFunction <> nil then 
        Result := theFunction(theParameter) 
      else 
        raise EDLLException.CreateFmt('Unable to link to function %s in DLL %s!', 
          [functionname, dllname]); 
    finally 
      // Free the DLL module. 
      // Dll wieder freigeben. 
      FreeLibrary(hDLL); 
    end; 
  end 
  else 
    raise EDLLException.CreateFmt('Unable to load DLL %s!'#13#10 + 
      'Reason: %s.', [dllname, DLLErrors[hDLL]]); 
end;


Vielleicht hilft dir das weiter!

Greetz Cyrus

_________________
Wer glaub er ist, hört auf zu werden!
Delphi Rulez!!!
jam176 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Windows 2000
Delphi 7
BeitragVerfasst: Di 29.07.03 11:26 
Titel: boah
danke für diese ausführlichen infos. jetzt hab ich endlich den unterschied kapiert! ich hab die dll's jetzt mal statisch eingebunden aber mit "stdcall", statt mit "cdecl" und voila: funzt schon!


vielen dank nochmals!

jam176