Translate anonymouse struct

Just starting out? Need help? Post your questions and find answers here.
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Translate anonymouse struct

Post by Aleks_Longard »

Hello all!
How to translate this code on PB?

Code: Select all

typedef struct MediaTrack mediatrack;
struct ReaProject;

mediatrack* tr = getTrack(*ReaProject, 0);
And how to use native C code in code with C_backend?
Where I can read about this?
Sory my bad english
User avatar
idle
Always Here
Always Here
Posts: 5093
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Translate anonymouse struct

Post by idle »

Not sure as I have no context MediaTrack is just an alias to the structure and ReaProject will be an PB integer

Code: Select all

Global *tr.mediatrack, ReaProject.i
!p_tr = getTrack(&ReaProject,0);
using in line c is easy enough but it's currently limited in scope without using the a compiler tool. which is only available for windows and linux https://www.purebasic.fr/english/viewtopic.php?t=78558

what c library are you trying to use?
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: Translate anonymouse struct

Post by Aleks_Longard »

Hi Idle,
thank you for help!
I write plugin for virtual music studio Reaper
http://reaper.fm

In C I write normal plugin, and it work. In PB I write only code for loading Reaper API, only some functions not work, but I not now as this translate in to PB.
I will test your small code.

If you want I can public my pure C example.

PS: My PB code work in Reaper only I compile with asm-backend, if change to C-backend - Reaper not load plugin and not scan actions.
Sory my bad english
User avatar
idle
Always Here
Always Here
Posts: 5093
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Translate anonymouse struct

Post by idle »

I found this but it's c++ and don't think you can use it with the c backend
https://github.com/justinfrankel/reaper ... r_plugin.h

it should be usable with PB asm on x64 like this assuming strings are unicode
and for x86 you could use this method
https://www.purebasic.fr/english/viewto ... 84#p442484

Code: Select all

; // abstract base class
; class PCM_source
; {
;   public:
;     virtual ~PCM_source() { }
; 
;     virtual PCM_source *Duplicate()=0;
; 
;     virtual bool IsAvailable()=0;
;     virtual void SetAvailable(bool avail) { } // optional, If called With avail=false, close files/etc, And so on
;     virtual const char *GetType()=0;
;     virtual const char *GetFileName() { Return NULL; } // return NULL if no filename (not purely a file)
;     virtual bool SetFileName(const char *newfn)=0; // return TRUE if supported, this will only be called when offline
; 
;     virtual PCM_source *GetSource() { Return NULL; }
;     virtual void SetSource(PCM_source *src) { }
;     virtual int GetNumChannels()=0; // return number of channels
;     virtual double GetSampleRate()=0; // returns preferred sample rate. if < 1.0 then it is assumed to be silent (or MIDI)
;     virtual double GetLength()=0; // length in seconds
;     virtual double GetLengthBeats() { Return -1.0; } // length in beats if supported
;     virtual int GetBitsPerSample() { Return 0; } // returns bits/sample, if available. only used for metadata purposes, since everything returns as doubles anyway
;     virtual double GetPreferredPosition() { Return -1.0; } // not supported returns -1
; 
;     virtual int PropertiesWindow(HWND hwndParent)=0;
; 
;     virtual void GetSamples(PCM_source_transfer_t *block)=0;
;     virtual void GetPeakInfo(PCM_source_peaktransfer_t *block)=0;
; 
;     virtual void SaveState(ProjectStateContext *ctx)=0;
;     virtual int LoadState(const char *firstline, ProjectStateContext *ctx)=0; // -1 on error
; 
; 
;     // these are called by the peaks building UI To build peaks For files.
;     virtual void Peaks_Clear(bool deleteFile)=0;
;     virtual int PeaksBuild_Begin()=0; // returns nonzero if building is opened, otherwise it may mean building isn't necessary
;     virtual int PeaksBuild_Run()=0; // returns nonzero if building should continue
;     virtual void PeaksBuild_Finish()=0; // called when done
; 
;     virtual int Extended(int call, void *parm1, void *parm2, void *parm3) { Return 0; } // return 0 if unsupported
; };
;// abstract base class
Interface PCM_source
  Free_PCM_source()
  Duplicate()
  IsAvailable();=0;
  SetAvailable(avail); { } // optional, If called With avail=false, close files/etc, And so on
  GetType()          ;=0;
  GetFileName()      ;  // return NULL if no filename (not purely a file)
  SetFileName(newfn.s); // return TRUE if supported, this will only be called when offline
  GetSource() 
  SetSource(src); { }
  GetNumChannels();=0; // return number of channels
  GetSampleRate() ;=0; // returns preferred sample rate. if < 1.0 then it is assumed to be silent (or MIDI)
  GetLength()=    ;0; // length in seconds
  GetLengthBeats(); { Return -1.0; } // length in beats if supported
  GetBitsPerSample(); { Return 0; } // returns bits/sample, if available. only used for metadata purposes, since everything returns as doubles anyway
  GetPreferredPosition(); { Return -1.0; } // not supported returns -1
  PropertiesWindow(hwndParent);
  GetSamples(*block.PCM_source_transfer_t);=0;
  GetPeakInfo(*block.PCM_source_peaktransfer_t);=0;
  SaveState(*ctx.ProjectStateContext)          ;=0;
  LoadState(firstline.s,*ctx.ProjectStateContext);=0; // -1 on error
                                                 ;// these are called by the peaks building UI To build peaks For files.
  Peaks_Clear(deleteFile)                        ;=0;
  PeaksBuild_Begin()                             ;=0; // returns nonzero if building is opened, otherwise it may mean building isn't necessary
  PeaksBuild_Run()                               ;=0; // returns nonzero if building should continue
  PeaksBuild_Finish()                            ;=0; // called when done
  Extended(call.l,*parm1,*parm2,*parm3)          ; { Return 0; } // return 0 if unsupported
EndInterface 
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: Translate anonymouse struct

Post by Aleks_Longard »

This work)))
I am programming in C++ 20 years, and know as emulate C++ classes in pure C.
Look please my old code:

Code: Select all

/*
Pure C Reaper plug example
coding Alexey Longard (UA)
compiled with TCC 0.97 x64/x86
*/

#include <stdio.h>
#include <stdbool.h>
#include <windows.h>

#define REAPER_PLUGIN_DLL		_EXPORT __declspec(dllexport)
#define REAPER_PLUGIN_HINSTANCE HINSTANCE
#define REAPERAPI_DEF extern

#define REAPER_PLUGIN_VERSION 0x20E
#define IMPAPI(x) if (!errcnt && !((*(void **)&(x)) = (void *)rec->GetFunc(#x))) errcnt++;

HWND hwnd_main;

struct ReaProject;
typedef struct MediaTrack MediaTrack;
typedef struct MediaItem MediaItem;
struct MediaItem_Take;
struct TrackEnvelope;

typedef struct reaper_plugin_info_t
{
int caller_version; // REAPER_PLUGIN_VERSION
HWND hwnd_main;
int (*Register)(const char *name, void *infostruct); // returns 1 if registered successfully
void * (*GetFunc)(const char *name); // returns 0 if function not found
} reaper_plugin_info_t;

typedef struct 
{
ACCEL accel; // key flags/etc represent default values (user may customize)
const char* desc; // description (for user customizability)
} gaccel_register_t; // use "gaccel"

bool (*APIExists)(const char* function_name);
void (*APITest)();
const char* (*GetExePath)();
void (*ShowConsoleMsg)(const char* msg);
int (*ShowMessageBox)(const char* msg, const char* title, int type);
struct MediaItem* (*AddMediaItemToTrack)(struct MediaTrack* tr);
int (*GetTrackNumMediaItems)(struct MediaTrack* tr);
bool (*GetTrackName)(struct MediaTrack* track, char* bufOut, int bufOut_sz);
struct MediaTrack* (*GetTrack)(struct ReaProject* proj, int trackidx);

gaccel_register_t acreg01={{0,0,0}, "extension 01 action test Alex"};
gaccel_register_t acreg02={{0,0,0}, "extension action 02 test Alex"};

int reg_command01 = 0;
int reg_command02 = 0;

void Action1()
{
MessageBox(hwnd_main, "Hello World!","Test 01",MB_OK);
}

void Action2()
{
char buf[10];
MediaTrack *tr = GetTrack(0, 0);
GetTrackName(tr, buf, 10);
ShowMessageBox(buf, "Message", 0);
}

bool hookCommandProc(int command, int flag)
{
if (reg_command01!=0 && command == reg_command01)
{
Action1();
return true;
}
if (reg_command02!=0 && command == reg_command02)
{
Action2();
return true;
}
return false;
}

REAPERAPI_DEF REAPER_PLUGIN_DLL_EXPORT int ReaperPluginEntry(REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t *rec)
{
if (rec != NULL)
{
int errcnt = 0;

IMPAPI(ShowMessageBox);
IMPAPI(ShowConsoleMsg);
IMPAPI(GetExePath);
IMPAPI(GetTrackNumMediaItems);
IMPAPI(GetTrackName);
IMPAPI(GetTrack);

ShowMessageBox(GetExePath(), "with", 0);

acreg01.accel.cmd = reg_command01 = rec->Register("command_id", (void*)"a105");
if (!reg_command01) return 0;

acreg02.accel.cmd = reg_command02 = rec->Register("command_id", (void*)"a107");
if (!reg_command02) return 0;

rec->Register("gaccel", &acreg01);
rec->Register("gaccel", &acreg02);

rec->Register("hookcommand", (void*)hookCommandProc);
return 1;
}
else
{
ShowMessageBox("Quit plugin", "Good bye", 0);
return 0;
}
}

					
And my PB experement:

Code: Select all

EnableExplicit

PrototypeC.i Register(name.p-ascii, *infostruct)
PrototypeC GetFunc(name.p-ascii)

Structure reaper_plugin_info_t Align #PB_Structure_AlignC
caller_version.i
hwnd_main.i
*register.Register
*GetFunc.GetFunc
EndStructure

Structure gaccel_register_t Align #PB_Structure_AlignC
  accel.ACCEL
  *desc
EndStructure

PrototypeC.i ShowMessageBox(msg.p-ascii, title.p-ascii, type.l)
PrototypeC GetExePath()

Global acreg01.gaccel_register_t
Global action.l, reg_command01.l = 0
Global *ShowMessage, *GetReaperPath
Global string.s

acreg01\accel\cmd = 0
acreg01\accel\fVirt = 0
acreg01\accel\key = 0
acreg01\accel\PB_Alignment = 0
acreg01\desc = Ascii("my one PureBasic action")

ProcedureC.l ShowMessage(message.s, title.s, flags.l)
  Protected *cm = Ascii(message), *ct = Ascii(title)
  ProcedureReturn CallFunctionFast(*ShowMessage, *cm, *ct, flags)
EndProcedure

ProcedureC GetReaperPath()
  ProcedureReturn CallFunctionFast(*getreaperpath)
EndProcedure

ProcedureC action01()
string = PeekS(GetreaperPath(), -1, #PB_Ascii)
ShowMessage(string, "Title", 0)
EndProcedure

ProcedureC.l hookCommandProc(command.i, flags.i)
  If reg_command01 <> 0 And command = reg_command01
action01()
    ProcedureReturn #True
    EndIf
    ProcedureReturn #False
EndProcedure

ProcedureC varning()
  ShowMessage("Works correctly", "title", 0)
  EndProcedure

ProcedureCDLL.i ReaperPluginEntry(hInstance.i, *rec.reaper_plugin_info_t)
 If *rec <> #NUL
*ShowMessage.ShowMessageBox = *rec\GetFunc("ShowMessageBox")
*GetReaperPath.GetExePath = *rec\GetFunc("GetExePath")

reg_command01 = *rec\register("command_id", Ascii("a9003"))
acreg01\accel\cmd = reg_command01
If Not reg_command01
  ProcedureReturn #False
  EndIf

*rec\register("gaccel", @acreg01)
*rec\register("hookcommand", @hookCommandProc())

varning()
ProcedureReturn #True
Else
 ProcedureReturn #False
 EndIf
EndProcedure

Sory my bad english
User avatar
idle
Always Here
Always Here
Posts: 5093
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Translate anonymouse struct

Post by idle »

Aleks_Longard wrote: Sat May 14, 2022 4:24 am This work)))
I am programming in C++ 20 years, and now as emulate C++ classes in pure C.
Look please my old code:
You should know better than me then, I've forgotten both c and c++
The c example you posted may work with the c backend but you will need to use my tool I linked earlier

Code: Select all

ImportC "somelib.lib" : EndImport 
!//#include <stdio.h> ;
!//#include <stdbool.h> ;
!//#include <windows.h> ;

!#define REAPER_PLUGIN_DLL_EXPORT __declspec(dllexport)
!#define REAPER_PLUGIN_HINSTANCE HINSTANCE
!#define REAPERAPI_DEF extern

;...

and the PB code for Action2, like this perhaps

Code: Select all


ProcedureC Action2()
  Protected *buf,tr 
  *buf = AllocateMemory(10) 
  tr = GetTrack(0, 0);
  GetTrackName(tr,*buf,10);
  ShowMessageBox(PeekS(*buf,-1, #PB_Ascii), "Message", 0);
  FreeMemory(*buf) 
EndProcedure 

Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: Translate anonymouse struct

Post by Aleks_Longard »

Thank you Idle,
i copy you compiler tool and will be test.
Thanks for you code, it's very good idea for me.

I like to programing on PB, only in some cases the C++ knowledge put me in an uncomfortable position)))
Sory my bad english
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: Translate anonymouse struct

Post by Aleks_Longard »

Idle, very big thank for you help, it's all work!

Full example code for plugin:
(PB 5.73 Windows x64, maybe work on all OS)

Code: Select all

; Small modification for same as C code

EnableExplicit

Macro quote
  "
EndMacro
Macro ImpAPI(name)
  *name.name = *rec\GetFunc(quote#name#quote)
  EndMacro

PrototypeC.i Register(name.p-ascii, *infostruct)
PrototypeC GetFunc(name.p-ascii)

Structure reaper_plugin_info_t Align #PB_Structure_AlignC
caller_version.i
hwnd_main.i
*register.Register
*GetFunc.GetFunc
EndStructure

Structure gaccel_register_t Align #PB_Structure_AlignC
  accel.ACCEL
  *desc
EndStructure

PrototypeC.i ShowMessageBox(m		sg.p-ascii, title.p-ascii, type.l)
PrototypeC GetExePath()
PrototypeC.l GetTrackName(*MediaTrack, *bufOut, bufOut_sz.i)
PrototypeC GetTrack(ReaProject, trackidx.i)

Global acreg01.gaccel_register_t, acreg02.gaccel_register_t
Global action.l, reg_command01.l = 0, reg_command02 = 0
Global *ShowMessageBox, *GetExePath, *GetTrackName, *GetTrack
Global ReaProject, MediaTrack, *MediaItem, *MediaItem_Take, *TrackEnvelope
Global string.s

acreg01\accel\cmd = 0
acreg01\accel\fVirt = 0
acreg01\accel\key = 0
acreg01\accel\PB_Alignment = 0
acreg01\desc = Ascii("my one PureBasic action")

acreg02\accel\cmd = 0
acreg02\accel\fVirt = 0
acreg02\accel\key = 0
acreg02\accel\PB_Alignment = 0
acreg02\desc = Ascii("my get track name")

ProcedureC.l ShowMessageBox(message.s, title.s, flags.l)
  Protected *cm = Ascii(message), *ct = Ascii(title)
  ProcedureReturn CallFunctionFast(*ShowMessageBox, *cm, *ct, flags)
EndProcedure

ProcedureC GetExePath()
  ProcedureReturn CallFunctionFast(*GetExePath)
EndProcedure

ProcedureC.l GetTrackName(*MediaTrack, *bufOut, bufOut_sz.i)
ProcedureReturn CallFunctionFast(*GetTrackName, *MediaTrack, *bufOut, bufOut_sz)
EndProcedure

ProcedureC GetTrack(ReaProject, trackidx.i)
ProcedureReturn CallFunctionFast(*GetTrack, ReaProject, trackidx)
EndProcedure

ProcedureC action01()
string = PeekS(GetExePath(), -1, #PB_Ascii)
ShowMessageBox(string, "Title", 0)
EndProcedure

ProcedureC action02()
  Protected *sbuf = AllocateMemory(20)
  MediaTrack = GetTrack(0, 0)
GetTrackName(MediaTrack, *sbuf, 20)
ShowMessageBox(PeekS(*sbuf, -1, #PB_Ascii), "Title", 0)
FreeMemory(*sbuf)
EndProcedure

ProcedureC.l hookCommandProc(command.i, flags.i)
If reg_command01 <> 0 And command = reg_command01
action01()
    ProcedureReturn #True
    EndIf
    If reg_command02 <> 0 And command = reg_command02
action02()
    ProcedureReturn #True
    EndIf
    ProcedureReturn #False
EndProcedure

ProcedureC varning()
ShowMessageBox("Works correctly", "title", 0)
  EndProcedure

ProcedureCDLL.i ReaperPluginEntry(hInstance.i, *rec.reaper_plugin_info_t)
 If *rec <> #NUL
ImpAPI(ShowMessageBox)
ImpAPI(GetExePath)
ImpAPI(GetTrack)
ImpAPI(GetTrackName)

reg_command01 = *rec\register("command_id", Ascii("a9003"))
acreg01\accel\cmd = reg_command01
If Not reg_command01
  ProcedureReturn #False
  EndIf

reg_command02 = *rec\register("command_id", Ascii("a9004"))
acreg02\accel\cmd = reg_command02
If Not reg_command02
  ProcedureReturn #False
  EndIf

*rec\register("gaccel", @acreg01)
*rec\register("gaccel", @acreg02)

*rec\register("hookcommand", @hookCommandProc())

varning()
ProcedureReturn #True
Else
 ProcedureReturn #False
 EndIf
EndProcedure

Sory my bad english
Post Reply