Daniel 417 Posted February 22, 2021 *sigh* I am fighting with a function from a DLL requiring a pointer that is dereferenced twice. In theory it should be "a pointer to a pointer to a pointer" but somehow I did not find the right language-contruct in Delphi. I actually have to deal with two functions: one to acquire a data-structure, one to release it. while I found a way to get my hands on the correct data (so the first step of acquiring the data seems to be working), my program crashes when I try to free that memory. Basically it is the following: typedef struct libvlc_media_track_t { /* some fields */ } libvlc_media_track_t; /* the two functions I need to import */ unsigned libvlc_media_tracks_get( libvlc_media_t *p_md, libvlc_media_track_t ***tracks ) // the second param is the problematic one libvlc_media_tracks_release( libvlc_media_track_t **p_tracks, unsigned i_count ) The import-declaration of the functions look like this: function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : Pointer) : LongWord; cdecl; procedure libvlc_media_tracks_release(tracks : Pointer; i_count : LongWord ); cdecl; These declarations are not from me, but - so far - all other declarations from that unit have been working correctly, so I assume that these are also correct. My approach was to offer just a pointer to the first function and do some nasty type-conversions afterwards: var LTracksPtr : Pointer; LTracks : libvlc_media_track_t; // a record LCount : int32; begin LCount := libvlc_media_tracks_get( FVLCMIntf, LTracksPtr ); // FVLCMIntf is just (an initialised) pointer LTracks := libvlc_media_track_t( Pointer(LTracksPtr^)^ ); // works (i have the correct data in the record), but looks ugly to me libvlc_media_tracks_release( Pointer(LTracksPtr^), LCount ); // does clearly not work Now the effects are more or less funny - after trying to release that memory in one out of two cases a listview in my program vanishes. Looks like it has a very unfortunate memory-address that is referenced here by mistake. Could anyone with more c-experience point me into the right direction how to deal with that functions? Share this post Link to post
Dalija Prasnikar 1396 Posted February 22, 2021 Logically, I would write libvlc_media_tracks_release( LTracksPtr, LCount ); You pass the LTracksPtr in ..._get function, so only logical thing to do would be to pass same pointer to ..._release function. But this is more logic than C... Strictly following the declarations, I would do the same you did in your non-working code. Share this post Link to post
Daniel 417 Posted February 22, 2021 This example should be working - and if I just (very naive) count the asterisks it should match the declarations. libvlc_media_track_t **tracks; uint track_count; if ((track_count = libvlc_media_tracks_get(media, &tracks)) > 0) { ... libvlc_media_tracks_release(tracks, track_count); } But I still fail to bring this to Delphi-language. Share this post Link to post
Stefan Glienke 2002 Posted February 22, 2021 Should be an (*1)array of (*2)pointer to libvlc_media_track_t passed by (*3)reference, no? 1 Share this post Link to post
Virgo 18 Posted February 22, 2021 (edited) libvlc_media_tracks_release( LTracksPtr, LCount ); should be correct In get function tracks is var parameter. Which is pointer. So that LTracksPtr itself is required parameter for release. You can also always add types Plibvlc_media_track_t = ^libvlc_media_track_t; PPlibvlc_media_track_t = ^Plibvlc_media_track_t; and then functions would be function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : PPlibvlc_media_track_t ) : LongWord; cdecl; procedure libvlc_media_tracks_release(tracks : PPlibvlc_media_track_t ; i_count : LongWord ); cdecl; Edited February 22, 2021 by Virgo correction Share this post Link to post
Fritzew 51 Posted February 22, 2021 I would declaree it all as types so t type Pmedia_track_t = libvlc_media_track_t^; PPmedia_track_t = ^Pmedia_track_t; and then function libvlc_media_tracks_get(p_md : libvlc_media_t_ptr; var tracks : PPmedia_track_t) : LongWord; cdecl; procedure libvlc_media_tracks_release(tracks : PPmedia_track_t; i_count : LongWord ); cdecl; use as: var LTracksPtr : PPmedia_track_t; LTrackUse : Pmedia_track_t; LTracks : libvlc_media_track_t; // a record LCount : int32; begin LCount := libvlc_media_tracks_get( FVLCMIntf, LTracksPtr ); // FVLCMIntf is just (an initialised) pointer LTrackUse := LTracksPtr^; LTracks := LTrackUse^ ; // The above will point to the first record you can increment for the following or use a Array[0..0] of Pmedia_track_t libvlc_media_tracks_release( LTracksPtr, LCount ); // should work end; Share this post Link to post
Daniel 417 Posted February 22, 2021 Thanks to all of you - it's working now. Share this post Link to post
Dalija Prasnikar 1396 Posted February 22, 2021 Just now, Daniel said: Thanks to all of you - it's working now. What is the solution? You cannot leave us like that, hanging in the air... Share this post Link to post
Daniel 417 Posted February 22, 2021 Yes, sorry - I will post my solution tomorrow morning. I have just turned off the development-computer. 😉 Share this post Link to post
DelphiUdIT 176 Posted March 10, 2021 I have used these functions for years (at least 7) for a remote visualization project in the security field (and not only) and I never had any problems in using them. The pointer of a pointer is simply .... a pointer. There is no need to change the "signature" of the originally imported functions. You may use the pointer argument like in this excerpt of a function (from Robert Jêdrzejczyk's PasLibVlc project): function TPasLibVlcPlayer.GetVideoSampleAspectRatio(var sar_num, sar_den : Longword): Boolean; var md : libvlc_media_t_ptr; tracks_ptr : Pointer; tracks_list : libvlc_media_track_list_t_ptr; tracks_count : Integer; tracks_idx : Integer; track_record : libvlc_media_track_t_ptr; begin Result := FALSE; if (p_mi = NIL) then exit; md := libvlc_media_player_get_media(p_mi); tracks_count := libvlc_media_tracks_get(md, tracks_ptr); if (tracks_count > 0) then begin tracks_list := libvlc_media_track_list_t_ptr(@tracks_ptr); for tracks_idx := 0 to tracks_count-1 do begin track_record := tracks_list^[tracks_idx]; if (track_record^.i_type = libvlc_track_video) then begin sar_num := track_record^.u.video^.i_sar_num; sar_den := track_record^.u.video^.i_sar_den; Result := TRUE; break; end; end; libvlc_media_tracks_release(tracks_ptr, tracks_count); end; end; Share this post Link to post
balabuev 102 Posted March 11, 2021 (edited) On 2/22/2021 at 11:46 AM, Stefan Glienke said: Should be an (*1)array of (*2)pointer to libvlc_media_track_t passed by (*3)reference, no? I think this is a: passed by reference (1*) pointer variable, which will point (2*) to array of pointers (3*) to libvlc_media_track_t structs. type PTracks = ^TTracks; TTracks = array[0..1024] of ^libvlc_media_track_t; function libvlc_media_tracks_get(p_md: libvlc_media_t_ptr; var tracks: PTracks): LongWord; cdecl; procedure libvlc_media_tracks_release(tracks: PTracks; i_count: LongWord); cdecl; procedure GetTracks; var tracks: PTracks; cnt: Integer; track: libvlc_media_track_t; begin cnt := libvlc_media_tracks_get(FVLCMIntf, tracks); try for i := 0 to cnt - 1 do begin track := tracks[i]^; DoSomething(track); end; finally libvlc_media_tracks_release(tracks, cnt); end; end; Edited March 11, 2021 by balabuev Share this post Link to post