How To Call procedure by pointer in RPGLE - rpgle

I use callback in the service module. The pointer of the callback function I want to pass as procedure parameter.
How I could to call the my callback function in the service module?
psevdocode:
main code:
dcl-pr Proc2;
ptr pointer;
end-pr;
dcl-s ptr inz(%Addr(Proc1))
Proc2( ptr);
dcl-proc Proc1;
dcl-pi *n;
parm1 char(123);
end-pi;
...
end-proc Proc1;
Service programm
dcl-proc Proc2;
dcl-pi *n;
ptr pointer;
end-pi;
dcl-s param char(123) inz('xxxaaaqqq')
*ptr( param ); // call callback
end-proc Proc2;

%PADDR() (Get Procedure Address) built in function
PROCPTR keyword (in fixed format d-specs)
POINTER(*PROC) (in free format d-specs)
dcl-pr Proc2;
ptr pointer(*PROC);
end-pr;
Proc2( %paddr(Proc1));
dcl-proc Proc1;
dcl-pi *n *IND;
parm1 char(123);
parm2 int(10);
end-pi;
...
end-proc Proc1;
*SRVPGM
dcl-proc Proc2;
dcl-pi *n;
ptr pointer(*PROC)
end-pi;
//defined prototype for callback
// as EXTernal PROCedure pointed to by ptr
dcl-pr callback extproc(ptr) *IND;
cbParm char(123);
cbParm2 int(10);
end-pr;
dcl-s param char(123) inz('xxxaaaqqq')
dcl-s myInt int(10);
dcl-s success ind;
success = callback( param:myInt ); // call callback
end-proc Proc2;

This article has an example on how to use procedure pointers.
https://github.com/OSSILE/OSSILE/tree/master/code_examples/rpg/interfaces

Related

Linux kernel function hooking fails in few cases?

I am writing a LKM that hooks a function with a custom function.
To achieve this I am modifying the function's prologue with
mov rax, <custom_func_addr> // Intel syntax.
jmp rax
The exact opcode is : "\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0" // 8 '\x00' are replaced with actual address.
The code works fine.say I hook vfs_read(), It works accordingly.
The is one case I have observed in which hooking fails :
void foo(char *func) {
unsigned long addr = get_sym_addr(func); // gets the address of function.
DEBUG("function %s addr : %lu\n", func, addr);
hook((void*)addr, &test_func_hooked); // hook it with custom function.
void (*test_func_orig) (int) = addr; // get ptr to the function.
test_func_orig(20); // call through func ptr.
test_func(10); // call function directly.
}
// defined in same file.
void test_func(int a) {
printk("a = %d\n", a);
}
However Hooking happens properly when function gets called using func ptr.
and, If I directly call the function as - test_func(10), hook is not called.
Is there anything I am missing here ? I have tested the module by hooking vfs_read() , whenever a 'read' comes on any file, hook get called. Only this particular case where function to hook is in the same file, It is not working.

String parameter to lua function suddenly goes null

My lua function looks like below. The parameter "scandate" is pased from c++ to the lua function. The printed output of the first line shows the date, and thereafter, any operation on the string indicates the string suddenly became null or empty.
function DoCustomLookup(wkItem,wkfId,wkevid,lookupTableID,scandate,lookuptext,lookupval,evtAlertText,newvalue,xtraFld1,xtraFld2,xtraFld3,xtraFld4,newStatus,newStatusDesc,errFlags)
local rslt = "Script error"
print (scandate)
local scYY = scandate.sub(1,4)
local scMM = scandate.sub(7,2)
local scDD = scandate.sub(10,2)
print (scYY)
print (scMM)
print (scDD)
local scandt = #scandate
print (scandt)
scYY,scMM, scDD = scandate.match("(%d+)%-(%d+)%-(%d+)%s.+")
...
end
Here is the console output:
2015-12-10 01:00:02
0
19
Workflow script error. Line :17: bad argument #2 to 'match' (string expected, got no value)
So it appears to me that the string simply vanishes in thin air.
Can someone please explain what is going on and how I can keep the string? The strange thing is that substrings do not work, but the string length still prints 19. Then match also keeps failing (That is why I tried the substr as alternative)
Here is my code calling it from c++. You will notice I copy the date to a temporary buffer. I thought maybe the std::string.c_str() maybe got out of scope, but it did not change wheter I pass the date as std::string or from a c buffer.
bool LuaScript::DoCustomLookup(int wkItem, int wkfId, int wkevid, const int lookupTableID, const std::string scantime,
const std::string& lookuptext, const std::string& lookupval, const std::string evtAlertText,
std::string& newvalue,
const std::string xtraFld1, const std::string xtraFld2, const std::string xtraFld3, const std::string xtraFld4,
int& newStatus, std::string& newStatusDesc, AlertFlags& errFlags, std::string& errMsg)
{
errMsg = "";
char **date**[50];
sprintf(date, "%s", scantime.c_str());
lua_getglobal(L, "DoCustomLookup"); // get function
lua_pushinteger(L, wkItem); // push parameter on call stack
lua_pushinteger(L, wkfId); // push parameter on call stack
lua_pushinteger(L, wkevid); // push parameter on call stack
lua_pushinteger(L, lookupTableID); // push parameter on call stack
lua_pushstring(L, **date**); // push parameter on call stack
lua_pushstring(L, lookuptext.c_str()); // push parameter on call stack
lua_pushstring(L, lookupval.c_str()); // push parameter on call stack
lua_pushstring(L, evtAlertText.c_str()); // push parameter on call stack
lua_pushstring(L, newvalue.c_str()); // push parameter on call stack
lua_pushstring(L, xtraFld1.c_str()); // push parameter on call stack
lua_pushstring(L, xtraFld2.c_str()); // push parameter on call stack
lua_pushstring(L, xtraFld3.c_str()); // push parameter on call stack
lua_pushstring(L, xtraFld4.c_str()); // push parameter on call stack
lua_pushinteger(L, newStatus); // push parameter on call stack
lua_pushstring(L, newStatusDesc.c_str()); // push parameter on call stack
lua_pushinteger(L, errFlags); // push parameter on call stack
int rslt = lua_pcall(L, 16, 1, 0);
Thank you

WASAPI AudioClient.GetMixFormat() returns AUDCLNT_E_NOT_INITIALIZED

I'm attempting to use AudioClient interface for the first time, without luck.
So far I managed to get the default AudioClient interface using the successfully MMDeviceEnumerator and MMDevice interfaces:
CoCreateInstance(
CLSID_MMDeviceEnumerator, nil,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
MMEnumerator);
MMEnumerator.GetDefaultAudioEndpoint(eRender,eConsole,MMDevice);
MMDevice.Activate(IID_IAudioClient, CLSCTX_ALL, nil, AudioClient);
(Result checking code not included here). This 3 call all returned no errors, and I've got a non-nil interface ptr in AudioClient variable.
My problem is when I try to get the mixing waveformat:
AudioClient.GetMixFormat(pwfx)
This returns the code 0x88890001 which is AUDCLNT_E_NOT_INITIALIZED. -> Of course not initialized as I only wanted to get what waveformat it likes first.
Looking up msdn tells that the AudioClient.GetMixFormat can be called before AudioClient.Initialization. Also the AUDCLNT_E_NOT_INITIALIZED is not on the list of possible return values. So I'm confused about what did I do wrong. GetMixFormat() doc -> http://msdn.microsoft.com/en-us/library/windows/desktop/dd370872(v=vs.85).aspx
Another weird thing is that when I call AudioClient.GetStreamLatency() it returns with S_OK and with a quasi-random value around 1000ms. But the documentation states that "This method requires prior initialization of the IAudioClient interface. All calls to this method will fail with the error AUDCLNT_E_NOT_INITIALIZED until the client initializes the audio stream by successfully calling the". Therefore I think I have a working AudioClient interface, I just can't understand why it doesn't work as the way documentation says.
(I'm using win7 64bit, Sound Blaster Live 5.1 with kx-project driver (DSound and classic windows MM sound works ok, but with a 100ms terrible long latency, that's the only reason why I'm going to use WASAPI on the win7)
Thank you in advance.
I actually found the bug. The definition of IAudioClient in MFPack is incorrect, the interface functions are in the wrong order. (I'd like to push this in some way some day, if I find the time for it, move to git etc.)
This is the correct ordering of methods in IAudioClient:
IAudioClient = interface(IUnknown)
['{1CB9AD4C-DBFA-4c32-B178-C2F568A703B2}']
function Initialize(ShareMode: AUDCLNT_SHAREMODE; StreamFlags: Dword; hnsBufferDuration: REFERENCE_TIME; hnsPeriodicity: REFERENCE_TIME; pFormat: PWaveFormatEx; AudioSessionGuid: LPCGUID): HResult; stdcall;
function GetBufferSize(out pNumBufferFrames: UINT32): HResult; stdcall;
function GetStreamLatency(out phnsLatency: REFERENCE_TIME): HResult; stdcall;
function GetCurrentPadding(out pNumPaddingFrames: UINT32): HResult; stdcall;
function IsFormatSupported(ShareMode: AUDCLNT_SHAREMODE; pFormat: PWaveFormatEx; out ppClosestMatch: PWaveFormatEx): HResult; stdcall;
function GetMixFormat(out ppDeviceFormat: PWaveFormatEx): HResult; stdcall;
function GetDevicePeriod(out phnsDefaultDevicePeriod: REFERENCE_TIME; phnsMinimumDevicePeriod: REFERENCE_TIME): HResult; stdcall;
function Start(): HResult; stdcall;
function Stop(): HResult; stdcall;
function Reset(): HResult; stdcall;
function SetEventHandle(const eventHandle: HANDLE): HResult; stdcall;
function GetService(const riid: TGUID; out ppv: Pointer): HResult; stdcall;
//The GetService method supports the following service interfaces: IAudioCaptureClient, IAudioClock, IAudioRenderClient,
//IAudioSessionControl, IAudioStreamVolume, IChannelAudioVolume, IMFTrustedOutput, ISimpleAudioVolume.
//Since Windows 7 the new interface indentifier IID_IMFTrustedOutput has been added, but is not implemented here.
end;
The function ReleaseBuffer is also wrong, this is the correct parameters:
IAudioRenderClient = interface(IUnknown)
['{F294ACFC-3146-4483-A7BF-ADDCA7C260E2}']
function GetBuffer(const NumFramesRequested: UINT; out ppData: PByte): HResult; stdcall;
function ReleaseBuffer(const NumFramesWritten: UINT32; const dwFlags: DWord): HResult; stdcall;
end;

Callback function in waveOutOpen() API

I am building an audio player that plays '.wav' files and I have a problem with the callback function called from waveOutOpen() API.
Opening the output audio device for playback:
MMRESULT mRes = waveOutOpen(m_hWO,WAVE_MAPPER,&wFmt,(DWORD)&waveOutProc,(DWORD)this, CALLBACK_FUNCTION);
Implementation of callback function:
void CPlayWave::waveOutProc(HWAVEOUT m_hWO,UINT uMsg,DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
MMRESULT mmRes;
CPlayWave *pPW = (CPlayWave*)dwInstance;
switch(uMsg)
{
case MM_WOM_DONE: //playback finished
mmRes = waveOutUnprepareHeader(m_hWO, &pPW->m_WHdr, sizeof(WAVEHDR));
if(mmRes!=MMSYSERR_NOERROR)
{
//error handling
.....
}
mmRes = waveOutClose(m_hWO);
if(mmRes!=MMSYSERR_NOERROR)
{
//error handling
.....
}
AfxMessageBox("Finished playing the file");
m_bPlay = FALSE; //boolean flag used for pausing
break;
case WIM_DATA:
//for recording completion
break;
}
}
The problem is the MM_WOM_DONE never occurs and the callback function is never called after the playback of the file is completed. If a thread has to be used instead of callback function, can someone give me a simple example on how to use a callback thread(haven't found on net).
Also waveOutReset() documentation suggests that it closes all the buffers and returns to the system, so for handling the Stop-button in my application, I used the waveOutReset() function but, this causing the application to freeze. Why is this happening? Is there any alternative method to stop playing while buffer is still in queue for playback.
Callback function probably can not be a method of your class CPlayWave itself. It must be simple function out of your class with requested prototype.
void CALLBACK waveOutProc(HWAVEOUT m_hWO, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
...
}
It must be, of course, declared/defined before you call waveOutOpen(). In addition, function name is pointer itself and ampersand & is not needed. Thus calling waveOutOpen() should be:
MMRESULT mRes = waveOutOpen(m_hWO, WAVE_MAPPER, &wFmt, (DWORD_PTR) waveOutProc, (DWORD_PTR) this, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);
Also you there are only few system functions you can call from waveOutProc:
"Applications should not call any system-defined functions from inside a callback function, except for EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, and timeSetEvent. Calling other wave functions will cause deadlock."
So calling funcitons like AfxMessageBox or waveOutUnprepareHeader might be cause terrible issues.

Runtime exception when calling dll function with parameter in Inno Setup

I am successfully calling a function in a DLL from Inno Setup, however upon returning I get a Runtime Error...Exception: Access violation at address XXXXXXX. Write of address XXXXXX.
The function is declared as:
function CompleteInstall(szIntallPath: String) : Integer;
external 'CompleteInstall#files:InstallHelper.dll stdcall setuponly';
And called:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then begin
CompleteInstall('Parm1'); // ExpandConstant('{app}')
end;
end;
There is no problem if I change the function to not take a parameter. It still occurs if I change it to take a single integer parameter or declare it as a function and change the function to be a void function with an integer parameter.
The called function does nothing but return:
__declspec(dllexport) int CompleteInstall(char* szInstallPath)
{
//AfxMessageBox ("Got here" /*szInstallPath*/, MB_OK);
return 1;
}
You have a mismatch of the calling conventions. Either make the DLL function use stdcall as well:
__declspec(dllexport) __stdcall int CompleteInstall(char* szInstallPath)
{
//AfxMessageBox ("Got here" /*szInstallPath*/, MB_OK);
return 1;
}
or change the function declaration to use cdecl instead of stdcall:
function CompleteInstall(szIntallPath: String) : Integer;
external 'CompleteInstall#files:InstallHelper.dll cdecl setuponly';
Although according to mghie (see comments) it shouldn't make a difference in this case, you might want to use PChar instead of String as that would be the more accurate equivalent of the C-declaration char*.
String is a Pascal-native type which is usually managed quite differently than a PChar (though apparently not so much in Inno's PascalScript).

Resources