Is anyone successfully using microsoft "ink" from Lisp via rdnzl?
I sent this note to Edi
RJF: Could you look at a (1 page) piece of code and see if there is something obvious that (my student and I) are doing wrong trying to use rdnzl?
It is at http://www.cs.berkeley.edu/~fateman/temp/mjnet.lisp
Edi: I just did and it looks OK to me.
... Nevertheless it doesn't work on either Allegro (RJF) or Lispworks. (Edi)
It opens a window and enables "Ink", but if a handler is set up, it stops inking after the first stroke, and never really calls the handler.
Oh, you don't need to have a Tablet PC, but it probably helps to have the microsoft Tablet PC SDK downloaded to your Windows machine. (Our project involves reading and speaking mathematics into a computer for processing by computer algebra programs in Lisp.)
Thanks for any hints. RJF
On Thu, 22 Dec 2005 09:26:38 -0800, Richard Fateman fateman@cs.berkeley.edu wrote:
Oh, you don't need to have a Tablet PC, but it probably helps to have the microsoft Tablet PC SDK downloaded to your Windows machine.
FWIW, I already had this SDK on my machine (which is not a Tablet PC) - most likely because I have Visual Studio. So, if some of you want to give it a try and have a recent version of Visual Studio you should be able to just load and execute the Lisp code. You can use your mouse to simulate the Tablet PC pen.
Cheers, Edi.
I forgot to mention: My guess is that this doesn't work because of threading issues - .NET is trying to call into Lisp from a thread which wasn't created by Lisp. This would explain the failure on LW, see:
http://www.lispworks.com/documentation/lw445/LWUG/html/lwuser-171.htm
I'm not familiar enough with AllegroCL but maybe it's similar there.
On Thu, 22 Dec 2005 18:47:39 +0100, Edi Weitz edi@agharta.de wrote:
My guess is that this doesn't work because of threading issues - .NET is trying to call into Lisp from a thread which wasn't created by Lisp.
And I was right. Here's a solution that avoids these problems and works for me. Files are at the end of this message.
1. Build a DLL (they don't have the threading problems I mentioned - see link in my earlier email) using LispWorks as usual, something like (from a console window):
"\Program Files\LispWorks\lispworks-4460.exe" -init deliver.lisp
2. Make sure RDNZL.dll can be found - put it into c:\Windows\System32 for example.
3. Start the DLL as a program:
rundll32 demo.dll,demo
You should now see a window on which you can "draw" using the mouse. After every fifth stroke a message should come up telling you how many strokes the app has counted so far.
If you don't have a LispWorks license to deliver executables you can download the DLL to play with from
http://nanook.agharta.de/InkDemo.zip
and start with #2 above.
I don't know how to do that with AllegroCL but I guess Franz' support will help you. If they come up with a solution it'd be nice if you could post it here.
Cheers, Edi.
-------------------- deliver.lisp --------------------
(load-all-patches)
;; modify to match the location of RDNZL on your PC (load "/home/lisp/RDNZL/load.lisp")
(use-package :rdnzl)
(load (compile-file "tablet.lisp"))
(shutdown-rdnzl)
(deliver 'init "demo" 1 :dll-exports '("demo"))
(quit)
-------------------- tablet.lisp --------------------
(enable-rdnzl-syntax)
(import-types "Microsoft.Ink" "InkOverlay" "InkCollectorStrokeEventHandler") (import-types "System.Windows.Forms" "Form" "Application" "MessageBox") (import-type "System.EventHandler") (use-namespace "Microsoft.Ink") (use-namespace "System.Windows.Forms") (use-namespace "System")
(defparameter *stroke-counter* 0)
(defun handle-stroke (object event) (declare (ignore object event)) (when (zerop (mod (incf *stroke-counter*) 5)) [MessageBox.Show (format nil "~A strokes so far..." *stroke-counter*)]))
(defun demo () (let ((window (new "Form")) (ink-overlay)) (flet ((on-load (object event) (declare (ignore object event)) (setf ink-overlay (new "InkOverlay" [%Handle window]) [%Enabled ink-overlay] t) [+Stroke ink-overlay (new "InkCollectorStrokeEventHandler" #'handle-stroke)])) [+Load window (new "EventHandler" #'on-load)] [Application.Run window])))
(disable-rdnzl-syntax)
(fli:define-foreign-callable ("demo" :calling-convention :stdcall) ((hwnd w:hwnd) (hinst w:hinstance) (string :pointer) (cmd-show :int)) (declare (ignore hwnd hinst string cmd-show)) (demo))
(defun init () (init-rdnzl))
On Thu, 22 Dec 2005 22:28:26 +0100, Edi Weitz edi@agharta.de wrote:
On Thu, 22 Dec 2005 18:47:39 +0100, Edi Weitz edi@agharta.de wrote:
My guess is that this doesn't work because of threading issues - .NET is trying to call into Lisp from a thread which wasn't created by Lisp.
And I was right.
FWIW, I now also tried the example with Corman Lisp and it seems to work fine. Looks like Corman Lisp doesn't have problems with "foreign" threads calling into Lisp.
On Fri, 23 Dec 2005 12:32:04 +0100, Edi Weitz edi@agharta.de wrote:
FWIW, I now also tried the example with Corman Lisp and it seems to work fine. Looks like Corman Lisp doesn't have problems with "foreign" threads calling into Lisp.
Another data point (I realize that I'm talking to myself all of the time... :) - LispWorks version 5.0 (due out Q2 2006) will also be able to cope with this:
http://article.gmane.org/gmane.lisp.lispworks.general/5093
Cheers, Edi.
On Thu, 22 Dec 2005 22:28:26 +0100, Edi Weitz edi@agharta.de wrote:
On Thu, 22 Dec 2005 18:47:39 +0100, Edi Weitz edi@agharta.de wrote:
My guess is that this doesn't work because of threading issues - .NET is trying to call into Lisp from a thread which wasn't created by Lisp.
And I was right. Here's a solution that avoids these problems and works for me.
Still talking to myself... :)
Here's a solution that'll enable you to keep your interactive development environment:
With a LispWorks built like that I can run the demo fine directly from the IDE.
Cheers, Edi.
On Thu, 22 Dec 2005 18:47:39 +0100, Edi Weitz edi@agharta.de wrote:
I forgot to mention: My guess is that this doesn't work because of threading issues - .NET is trying to call into Lisp from a thread which wasn't created by Lisp. [...] I'm not familiar enough with AllegroCL but maybe it's similar there.
Hmm, seems that it's slightly more complicated in this case. I got a copy of AllegroCL 8.0 for Windows today and played around with it a bit. Still no solution, unfortunately, but here are some more data points:
1. RDNZL seems to work fine with AllegroCL 8.0. I had already checked with the beta, so no surprise.
2. The problem with the "Microsoft.Ink" library remains the same, though.
3. I rummaged around in the AllegroCL docs and found the following:
"A note on calling into Lisp from threads started by foreign code
[...]
In an :os-threads Allegro CL, however, it is legitimate for a thread started outside Lisp to call into Lisp via any foreign-callable function. Some extra work has to be done to create a Lisp process to represent that thread within the lisp world. That extra work is performed by a 'customs agent' process that is started by a call to START-CUSTOMS. See the documentation for that function for details."
Aha! So we just have to call START-CUSTOMS and everything works? No, unfortunately not.
4. The reference entry for START-CUSTOMS says that the function is deprecated, so the paragraph from above is bogus. Nowadays, START-CUSTOM just calls START-SCHEDULER and (again, according to the docs) this is actually never necessary because starting a process will call this function implicitely.
5. So, back to square one. But I thought, hey, what will happen if I start the function DEMO[1] not from the REPL but from a thread?
(mp:process-run-function "demo" #'demo)
The problem is still the same but MP:PROCESS-RUN-FUNCTION does /not/ return until I close the .NET window. So, /something/ is blocking there because the function usually returns immediately.
As I said, still no cigar. But maybe someone more familiar with AllegroCL's MP implementation knows what to make of this.
Cheers, Edi.
[1] see http://common-lisp.net/pipermail/rdnzl-devel/2005-December/000044.html