r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[Red] Red language group

Kaj
12-Feb-2012
[4883x5]
What your binding still does differently than the C code is that 
the C code loads the functions dynamically, while Red #import embeds 
loader symbols in the executable format. I think GetProcAddress is 
the standard Windows function to load symbols manually at run time
The good news is that this is independent from the manual setup of 
the function pointers that the C code seems to use to pass the manually 
loaded functions to other program files. You should be able to duplicate 
the manual loading of the functions. It's likely that the functions 
that already work, which are early initialisation functions, happen 
to already be loaded by the library, while the other functions aren't
You should bind the GetProcAddress function (I think there are already 
Red/System Windows examples floating around that use it), find out 
how to get the value of the g_hLedCtrlInst library handle, and use 
them to load the functions like the C code does
Then for each function you have to write a Red/System wrapper function 
and pass it the function pointer as if it were a callback function, 
and call it. There are examples of such constructs in my bindings
There's not much still missing to have Red/System inferface to any 
C code. Basically just importing external variables and support for 
64 bits integers. I think 16 bits integers can be faked on most CPUs
Pekr
12-Feb-2012
[4888x2]
I think I understand what you think, but I got lost in translation 
:-) I will have to think about it few times and try to do some experiments.Thank 
for putting some time into the topic ...
I understand the first two steps, but I don't understand, how such 
a function wrapper in Red/System would look like ...
Kaj
12-Feb-2012
[4890x3]
Here's an example from the C library binding:
on-quit: function [  ; Register handler for normal program termination.
;	handler		[function! []]  ; Callback
	handler		[integer!]
	return:		[logic!]
][
	#either OS = 'Syllable [
		not as-logic _on-quit handler none none
	][
		not as-logic _on-quit handler
	]
]
Instead of passing the handler, you'd execute it directly
Pekr
12-Feb-2012
[4893x2]
hmm, as I am not loading the library myself (IIRC R2 had something 
like addres-of), but Red/System is doing so. I wonder, if there is 
a way of how actually get the library handle ...
hmm, I have installed PE Explorer. It can somehow display some DLL 
related info. In export table, I can see functions entry points. 
If I understand it correctly, those will be an offsets from address, 
to which the library is bound after loading?
Kaj
12-Feb-2012
[4895x6]
Basically, but that's not the method used when loading manually
If you can find the functions you need in there, it shouldn't be 
necessary to load them manually. If so, something else keeps your 
functions from working
If they're not in the list, that would explain why they don't work, 
because the manual loading is needed to pull them in at run time
Besides GetProcAddress, there's a set of a few function for loading 
libraries and symbols. You'd need to bind them and use them to load 
the library, which yields the library handle, and then load the functions. 
They're what load/library and make routine! in REBOL use
Not sure if the Windows symbol tables work like I said, so you'll 
have to try
Hm, I'm not sure either if the wrapper function can currently be 
written like I said. You'd have to use the specific declaration as 
function! type for the function pointer, but the Red/System type 
checker may not currently support getting the function pointer in 
the right type
Pekr
12-Feb-2012
[4901]
Hmm, so in my case the situation in Red/System is even worse than 
possibly in R2 and World, where I could get such a handle from load/library 
directive, whereas in Red/System, what you describe, is writing completly 
separate layer. In fact, C's LoadLibrary is not difficult to handle, 
but still - a C level coding, which I thought is almost eliminated 
for wrapping purposes ...
Kaj
12-Feb-2012
[4902x4]
All in all, if it's possible to load the functions manually, it should 
also be possible to import them at load time with the regular #import 
method. So something else may be wrong in the binding
The Red/System situation is certainly not worse: it's the other way 
around. You can program manual loading with just a few well defined 
functions, the same that R2 and World use. But normally, you use 
automatic loading by the operating system, which is the standard 
and most efficient way to do it, and which R2 and World can't use 
because they execute bindings at run time
It's just that there is no ready binding for manual loading that, 
so you currently have to program it yourself
loading yet
Pekr
12-Feb-2012
[4906x2]
This is the code from LEDSet program:

bool LoadLedCtrl(void)
{
	g_hLedCtrlInst = LoadLibrary("LedCtrl.dll");
	if (!g_hLedCtrlInst)
	{
		g_hLedCtrlInst = LoadLibrary("..\\LedCtrl.dll");
		return false; 
	}
	//

 fpIsPower		= (LSN_ISPOWER)GetProcAddress(g_hLedCtrlInst, "LSN_IsPower");
So, if I would wrap LoadLibrary and GetProcAddress, I could get what 
you describe? :-)
Kaj
12-Feb-2012
[4908x3]
See, the library handle comes from the standard library loading function 
(well, Windows standard)
Yes, that would make your binding work the same way as the C code, 
so if that doesn't work, you definitely know the problem is elsewhere
Can you show your complete #import specification and the definition 
of a function that doesn't work?
Pekr
12-Feb-2012
[4911x2]
#import [

   "LedCtrl.dll" cdecl [

      led-is-power?: "LSN_IsPower" [
         return: [logic!]
      ]

      led-open-card: "LSN_OpenCard" [
          return: [logic!]
      ]  

      led-get-screen-number: "LSN_GetLedScrNumb" [
          return: [integer!]
      ]

      led-set-power: "LSN_Power" [
         power-on? [logic!]
         return: [logic!]
      ]

      led-get-brightness: "LSN_GetBright" [
         return: [integer!]
      ]
led-get-brightness is the first one to fail ...
Andreas
12-Feb-2012
[4913]
your lib uses stdcall, so better use stdcall instead of cdecl (though 
that's most likely not the culprit here)
Pekr
12-Feb-2012
[4914]
I used that, I changed it later to give it a try ...
Andreas
12-Feb-2012
[4915x2]
rest looks good to me, at first glance
just to be sure: in the code example from the LEDSet program you 
gave earlier, is there maybe some initialisation function called 
_after_ all the proc addrs have been retrieved?
Pekr
12-Feb-2012
[4917x2]
there is plenty of ASSERT(fpIsPower		!= NULL);, for each funcitons, 
then function LoadLedCtrl returns true ...
well, I am bothering you here more, than if I would upload somewhere 
a project file with all sources. The app is really small, but I might 
be missing some obvious setting or something else :-)
Kaj
12-Feb-2012
[4919]
An initialisation function is indeed a good candidate for the problem
Pekr
12-Feb-2012
[4920]
http://xidys.com/pekr/ledset-source.zip
Kaj
12-Feb-2012
[4921]
It's not that obvious, the C code does strange indirections :-)
Pekr
12-Feb-2012
[4922]
Kaj - so I defined following functions. It returns something :-) 
Hopefully I have an integer handle, representing the "address"? of 
the requested function. Now is the last step you described - how 
should I invoke it?

   "Kernel32.dll" stdcall [

      load-library: "LoadLibraryA" [
         name [c-string!]
         return: [integer!]
      ]
       
      get-proc-address: "GetProcAddress" [
         library-handle [integer!]
         function-name  [c-string!]
         return: [integer!] 
       ]

   ]

print ["load-library: " handle: load-library "LedCtrl.dll" lf]

print ["get-proc-address: " get-proc-address handle "LSN_IsPower" 
lf]
Kaj
12-Feb-2012
[4923x4]
led-power?: function [
	handler		[function! [return: [logic!]]]
	return:		[logic!]
][
	handler
]
led-power? as function! get-proc-address handle "LSN_IsPower"
Something like that, but I'm not sure the casting to function! type 
will be accepted
get-proc-address should really be defined as return: [function!] 
but that's not currently supported
Pekr
12-Feb-2012
[4927]
*** Compilation Error: invalid definition for function led-power?: 
[function! [return: [logic!]]]
Kaj
12-Feb-2012
[4928]
Ah, that's only supported in import functions, I think. That's why 
I handle them as integers everywhere, but then you can't call it 
as a function. So game over
Pekr
12-Feb-2012
[4929x2]
I will return to serial communication decoding, although that's not 
much fun :-)
Some Red/System type casting will not help? :-)
Kaj
12-Feb-2012
[4931]
No, because those casts aren't supported yet
Pekr
12-Feb-2012
[4932]
Anyway - it was a good way to learn a few bits in a practical manner 
:-)