Avatar billede stois Nybegynder
11. december 2007 - 13:11 Der er 27 kommentarer

Hvordan laver man en pointer?

Jeg skal skrive et program, som snakker med et andet program igennem en DLL, og der er selvfølgelig et antal funktioner, som jeg kan skrive til, men jeg ved ikke nok om hvordan de skal bruges.

Stillede at andet spørgsmål om oversættelse af noget C++ kode, som fulgte med som eksempel.
Fik det her svar:

homeputer_GetObjIdx(IndexTilHvorDuVilHenteVærdierFra, PointerTilCharArrayHvorReturVærdiPlaceres, EnAndenPointerTilCharArrayHvorAndenReturVærdiPlaceres)

Her er et eksemple på hvordan jeg kalder funktionerne i DLL'en:
[DllImport("homeputer.dll",
  EntryPoint = "homeputer_SetWindowHandle",
  CharSet = CharSet.Unicode,
  ExactSpelling = true,
  CallingConvention = CallingConvention.StdCall)]
public static extern bool homeputer_SetWindowHandle(IntPtr WindowsHandle);

Nu skal jeg bare finde ud af hvordan jeg laver en pointer.
Avatar billede clausc Nybegynder
11. december 2007 - 13:19 #1
Check
Marshal.StructureToPtr
Avatar billede stois Nybegynder
11. december 2007 - 13:30 #2
skal jeg checke hjælpefilerne igennem for det Marshal.StructureToPtr?
Avatar billede bvli Praktikant
11. december 2007 - 13:48 #3
Njah.. Lige i din situation kan du nok nøjes med at bruge din "Handle" Property på din form.

/B :)
Avatar billede stois Nybegynder
11. december 2007 - 14:29 #4
jeg er ikke sikker på at jeg forstår hvad det betyder...
Er ret dårlig til det her :-(
Avatar billede stois Nybegynder
11. december 2007 - 14:40 #5
Ref til det spørgsmål som det her er afledt af =)
http://www.eksperten.dk/spm/809802
Avatar billede bvli Praktikant
11. december 2007 - 14:54 #6
Øhm.. Hvilken af funktionerne mener du?

Hvis det er: homeputer_SetWindowHandle(IntPtr p) - så kan du kalde den så'n her:

homeputer_SetWindowHandle(form.Handle);

Hvor form er den form du vil sætte window-handlet til.

Hvis det er dine char arrays du vil have pointers til, så kan du reelt bare smide en string eller stringbuilder ind.

/B :)
Avatar billede stois Nybegynder
11. december 2007 - 15:02 #7
Den med windowshandle har jeg fundet ud af at få til at fungere, men jeg er den her jeg her problemer med ...

[DllImport("homeputer.dll",
EntryPoint = "homeputer_GetObjIdx",
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern string[] homeputer_GetObjIdx(int Index, string ObjectName, string ObjectValue);

Jeg ved ikke hvad det er jeg gør galt?
Avatar billede bvli Praktikant
11. december 2007 - 15:22 #8
Hva' får du af fejl? Er du sikker på at din DllImportAttribute er korrekt? Og hvordan kalder du den nu?

/B :)
Avatar billede stois Nybegynder
11. december 2007 - 18:26 #9
Jeg får den fejl at jeg ikke kan kalde den med de parametre.

Jeg viser dig lige alle de DLLImportAttributes, som virker:

[DllImport("homeputer.dll",
    EntryPoint = "homeputer_InitDLL",
    CharSet = CharSet.Unicode,
    ExactSpelling = true,
    CallingConvention = CallingConvention.StdCall)]
public static extern bool homeputer_InitDll();

[DllImport("homeputer.dll",
    EntryPoint = "homeputer_ObjectCount",
    CharSet = CharSet.Unicode,
    ExactSpelling = true,
    CallingConvention = CallingConvention.StdCall)]
public static extern int homeputer_ObjectCount();

[DllImport("homeputer.dll",
    EntryPoint = "homeputer_SetWindowHandle",
    CharSet = CharSet.Unicode,
    ExactSpelling = true,
    CallingConvention = CallingConvention.StdCall)]
public static extern bool homeputer_SetWindowHandle(IntPtr WindowsHandle);

og det er sådan her jeg har lavet den nyeste:

[DllImport("homeputer.dll",
    EntryPoint = "homeputer_GetObjIdx",
    CharSet = CharSet.Unicode,
    ExactSpelling = true,
    CallingConvention = CallingConvention.StdCall)]
public static extern string[] homeputer_GetObjIdx(int Index, string Objectname, string ObjectValue);

Og det er den jeg har problemer med :-(
Avatar billede clausc Nybegynder
11. december 2007 - 18:39 #10
Prøv i stedet:
public static extern string[] homeputer_GetObjIdx(int Index, ref string Objectname, ref string ObjectValue);
Avatar billede bvli Praktikant
11. december 2007 - 19:00 #11
Eller:
public static extern string[] homeputer_getObjIdx(int index, StringBuilder objectName, StringBuilder objectValue)

/B :)
Avatar billede stois Nybegynder
11. december 2007 - 21:37 #12
Hvad er en stringbuilder....?
Gætter det er noget der kan bygge en streng, måske af chars?

Jeg forstår bare ikke hvordan det kommer over i string[]?

Plejer det ikke være sådan her, man bygger klasser?

Modifiers navnPåObejct(variabelType NavnPåVariabelSomBliverSendtIndIKlassen) {Indhold/kode/variabler}

hvorfor skriver i så, "ref string ObjectName" eller "StringBuilder objectName", i de variableer der skal sendes til objektet?
Avatar billede clausc Nybegynder
11. december 2007 - 21:59 #13
Mht StringBuilder:
Strenge i c# er immutables, dvs når du skriver noget i stil med:
  string a = "abc";
  a = a + "def";
så bliver a reelt nedlagt og genoprettet som 'abcdef'.
Med andre ord, så medfører streng + streng en frygtelig masse allokering og deallokering af hukommelse. Det er ineffektivt (og en dødssynd ved web-udvikling).

Derfor findes der en 'hjælpeklasse' System.Text.StringBuilder som er effektiv til konkatenering af strenge.


Mht 'ref':
Parametre kan overføres som reference parametre; dvs givet to funktioner:
  void foo1(int x) {x = 123;}
  void foo2(ref int x) {x = 123;}
så er forskellen at foo1 IKKE ændrer ved parameteren; hvilket foo2 derimod gør. Dvs:
  int a = 1;
  foo1(a);
  // a er stadig 1
  foo2(a);
  // nu er a 123!

Grunden til jeg foreslår du ændrer parametrene til 'ref string', er at det reelt giver et ekstra lag indirection i forhold til C++ kaldet.
I 'gamle dage' med VB6, skulle man typisk lave det modsatte trick pga VB6's noget mystiske implementering internt af strenge.
Avatar billede bvli Praktikant
12. december 2007 - 12:25 #14
StringBuilder har 'indbygget' lidt ekstra Marshall'ing funktionalitet, i forbindelse med p/invoke til en pointer til et char array.

Men altså - det aller-aller letteste ville nok være, hvis du gav os den oprindelige C deklaration til metoden homeputer_getObjIdx, hvis du har den nogen steder. Så ville vi være fri for at gætte os frem.

/B :)
Avatar billede stois Nybegynder
13. december 2007 - 23:35 #15
Jeg finder den lige =)

Her er hele deklaration filen =)

Here goes....
.................................
#include <dir.h>
#include <string.h>

HINSTANCE DLL_Handle;

typedef INT _stdcall (*Thomeputer_InitDLL)();
typedef INT _stdcall (*Thomeputer_SetObjValName)(char*, char*);
typedef INT _stdcall (*Thomeputer_GetObjValName)(char*, char*);
typedef INT _stdcall (*Thomeputer_SetWindowHandle)(longword);
typedef INT _stdcall (*Thomeputer_ChangeCount)();
typedef INT _stdcall (*Thomeputer_ChangedObjects)(char*);
typedef INT _stdcall (*Thomeputer_ObjectCount)();
typedef INT _stdcall (*Thomeputer_GetObjIdx)(int, char*, char*);

Thomeputer_InitDLL homeputer_InitDLL;
Thomeputer_SetObjValName homeputer_SetObjValName;
Thomeputer_GetObjValName homeputer_GetObjValName;
Thomeputer_SetWindowHandle homeputer_SetWindowHandle;
Thomeputer_ChangeCount homeputer_ChangeCount;
Thomeputer_ChangedObjects homeputer_ChangedObjects;
Thomeputer_ObjectCount homeputer_ObjectCount;
Thomeputer_GetObjIdx homeputer_GetObjIdx;

int LoadDLL()
{
  char sA[255];
  char *s=sA;
  AnsiString s2;
  s=getcwd(s,254);
  s2=s;
  s2=StringReplace(s2,"\\","/",TReplaceFlags() << rfReplaceAll)+"/homeputer.dll";
  //  s="c:/MeinVerzeichnis/homeputer.dll";
  s=s2.c_str();
  DLL_Handle=LoadLibrary(s);
  if (DLL_Handle != NULL)
  {
    homeputer_InitDLL = (Thomeputer_InitDLL) GetProcAddress(DLL_Handle,
    "homeputer_InitDLL");
    homeputer_SetObjValName = (Thomeputer_SetObjValName) GetProcAddress(DLL_Handle,
    "homeputer_SetObjValName");
    homeputer_GetObjValName = (Thomeputer_GetObjValName) GetProcAddress(DLL_Handle,
    "homeputer_GetObjValName");
    homeputer_SetWindowHandle = (Thomeputer_SetWindowHandle)GetProcAddress(DLL_Handle,
    "homeputer_SetWindowHandle");
    homeputer_ChangeCount = (Thomeputer_ChangeCount) GetProcAddress(DLL_Handle,
    "homeputer_ChangeCount");
    homeputer_ChangedObjects = (Thomeputer_ChangedObjects) GetProcAddress(DLL_Handle,
    "homeputer_ChangedObjects");
    homeputer_ObjectCount = (Thomeputer_ObjectCount) GetProcAddress(DLL_Handle,
    "homeputer_ObjectCount");
    homeputer_GetObjIdx = (Thomeputer_GetObjIdx) GetProcAddress(DLL_Handle,
    "homeputer_GetObjIdx");
    return(1);
  }
  else
    return(0);
}

...................

Tak for hjælpe indtil videre, håber det hjælper jer til at kunne give mig det hele rigtige svar. =)
Avatar billede stois Nybegynder
17. december 2007 - 12:57 #16
Kan jeg får et svar af en af jer eller jer begge to, så jeg kan lukke det her spørgsmål.

Det har hjulpet, men det virker ikke endnu.
Avatar billede clausc Nybegynder
17. december 2007 - 13:12 #17
C++ interfacet er IMHO et bufferoverrun der venter på at ske.

Hvorom det er, så prøv at sikre, at strengene du kalder med, inden kaldet fyldes med f.eks 254 spaces. Så vidt jeg kan se, så kan man ikke angive en buffer størrelse og man får heller ikke en tilbage, hvilket er MEGET uheldigt.

Mht points , så samler jeg ikke.
Avatar billede stois Nybegynder
17. december 2007 - 15:29 #18
Hvad betyder alt det her?:

char sA[255];
  char *s=sA;
  AnsiString s2;
  s=getcwd(s,254);
  s2=s;
  s2=StringReplace(s2,"\\","/",TReplaceFlags() << rfReplaceAll)+"/homeputer.dll";
  //  s="c:/MeinVerzeichnis/homeputer.dll";
  s=s2.c_str();
  DLL_Handle=LoadLibrary(s);

Jeg kan bare ikke forstå det...
Avatar billede clausc Nybegynder
17. december 2007 - 15:49 #19
Det er c++ a la Borland...

De første 5 linier smider Working Dir ind i s2.
Så skiftes "\" ud med "/" og dll'ens navn lægges til.
Til sidst smides værdien af s2 (som er stien til dll'en) ned i en c-streng,
som så bruges som argument til dynamisk at load'e dll'en.

Alt det burde være transparent ifbm .Net DllImport.

Du siger det ikke virker helt. Hvad er fejlen? Får du en exception eller forkerte retur værdier eller ??
Avatar billede stois Nybegynder
17. december 2007 - 19:17 #20
Jeg får en exception, men ikke hvad den handler om...

Her er min try catch
try
{
  string ObjectName = null;
  string ObjectValue = null;
  Homeputer.homeputer_GetObjIdx(
    Homeputer_Message.WParam.ToInt32(),
    ref ObjectName,
    ref ObjectValue);
  lbl_Windows_Handle_Info.Text += "\nObject Call Successful" +
    "\n Object Returned:" +
    "\n  Name:  " + ObjectName +
    "\n  Value: " + ObjectValue;
}
catch (SEHException e)
{
  lbl_Windows_Handle_Info.Text += "\nObject calling error!";
  txtbx_Exception.Text = "Exception:\n" + e.ToString();
}

Og her er den exception jeg får...
System.Runtime.InteropServices.SEHException: External component has thrown an exception.
  at ALMAX_TEST_2.Homeputer.homeputer_GetObjIdx(Int32 Index, String& ObjectName, String& ObjectValue)
  at ALMAX_TEST_2.MainWindow.WndProc(Message& Homeputer_Message) in T:\Program\ALMAX TEST 2\ALMAX TEST 2\MainWindow.cs:line 69

Linie 69 er:
Homeputer.homeputer_GetObjIdx(
    Homeputer_Message.WParam.ToInt32(),
    ref ObjectName,
    ref ObjectValue);

-----------------------------------

Jeg har fået forslaget om at lave en catch, som ser sådan her ud:
catch (System.Runtime.InteropServices.SEHException ex)
{
    MessageBox.Show(ex.InnerExcepotion.ToString());
}

Det prøver jeg lige, så jeg kan få den inderste exception men her op, så du har mere at gå på =)
Avatar billede clausc Nybegynder
17. december 2007 - 19:53 #21
Godt; du forventer at ObjectName og ObjectValue udfyldes af kaldet. Derfor får du en fejl når du sender to null-strenge med.

Funktionen forventer to strenge med plads til 254 karakterer (+1 til nul-terminering). Det er IMHO noget hø. Men lad det hvile.

Som foreslået tidligere, prøv :
  string ObjectName = String(' ', 254);
  string ObjectValue = String(' ', 254);
Avatar billede stois Nybegynder
17. december 2007 - 22:54 #22
Okay det gør jeg så =)

Har du forslået det tilligere.... syntes ikke jeg fik set det ... ohh well
Avatar billede stois Nybegynder
17. december 2007 - 23:00 #23
Nu får jeg den her Exception:

System.NullReferenceException: Object reference not set to an instance of an object.
  at ALMAX_TEST_2.MainWindow.WndProc(Message& Homeputer_Message) in T:\Program\ALMAX TEST 2\ALMAX TEST 2\MainWindow.cs:line 80
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Avatar billede clausc Nybegynder
17. december 2007 - 23:33 #24
Det må være:
Homeputer_Message.WParam.ToInt32()

Tvivler på WParam er noget fornuftigt. Prøv at kalde med Index = 0
Avatar billede clausc Nybegynder
17. december 2007 - 23:36 #25
Det er rent gætteri; men jeg går ud fra at homeputer_GetObjIdx skal kaldes med et Index (på et object) og at du får udfyldt to string med navn og værdi. Lyder det nogenlunde rigtigt???
Avatar billede stois Nybegynder
18. december 2007 - 01:25 #26
ja så vidt jeg ved...

Her er den tysk vejlednings tekst, måske kan du så noget ud af den =)

homeputer_GetObjIdx(Index, Objektname, Objektwert)
Mit dieser Funktion können Objektname und Objektwert für den angegebenen Index ermittelt werden.
Der Index ist vom Typ integer, Objektname und Objektwert sind Pointer auf nullterminierte Strings.
Aufrufparameter : Index, Objektname, Objektwert
Rückgabewert: 1 Aufruf war erfolgreich, gültigen Werte in Objektname, Objektwert
0 Aufruf war nicht erfolgreich, keine gültigen Werte in Objektname, Objektwert
Aufrufbeispiel in Delphi und C
homeputer_GetObjIdx(Idx, ObjName, ObjValue)

Du får lige hovedteksten igen, men kørt igennem babelfish.

With this function object name and object value for the indicated index can be determined. The index is more integer of the type, object name and object value is pointers on zero-scheduled stringers. Call parameter: Index, object name, object value
Avatar billede stois Nybegynder
18. december 2007 - 01:34 #27
Hver gang der sker en ændring i vinduet, som DLL har forbindelse til får jeg en winproc tilbage... med beskeden (message) WParam.

wparam = 0, hver gang uret tikker... lige gyldigt
wparam = 1, Hver gang der sker en ændring i FHT modulet, som er det modul jeg er interesseret i =)

P.s: FHT står ikke har noget sætligt, det er bare et modul nummer/navn
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester