Discussion:
FoxPro 2.6 on Windows XP
(too old to reply)
Dennis Allen
2005-10-05 19:40:16 UTC
Permalink
Hi. Got a client getting new XP machines. Still wants to run FoxPro
2.6 for DOS and FoxPro 2.6 for Windows. Ran into the following issues:

1) Created a command prompt desktop shortcut icon. Very little
available memory in FoxPro for DOS. Don't see any memory option in the
shortcut properties.

2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).

3) FoxPro 2.6 for Windows. Sending output directly to printer lpt1
(???) causes general protection fault. Sending output to normal spooler
(?) goes to local printer, regardless of lpt?.

If anyone has a solution to any of these issues, I'd greatly appreciate
the help...Dennis
Stephen Ibbs
2005-10-05 21:16:55 UTC
Permalink
Item 3 - is it an HP printer. There was a known problem and there is a
convoluted fix on the Microsoft website

http://support.microsoft.com/default.aspx?scid=kb;en-us;183522

The easier fix I found was to persuade the user to use one of the MS printer
drivers rather than the driver supplied by HP.

Of course this is all irrelevant if it is not an HP printer <g>

HTH

Stephen
Hi. Got a client getting new XP machines. Still wants to run FoxPro 2.6
1) Created a command prompt desktop shortcut icon. Very little available
memory in FoxPro for DOS. Don't see any memory option in the shortcut
properties.
2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).
3) FoxPro 2.6 for Windows. Sending output directly to printer lpt1 (???)
causes general protection fault. Sending output to normal spooler (?)
goes to local printer, regardless of lpt?.
If anyone has a solution to any of these issues, I'd greatly appreciate
the help...Dennis
Dennis Allen
2005-10-05 22:07:18 UTC
Permalink
Thanks for the reply. Yes, it was a HP driver. In FoxPro 2.6 for
Windows I tried DECLARE _fpreset IN msvcrt20.dll, but no go. Where is
msvcrt20.dll or anything like msvcrt??.dll ...Dennis
Post by Stephen Ibbs
Item 3 - is it an HP printer. There was a known problem and there is a
convoluted fix on the Microsoft website
http://support.microsoft.com/default.aspx?scid=kb;en-us;183522
The easier fix I found was to persuade the user to use one of the MS
printer drivers rather than the driver supplied by HP.
Of course this is all irrelevant if it is not an HP printer <g>
HTH
Stephen
Post by Dennis Allen
Hi. Got a client getting new XP machines. Still wants to run FoxPro
1) Created a command prompt desktop shortcut icon. Very little
available memory in FoxPro for DOS. Don't see any memory option in
the shortcut properties.
2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).
3) FoxPro 2.6 for Windows. Sending output directly to printer lpt1
(???) causes general protection fault. Sending output to normal
spooler (?) goes to local printer, regardless of lpt?.
If anyone has a solution to any of these issues, I'd greatly
appreciate the help...Dennis
Stephen Ibbs
2005-10-06 06:19:18 UTC
Permalink
Note the article was specifically referring to vfp so I don't think that fix
will work with fpw26. I simply read the article as meaning all versions of
foxpro up to that point, ie including fpw26, and of course I may be mistaken
on this.

This is why I went for the simple option of using a Windows driver.

I did find the 'More information' section interesting because it showed how
to reproduce the error. This told me that somewhere in my app a divide by
zero was probably occurring. I did investigate and found one or two
circumstances where this could occur and fixed them. The issue almost went
away but I don't know whether this is because I fixed the divide by zero, or
they switched drivers.

HTH

Stephen
Thanks for the reply. Yes, it was a HP driver. In FoxPro 2.6 for Windows
I tried DECLARE _fpreset IN msvcrt20.dll, but no go. Where is
msvcrt20.dll or anything like msvcrt??.dll ...Dennis
Post by Stephen Ibbs
Item 3 - is it an HP printer. There was a known problem and there is a
convoluted fix on the Microsoft website
http://support.microsoft.com/default.aspx?scid=kb;en-us;183522
The easier fix I found was to persuade the user to use one of the MS
printer drivers rather than the driver supplied by HP.
Of course this is all irrelevant if it is not an HP printer <g>
HTH
Stephen
Post by Dennis Allen
Hi. Got a client getting new XP machines. Still wants to run FoxPro
1) Created a command prompt desktop shortcut icon. Very little
available memory in FoxPro for DOS. Don't see any memory option in the
shortcut properties.
2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).
3) FoxPro 2.6 for Windows. Sending output directly to printer lpt1
(???) causes general protection fault. Sending output to normal spooler
(?) goes to local printer, regardless of lpt?.
If anyone has a solution to any of these issues, I'd greatly appreciate
the help...Dennis
Andrew Howell
2005-10-06 08:46:36 UTC
Permalink
Thanks for the reply. Yes, it was a HP driver. In FoxPro 2.6 for Windows
I tried DECLARE _fpreset IN msvcrt20.dll, but no go. Where is
msvcrt20.dll or anything like msvcrt??.dll ...Dennis
DECLARE creates arrays in FPW :-D

You need call32.dll from here:
http://www.spaldingsoftware.com/rob/call32.htm


And something like this in FPW:
* begin
IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO SYS(2004)+'foxtools' ADDITIVE
ENDIF

IF FILE('call32.dll')
IF FILE(JUSTPATH(GETENV('comspec')+'\msvcrt20.dll'))
m.ldecl32=regfn('Declare32', 'CCC', 'L', 'call32.dll')
m.lfree32=regfn('FreeCall32IDs', '', '', 'call32.dll')

* call Declare32 to set up pointer interface for 32bit function
m.lfpr32=callfn(m.ldecl32, '_fpreset', 'msvcrt20.dll', '')

* register 16bit calls to pass through the 32bit calls
m.lfpr16=regfn('Call32', 'L', 'L', 'call32.dll')

* call it - you probably want to check the result or something
* but I haven't here
=callfn(m.lfpr16, m.lfpr32)

* free libraries
=callfn(m.lfree32)
ELSE
=MSGBOX('Cannot find msvcrt20.dll', 'File not found..', 48)
ENDIF
ELSE
=MSGBOX('Cannot find call32.dll', 'File not found..', 48)
ENDIF
* end

I'm still a bit touchy about using call32 - problem being if anything is
wrong a GPF is thrown (try removing the leading underscore from '_fpreset'
to create a non existant function name, for example.) This is annoying
because it cannot be trapped like all other fox errors (if it can be trapped
at all.)
This is also why I tested for msvcrt20.dll with FILE - if call32 can't find
it you'll get a GPF again.

At least once it has got into a state on a machine where it GPFs every time
on previously working calls until ntvdm is killed (in task manager) or the
machine is rebooted. I've started using the call32 I mentioned above in
preference to Rick Strahl's build since it has an extra function to free the
dlls which I'm now doing. It hasn't gone wrong yet but it's only been in use
for about a week so far.

Also, don't put a full path to call32.dll in the regfn() calls, there seems
to be a bug in regfn() that reports it cannot find any function name in the
dll after the first use (a relative path works OK.)
--
HTH
Andrew Howell
Dennis Allen
2005-10-06 15:56:57 UTC
Permalink
The Microsoft knowledge sheet says to =_fpreset() after every major
print command. So would I use all your code to initialize (declare),
before I can use =_fpreset()? How would I release everything, or is
that your =callfn(m.lfpr16, m.lfpr32) and =callfn(m.lfree32)?
Post by Andrew Howell
Post by Dennis Allen
Thanks for the reply. Yes, it was a HP driver. In FoxPro 2.6 for
Windows I tried DECLARE _fpreset IN msvcrt20.dll, but no go. Where
is msvcrt20.dll or anything like msvcrt??.dll ...Dennis
DECLARE creates arrays in FPW :-D
http://www.spaldingsoftware.com/rob/call32.htm
* begin
IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO SYS(2004)+'foxtools' ADDITIVE
ENDIF
IF FILE('call32.dll')
IF FILE(JUSTPATH(GETENV('comspec')+'\msvcrt20.dll'))
m.ldecl32=regfn('Declare32', 'CCC', 'L', 'call32.dll')
m.lfree32=regfn('FreeCall32IDs', '', '', 'call32.dll')
* call Declare32 to set up pointer interface for 32bit function
m.lfpr32=callfn(m.ldecl32, '_fpreset', 'msvcrt20.dll', '')
* register 16bit calls to pass through the 32bit calls
m.lfpr16=regfn('Call32', 'L', 'L', 'call32.dll')
* call it - you probably want to check the result or something
* but I haven't here
=callfn(m.lfpr16, m.lfpr32)
* free libraries
=callfn(m.lfree32)
ELSE
=MSGBOX('Cannot find msvcrt20.dll', 'File not found..', 48)
ENDIF
ELSE
=MSGBOX('Cannot find call32.dll', 'File not found..', 48)
ENDIF
* end
I'm still a bit touchy about using call32 - problem being if anything
is wrong a GPF is thrown (try removing the leading underscore from
'_fpreset' to create a non existant function name, for example.) This
is annoying because it cannot be trapped like all other fox errors (if
it can be trapped at all.)
This is also why I tested for msvcrt20.dll with FILE - if call32 can't
find it you'll get a GPF again.
At least once it has got into a state on a machine where it GPFs every
time on previously working calls until ntvdm is killed (in task
manager) or the machine is rebooted. I've started using the call32 I
mentioned above in preference to Rick Strahl's build since it has an
extra function to free the dlls which I'm now doing. It hasn't gone
wrong yet but it's only been in use for about a week so far.
Also, don't put a full path to call32.dll in the regfn() calls, there
seems to be a bug in regfn() that reports it cannot find any function
name in the dll after the first use (a relative path works OK.)
--
HTH
Andrew Howell
Andrew Howell
2005-10-07 07:21:53 UTC
Permalink
The Microsoft knowledge sheet says to =_fpreset() after every major print
command. So would I use all your code to initialize (declare), before I
can use =_fpreset()? How would I release everything, or is that your
=callfn(m.lfpr16, m.lfpr32) and =callfn(m.lfree32)?
callfn(m.lfpr16, m.lfpr32) is the call to _fpreset() in msvcrt20.dll

callfn(m.lfree32) is what frees msvcrt20.dll


You could either put all that code in a Foxpro function and call it after
your print job [in which case it declares, calls and releases every time,]
or maybe register the dll functions once at the top of your application,
then use callfn(m.lfpr16, m.lfpr32) after your print jobs and finally
callfn(m.lfree32) when the application quits.

I tend to prefer the first approach because the function is kind of loosely
coupled, I can save all that in its own "fpreset.prg" and use it in whatever
application I like without having a dependency on creating the declarations
at the top of different applications.
Just issuing "=fpreset()" in a program will cause the project manager to
include fpreset.prg it in a project and that's all I need to do.
--
HTH
Andrew Howell
Dennis Allen
2005-10-10 03:42:50 UTC
Permalink
Hi. Been gone a couple of days. Here's the procedure I wrote, based on
your code:

PROCEDURE FPWRESET
*
IF .NOT. "FOXPRO 2.6A FOR WINDOWS" $ UPPER(VERSION())
RETURN
ENDIF
IF SYS(2000,cMEMPATH+'foxtools.fll')=='' .OR.
SYS(2000,cMEMPATH+'call32.dll')==''
RETURN
ENDIF
PRIVATE cCOMPATH
cCOMPATH = GETENV('COMSPEC')
IF RAT(cPATH_SEP,cCOMPATH) > 0
cCOMPATH = SUBSTR(cCOMPATH,1,RAT(cPATH_SEP,cCOMPATH))
ELSE
cCOMPATH = ""
ENDIF
IF SYS(2000,cCOMPATH+'msvcrt20.dll')==''
RETURN
ENDIF
IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO (cMEMPATH+'foxtools') ADDITIVE
ENDIF
* "Andrew Howell" <***@work>
m.ldecl32=regfn('Declare32', 'CCC', 'L', cMEMPATH+'call32.dll')
m.lfree32=regfn('FreeCall32IDs', '', '', cMEMPATH+'call32.dll')
* call Declare32 to set up pointer interface for 32bit function
m.lfpr32=callfn(m.ldecl32, '_fpreset', cCOMPATH+'msvcrt20.dll', '')
* register 16bit calls to pass through the 32bit calls
m.lfpr16=regfn('Call32', 'L', 'L', cMEMPATH+'call32.dll')
* call it - you probably want to check the result or something
* but I haven't here
=callfn(m.lfpr16, m.lfpr32)
* free libraries
=callfn(m.lfree32)
* end
WAIT 'FPWRESET COMPLETE' WINDOW
RETURN

I call this procedure before every SET PRINT TO, SET("PRINT",1), and
SYS(1037). I perform:

SET PRINT TO PRN
DO FPWRESET
DO WHILE !FEOF(n)
c = FGETS(n)
??? c
SKIP
ENDDO
SET PRINT TO

...the resetting SET PRINT TO results in a GPF. At least on my machine,
with a HP 5L attached. What am I doing wrong? That Microsoft KB
articule refers to SET PRINT TO NAME, SET('PRINT,3), GETPRINTER(), etc.
These commands aren't in Foxpro 2.6a for Windows. Could I be calling
FPWRESET too many times? When should I call FPWRESET?
Andrew Howell
2005-10-10 07:06:57 UTC
Permalink
<call to _fpreset code>
I call this procedure before every SET PRINT TO, SET("PRINT",1), and
SET PRINT TO PRN
DO FPWRESET
DO WHILE !FEOF(n)
c = FGETS(n)
??? c
SKIP
ENDDO
SET PRINT TO
...the resetting SET PRINT TO results in a GPF. At least on my machine,
with a HP 5L attached. What am I doing wrong? That Microsoft KB articule
refers to SET PRINT TO NAME, SET('PRINT,3), GETPRINTER(), etc. These
commands aren't in Foxpro 2.6a for Windows. Could I be calling FPWRESET
too many times? When should I call FPWRESET?
You said the KB article said to call after each major (?) print command.
Have you tried it between the ENDDO and SET PRINT TO?

I'm not sure, I've never actually needed to use the function.
--
Regards
Andrew Howell
Dennis Allen
2005-10-10 14:18:07 UTC
Permalink
Placed a DO fpwreset right after the ???. Still GPF after the second
SET PRINT TO. Is the fpwreset procedure correct for a XP machine?
Post by Andrew Howell
<call to _fpreset code>
I call this procedure before every SET PRINT TO, SET("PRINT",1), and
SET PRINT TO PRN
DO FPWRESET
DO WHILE !FEOF(n)
c = FGETS(n)
??? c
SKIP
ENDDO
SET PRINT TO
...the resetting SET PRINT TO results in a GPF. At least on my
machine, with a HP 5L attached. What am I doing wrong? That
Microsoft KB articule refers to SET PRINT TO NAME, SET('PRINT,3),
GETPRINTER(), etc. These commands aren't in Foxpro 2.6a for Windows.
Could I be calling FPWRESET too many times? When should I call
FPWRESET?
You said the KB article said to call after each major (?) print command.
Have you tried it between the ENDDO and SET PRINT TO?
I'm not sure, I've never actually needed to use the function.
--
Regards
Andrew Howell
Andrew Howell
2005-10-10 14:47:36 UTC
Permalink
Placed a DO fpwreset right after the ???. Still GPF after the second SET
PRINT TO. Is the fpwreset procedure correct for a XP machine?
Ick. These GPFs are not good :-(

I wouldn't like to say whether or not it is "correct..."
The file msvcrt20.dll (Microsoft Visual C runtime 2.0?) is there on a
default XP installation, all i did was looked at the KB article and wrote
the FPW code to use the 32bit thunking layer (ie call32.dll) to call it.

I figure it must be doing the _fpreset OK, otherwise it would be GPFing on
that and it was GPFing before you put the call in. So that just means it's
not fixing it.

I don't think we have a 5L here any more but I have a LJ4, if you could post
some example data I could output via ??? to test with it (ie give me some
sort of simple print so I see it is) then I'll give it a look.
I've actually never had a deal of luck with ??? and when I've wanted to
output directly to printer I've written a file to disc, then used

RUN TYPE file.txt>LPT1:
or
RUN COPY file.txt LPT1:

It is klugey and doesn't look great with a DOSbox popping up but as is often
the way with kluges, has worked faultlessly for years.
--
Regards
Andrew Howell
Dennis Allen
2005-10-10 19:05:05 UTC
Permalink
This 3 line program will cause a GPF on my machine:

SET PRINT TO LPT1
??? "Hi"
SET PRINT TO


I've sent you a compiled fxp...Dennis
Post by Andrew Howell
Post by Dennis Allen
Placed a DO fpwreset right after the ???. Still GPF after the second
SET PRINT TO. Is the fpwreset procedure correct for a XP machine?
Ick. These GPFs are not good :-(
I wouldn't like to say whether or not it is "correct..."
The file msvcrt20.dll (Microsoft Visual C runtime 2.0?) is there on a
default XP installation, all i did was looked at the KB article and
wrote the FPW code to use the 32bit thunking layer (ie call32.dll) to
call it.
I figure it must be doing the _fpreset OK, otherwise it would be
GPFing on that and it was GPFing before you put the call in. So that
just means it's not fixing it.
I don't think we have a 5L here any more but I have a LJ4, if you
could post some example data I could output via ??? to test with it
(ie give me some sort of simple print so I see it is) then I'll give
it a look.
I've actually never had a deal of luck with ??? and when I've wanted
to output directly to printer I've written a file to disc, then used
or
It is klugey and doesn't look great with a DOSbox popping up but as is
often the way with kluges, has worked faultlessly for years.
--
Regards
Andrew Howell
Dennis Allen
2005-10-10 21:16:26 UTC
Permalink
Hi again. My email to <***@work> bounced back. Did you need a copy of
the fxp file? How about a Foxpro 2.6a for Windows runtime?
Post by Andrew Howell
Post by Dennis Allen
Placed a DO fpwreset right after the ???. Still GPF after the second
SET PRINT TO. Is the fpwreset procedure correct for a XP machine?
Ick. These GPFs are not good :-(
I wouldn't like to say whether or not it is "correct..."
The file msvcrt20.dll (Microsoft Visual C runtime 2.0?) is there on a
default XP installation, all i did was looked at the KB article and
wrote the FPW code to use the 32bit thunking layer (ie call32.dll) to
call it.
I figure it must be doing the _fpreset OK, otherwise it would be
GPFing on that and it was GPFing before you put the call in. So that
just means it's not fixing it.
I don't think we have a 5L here any more but I have a LJ4, if you
could post some example data I could output via ??? to test with it
(ie give me some sort of simple print so I see it is) then I'll give
it a look.
I've actually never had a deal of luck with ??? and when I've wanted
to output directly to printer I've written a file to disc, then used
or
It is klugey and doesn't look great with a DOSbox popping up but as is
often the way with kluges, has worked faultlessly for years.
--
Regards
Andrew Howell
Andrew Howell
2005-10-11 11:09:34 UTC
Permalink
Post by Dennis Allen
the fxp file? How about a Foxpro 2.6a for Windows runtime?
Yes, sorry it's just a phoney email address for newsgroup posting.
I've reproduced the problem, I'm not sure it's an XP thing because it kills
Foxpro in Win95 too for me.
I tried the different parallel port modes in the BIOS but that made no
difference either.

I also tried COM1 and that didn't GPF but gave me a "File read error" when
trying to SET PRINTER TO - I assume that is when it tries to flush the
buffer to the port.

I did manage marginal success with SET DEVICE TO PRINTER - but only on a
network printer (it threw "Printer not ready" error for a network printer
with SET PRINTER TO \\server\sharename.) As soon as I setup a generic/text
only driver on LPT1 it would cause the same GPF as SET PRINTER TO when
flushing the buffer.

** later on **

Hmmmmm, I have managed to send data to the print spooler via Win32 API,
there are some nasty things I haven't worked out but it is sending raw data
and not crashing my computer in the 50 odd tests I've done so far.
I have the same tentative feeling regarding stability as with my last
comment concerning use of call32.dll. Of course this has many more calls so
I'm even more worried... In other words, if you get stability problems with
this you're probably on your own from now.
Having said that, it does do what you want. But *please* test it more
thoroughly than I have..

First you'll need to install a printer, manufacturer "Generic", printer
"Generic / Text Only". Give it a name, say "test raw".

Then try this [watch for line wrapping:]

* BEGIN

?rawprint('test raw', 'some test data')
*******************
FUNCTION rawprint
*******************
* send raw data to named printer via spooler
PARAMETERS m.pprinter, m.pdata
* pprinter - [R] C printer name (as in machine's printers folder.) Doesn't
seem to like network printer names for some reason
* pdata - [R] C data to send to printer
PRIVATE ALL LIKE l*

* returns .T. if all calls OK, .F. if anything went wrong
* (although you may get GPF before you can check return value..)
m.lallok=.T.

* get foxtools
IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO SYS(2004)+'foxtools' ADDITIVE
ENDIF

IF FILE('call32.dll')
m.ldecl32=regfn('Declare32', 'CCC', 'L', 'call32.dll')
m.lfree32=regfn('FreeCall32IDs', '', '', 'call32.dll')

* call Declare32 to register 32bit functions
m.lclose32=callfn(m.ldecl32, 'ClosePrinter', 'winspool.drv', 'i')
m.ledoc32=callfn(m.ldecl32, 'EndDocPrinter', 'winspool.drv', 'i')
m.lepage32=callfn(m.ldecl32, 'EndPagePrinter', 'winspool.drv', 'i')
m.lopen32=callfn(m.ldecl32, 'OpenPrinter', 'winspool.drv', 'ppi')
m.lstard32=callfn(m.ldecl32, 'StartDocPrinter', 'winspool.drv', 'iip')
m.lstarp32=callfn(m.ldecl32, 'StartPagePrinter', 'winspool.drv', 'i')
m.lwrite32=callfn(m.ldecl32, 'WritePrinter', 'winspool.drv', 'ipii')

* now register 16bit calls to pass through the 32bit calls
* (actually, 4 of these are identical but it's easier to remember by
(truncated) name <g>)
m.lclose16=regfn('Call32', 'LL', 'L', 'call32.dll')
m.ledoc16=regfn('Call32', 'LL', 'L', 'call32.dll')
m.lepage16=regfn('Call32', 'LL', 'L', 'call32.dll')
m.lopen16=regfn('Call32', '***@CLL', 'L', 'call32.dll')
m.lstard16=regfn('Call32', 'LLCL', 'L', 'call32.dll')
m.lstarp16=regfn('Call32', 'LL', 'L', 'call32.dll')
m.lwrite16=regfn('Call32', 'LCLLL', 'L', 'call32.dll')

* open printer and get its handle
* I should have been able to pass 0 as a long/int and get it back as
numeric,
* in fact I'm sure I did this whilst hacking and it worked
* but now it won't so I pass a null dword and convert it to int
m.lhprint=REPLICATE(CHR(0), 4)
=callfn(m.lopen16, m.pprinter, @m.lhprint, 0, m.lopen32)
m.lhprint=dwton(m.lhprint)

IF m.lhprint#0
* docinfo_1 struct - 12 bytes:
* LPCTSTR DocName, 4
* LPCTSTR Output, 4
* LPCTSTR DataType, 4
m.ldocinfo= REPLICATE(CHR(0), 12) && they appear as "Remote Downlevel
Document" having not passed a pointer to a name for the job..

* all the following calls return 0 if they fail
* if that happens then don't bother calling any more, just free libraries
and return
* start document
IF m.lallok
m.lallok=0#callfn(m.lstard16, m.lhprint, 1, m.ldocinfo, m.lstard32)
ENDIF

* start page
IF m.lallok
m.lallok=0#callfn(m.lstarp16, m.lhprint, m.lstarp32)
ENDIF

* write data
IF m.lallok
m.lallok=0#callfn(m.lwrite16, m.lhprint, m.pdata, LEN(m.pdata), 0,
m.lwrite32)
ENDIF

* end page
IF m.lallok
m.lallok=0#callfn(m.lepage16, m.lhprint, m.lepage32)
ENDIF

* end document
IF m.lallok
m.lallok=0#callfn(m.ledoc16, m.lhprint, m.ledoc32)
ENDIF

* close printer
IF m.lallok
m.lallok=0#callfn(m.lclose16, m.lhprint, m.lclose32)
ENDIF


* free libraries
=callfn(m.lfree32)
ELSE
m.lallok=.F.
=MSGBOX('Bad printer name "'+m.pprinter+'" ?', 'Error opening printer..',
48)
ENDIF
ELSE
m.lallok=.F.
=MSGBOX('call32.dll not found.', 'File error..', 48)
ENDIF
RETURN m.lallok

*******************
FUNCTION dwton
*******************
* convert dword to fox numeric
PARAMETERS m.pstr
* pstr - [R] C binary dword

RETURN ASC(SUBSTR(m.pstr, 1, 1))+ ;
ASC(SUBSTR(m.pstr, 2, 1))*256+ ;
ASC(SUBSTR(m.pstr, 3, 1))*65536+ ;
ASC(SUBSTR(m.pstr, 4, 1))*16777216

* END
--
HTH
Andrew Howell
Dennis Allen
2005-10-11 13:53:45 UTC
Permalink
Hi. Wrote your routine, so instead of [??? coutput], I do [do fpwraw
with coutput]. Got to figure out how to let the fpw user specify a
printer name, so I hard wired m.pprinter = "HP LaserJet 5L". Sent a 2
page test. Got 6 pages, several chunks of data out of order. On the
positive side, I didn't get a GPF and the printer control codes seem to
work.


*
PROCEDURE FPWRAW
*
PARAMETERS cDATA

IF .NOT. "FOXPRO 2.6A FOR WINDOWS" $ UPPER(VERSION())
??? cDATA
RETURN
ENDIF

IF SYS(2000,cMEMPATH+'foxtools.fll')=='' .OR.
SYS(2000,cMEMPATH+'call32.dll')==''
RETURN
ENDIF

IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO (cMEMPATH+'foxtools') ADDITIVE
ENDIF

* "Andrew Howell" <***@work>

m.pprinter = "HP LaserJet 5L"

PRIVATE ALL LIKE l*

* returns .T. if all calls OK, .F. if anything went wrong
* (although you may get GPF before you can check return value..)
m.lallok=.T.

m.ldecl32=regfn('Declare32', 'CCC', 'L', cMEMPATH+'call32.dll')
m.lfree32=regfn('FreeCall32IDs', '', '', cMEMPATH+'call32.dll')

* call Declare32 to register 32bit functions
m.lclose32=callfn(m.ldecl32, 'ClosePrinter', 'winspool.drv', 'i')
m.ledoc32=callfn(m.ldecl32, 'EndDocPrinter', 'winspool.drv', 'i')
m.lepage32=callfn(m.ldecl32, 'EndPagePrinter', 'winspool.drv', 'i')
m.lopen32=callfn(m.ldecl32, 'OpenPrinter', 'winspool.drv', 'ppi')
m.lstard32=callfn(m.ldecl32, 'StartDocPrinter', 'winspool.drv', 'iip')
m.lstarp32=callfn(m.ldecl32, 'StartPagePrinter', 'winspool.drv', 'i')
m.lwrite32=callfn(m.ldecl32, 'WritePrinter', 'winspool.drv', 'ipii')

* now register 16bit calls to pass through the 32bit calls
* (actually, 4 of these are identical but it's easier to remember by
(truncated) name <g>)
m.lclose16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
m.ledoc16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
m.lepage16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
m.lopen16=regfn('Call32', '***@CLL', 'L', cMEMPATH+'call32.dll')
m.lstard16=regfn('Call32', 'LLCL', 'L', cMEMPATH+'call32.dll')
m.lstarp16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
m.lwrite16=regfn('Call32', 'LCLLL', 'L', cMEMPATH+'call32.dll')

* open printer and get its handle
* I should have been able to pass 0 as a long/int and get it back as
numeric,
* in fact I'm sure I did this whilst hacking and it worked
* but now it won't so I pass a null dword and convert it to int
m.lhprint=REPLICATE(CHR(0), 4)
=callfn(m.lopen16, m.pprinter, @m.lhprint, 0, m.lopen32)
m.lhprint=dwton(m.lhprint)

IF m.lhprint#0
* docinfo_1 struct - 12 bytes:
* LPCTSTR DocName, 4
* LPCTSTR Output, 4
* LPCTSTR DataType, 4
m.ldocinfo= REPLICATE(CHR(0), 12) && they appear as "Remote Downlevel
Document" having not passed a pointer to a name for the job..
* all the following calls return 0 if they fail
* if that happens then don't bother calling any more, just free
libraries and return
* start document
IF m.lallok
m.lallok=0#callfn(m.lstard16, m.lhprint, 1, m.ldocinfo, m.lstard32)
ENDIF

* start page
IF m.lallok
m.lallok=0#callfn(m.lstarp16, m.lhprint, m.lstarp32)
ENDIF

* write data
IF m.lallok
m.lallok=0#callfn(m.lwrite16, m.lhprint, cDATA, LEN(cDATA), 0,
m.lwrite32)
ENDIF

* end page
IF m.lallok
m.lallok=0#callfn(m.lepage16, m.lhprint, m.lepage32)
ENDIF

* end document
IF m.lallok
m.lallok=0#callfn(m.ledoc16, m.lhprint, m.ledoc32)
ENDIF

* close printer
IF m.lallok
m.lallok=0#callfn(m.lclose16, m.lhprint, m.lclose32)
ENDIF

* free libraries
=callfn(m.lfree32)
ELSE
m.lallok=.F.
=MSGBOX('Bad printer name "'+m.pprinter+'" ?', 'Error opening
printer..', 48)
ENDIF

wait 'fpwraw complete ' window

RETURN m.lallok
Dennis Allen
2005-10-11 14:01:09 UTC
Permalink
I take that back. The chunks of data are not out of order. And since I
can only send data out 1024 bytes at a time, each of the 6 pages is only
1024 bytes long. Is there a way to keep the printer open so I can print
an entire report?
Andrew Howell
2005-10-11 14:42:55 UTC
Permalink
Post by Dennis Allen
I take that back. The chunks of data are not out of order. And since I
can only send data out 1024 bytes at a time, each of the 6 pages is only
1024 bytes long. Is there a way to keep the printer open so I can print an
entire report?
The spool calls in my function go

OpenPrinter
StartDocPrinter
StartPagePrinter
WriteData
EndPagePrinter
EndDocPrinter
ClosePrinter

WriteData is the function that pushes your bytes into the queue, I don't see
why you can't do the first 3 to set it up, then several WriteData calls as
you get the data and finally the last 3 calls to close and tidy up.

Can you not build all the data into a single string and once you have it
all, issue a

m.lsuccess=fpwraw(m.lalldata)

?

I guess wrapping all your pages in StartPagePrinter and EndPagePrinter calls
will result in the correct number of pages showing in the spool queue.

But I'm not certain..
--
Regards
Andrew Howell
Dennis Allen
2005-10-11 18:25:39 UTC
Permalink
I modified the routine is that the first call leaves your variables in
PUBLIC. After printing is done you need to call it to clean things up.
Seems to be working fine. I'll have to try it on the client site to
make sure.

A lot of effort on your part. Thanks. I have an information sheet on
my web site, I'd like to add you and your code to it. Who knows, maybe
some other fpw programmer can benefit from your work...Dennis


*
PROCEDURE fnPRINT_RAW
*
* THE PURPOSE OF THIS FUNCTION IS TO SEND RAW OUTPUT TO SPECIFED
* PRINTER VIA SPOOLER. DESIGNED AS WORK AROUND FOR FOXPRO 2.6A
* FOR WINDOWS BUG.
*
* PARAMETERS:
* cNAME - PRINTER DEVICE NAME, IF NOT CHARACTER THEN RELEASE
LIBRARIES
* cDATA - DATA OUTPUT
*
* PUBLIC:
* cMEMPATH - MEMORY FILE PATH STRING
* cPR_NAME - PRINTER DEVICE NAME
*
PARAMETERS cNAME, cDATA

IF .NOT. "FOXPRO 2.6A FOR WINDOWS" $ UPPER(VERSION())
IF TYPE("cDATA") = "C"
??? cDATA
ENDIF
RETURN .T.
ENDIF

IF !fnFILE(cMEMPATH+'foxtools.fll') .OR. !fnFILE(cMEMPATH+'call32.dll')
IF TYPE("cDATA") = "C"
??? cDATA
ENDIF
RETURN .T.
ENDIF

m.pprinter = ALLTRIM(IIF(TYPE("cNAME") = "C", cNAME,
IIF(TYPE("cPR_NAME")="C", cPR_NAME, "")))
IF EMPTY(m.pprinter)
IF TYPE("cDATA") = "C"
??? cDATA
ENDIF
RETURN .T.
ENDIF

IF !'FOXTOOLS' $ SET('LIBRARY')
SET LIBRARY TO (cMEMPATH+'foxtools') ADDITIVE
ENDIF

* "Andrew Howell" <microsoft.public.fox.programmer.exchange>

PRIVATE ALL LIKE l*

* returns .T. if all calls OK, .F. if anything went wrong
* (although you may get GPF before you can check return value..)
m.lallok=.t.

IF TYPE("_decl32") = "U"
PUBLIC _decl32, _free32, _close32, _edoc32, _epage32, _open32,
_stard32, _starp32, _write32
PUBLIC _close16, _edoc16, _epage16, _open16, _stard16, _starp16,
_write16
PUBLIC _hprint, _docinfo

_decl32=regfn('Declare32', 'CCC', 'L', cMEMPATH+'call32.dll')
_free32=regfn('FreeCall32IDs', '', '', cMEMPATH+'call32.dll')

* call Declare32 to register 32bit functions
_close32=callfn(_decl32, 'ClosePrinter', 'winspool.drv', 'i')
_edoc32=callfn(_decl32, 'EndDocPrinter', 'winspool.drv', 'i')
_epage32=callfn(_decl32, 'EndPagePrinter', 'winspool.drv', 'i')
_open32=callfn(_decl32, 'OpenPrinter', 'winspool.drv', 'ppi')
_stard32=callfn(_decl32, 'StartDocPrinter', 'winspool.drv', 'iip')
_starp32=callfn(_decl32, 'StartPagePrinter', 'winspool.drv', 'i')
_write32=callfn(_decl32, 'WritePrinter', 'winspool.drv', 'ipii')

* now register 16bit calls to pass through the 32bit calls
* (actually, 4 of these are identical but it's easier to remember by
(truncated) name <g>)
_close16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
_edoc16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
_epage16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
_open16=regfn('Call32', '***@CLL', 'L', cMEMPATH+'call32.dll')
_stard16=regfn('Call32', 'LLCL', 'L', cMEMPATH+'call32.dll')
_starp16=regfn('Call32', 'LL', 'L', cMEMPATH+'call32.dll')
_write16=regfn('Call32', 'LCLLL', 'L', cMEMPATH+'call32.dll')

* open printer and get its handle
* I should have been able to pass 0 as a long/int and get it back as
numeric,
* in fact I'm sure I did this whilst hacking and it worked
* but now it won't so I pass a null dword and convert it to int
_hprint=REPLICATE(CHR(0), 4)
=callfn(_open16, m.pprinter, @_hprint, 0, _open32)
_hprint=dwton(_hprint)

IF _hprint # 0
* docinfo_1 struct - 12 bytes:
* LPCTSTR DocName, 4
* LPCTSTR Output, 4
* LPCTSTR DataType, 4
_docinfo= REPLICATE(CHR(0), 12) && they appear as "Remote Downlevel
Document" having not passed a pointer to a name for the job..
* all the following calls return 0 if they fail
* if that happens then don't bother calling any more, just free
libraries and return
* start document
IF m.lallok
m.lallok=0#callfn(_stard16, _hprint, 1, _docinfo, _stard32)
ENDIF

* start page
IF m.lallok
m.lallok=0#callfn(_starp16, _hprint, _starp32)
ENDIF
ELSE
m.lallok = .f.
ENDIF

IF .NOT. m.lallok
DO ERR WITH 'Bad printer name "'+m.pprinter+'" ?', 'Error opening
printer..'
RETURN .f.
ENDIF
ENDIF

IF TYPE("cNAME") = "C"
* write data
IF _hprint # 0
IF m.lallok
m.lallok=0#callfn(_write16, _hprint, cDATA, LEN(cDATA), 0,
_write32)
ENDIF
IF .NOT. m.lallok
DO ERR WITH 'Error writing to printer..'
ENDIF
ENDIF
ELSE
IF _hprint # 0
* end page
IF m.lallok
m.lallok=0#callfn(_epage16, _hprint, _epage32)
ENDIF

* end document
IF m.lallok
m.lallok=0#callfn(_edoc16, _hprint, _edoc32)
ENDIF

* close printer
IF m.lallok
m.lallok=0#callfn(_close16, _hprint, _close32)
ENDIF
ENDIF

* free libraries
=callfn(_free32)

RELEASE _decl32, _free32, _close32, _edoc32, _epage32, _open32,
_stard32, _starp32, _write32
RELEASE _close16, _edoc16, _epage16, _open16, _stard16, _starp16,
_write16
RELEASE _hprint, _docinfo
ENDIF
RETURN m.lallok
*
*
* PRINT RAW ROUTINES SECTION.
*
FUNCTION dwton
*
* convert dword to fox numeric
*
PARAMETERS m.pstr
* pstr - [R] C binary dword

RETURN ASC(SUBSTR(m.pstr, 1, 1))+ ;
ASC(SUBSTR(m.pstr, 2, 1))*256+ ;
ASC(SUBSTR(m.pstr, 3, 1))*65536+ ;
ASC(SUBSTR(m.pstr, 4, 1))*16777216
*
* PRINT RAW ROUTINES SECTION EXIT.
*
Andrew Howell
2005-10-12 07:50:54 UTC
Permalink
Post by Dennis Allen
I modified the routine is that the first call leaves your variables in
PUBLIC. After printing is done you need to call it to clean things up.
Seems to be working fine. I'll have to try it on the client site to make
sure.
A lot of effort on your part. Thanks. I have an information sheet on my
web site, I'd like to add you and your code to it. Who knows, maybe some
other fpw programmer can benefit from your work...Dennis
No worries, I started to get a bit interested in the problem after I
reproduced your GPF. There are a couple of places I may use the code here.
I also thought about the network printer not working. If you use the UNC
path to the shared printer (ie \\servername\printershare) rather than the
name of the connection in the printers folder then it works fine.

Feel free to post on your website, I'd be honoured :-) certainly a first
having someone else publish my work (the function calls are originally
pinched / translated from a KB article describing how to do the same in VB.)
I was originally going to post a link to the code because of line wraps but
decided it would be more useful for others to get it indexed on google
groups.
--
Regards
Andrew Howell
swdev2
2005-10-06 06:36:38 UTC
Permalink
ug ug - get the book, ah ?
http://www.hentzenwerke.com/catalog/painless.htm

hopefully it will sort you out.
regards [Bill]

--
===================
William Sanders / EFG VFP / mySql / MS-SQL
www.efgroup.net/vfpwebhosting
www.terrafox.net www.viasqlserver.net
Post by Dennis Allen
Hi. Got a client getting new XP machines. Still wants to run FoxPro
1) Created a command prompt desktop shortcut icon. Very little
available memory in FoxPro for DOS. Don't see any memory option in the
shortcut properties.
2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).
3) FoxPro 2.6 for Windows. Sending output directly to printer lpt1
(???) causes general protection fault. Sending output to normal spooler
(?) goes to local printer, regardless of lpt?.
If anyone has a solution to any of these issues, I'd greatly appreciate
the help...Dennis
ezopaci
2005-10-06 13:02:35 UTC
Permalink
About item 1 and 2:
You have to set memory parameters on file _DEFAULT.PIF in \WINDOWS\
directory.
There are much diferences between LNK and PIF shortcut. You should use
PIF. Try drag&drop (by rightclick and "create shortcut") BATch file
onto desktop and try !DOS! EXE file. In case of EXE, windows creates
PIF shortcut.

Tomas



--
ezopaci
------------------------------------------------------------------------
Posted via http://www.codecomments.com
------------------------------------------------------------------------
Dennis Allen
2005-10-06 16:22:34 UTC
Permalink
Easier solution. From the command prompt, try FOX +X.
Post by ezopaci
You have to set memory parameters on file _DEFAULT.PIF in \WINDOWS\
directory.
There are much diferences between LNK and PIF shortcut. You should use
PIF. Try drag&drop (by rightclick and "create shortcut") BATch file
onto desktop and try !DOS! EXE file. In case of EXE, windows creates
PIF shortcut.
Tomas
--
ezopaci
------------------------------------------------------------------------
Posted via http://www.codecomments.com
------------------------------------------------------------------------
John Seale
2005-10-06 17:03:12 UTC
Permalink
For #2, try putting DISPLAY=VGA25 in config.fp.

If that doesn't work, start the app, press Alt-Enter to go to windowed mode.
Then right-click in the title bar, go to Properties, Layout. Change the
Height in Screen Buffer Size and Window Size to 25. In the Apply Properties
dialog, select "Save properties for future windows with the same title."
Dennis Allen
2005-10-06 17:59:22 UTC
Permalink
That did it. Thanks...Dennis
Post by John Seale
For #2, try putting DISPLAY=VGA25 in config.fp.
Neil Waterworth
2005-10-06 18:17:04 UTC
Permalink
Post by Dennis Allen
2) Created a batch file desktop shortcut icon. Plenty of memory in
FoxPro for DOS, but comes up in 43 line mode when set to full screen
(changing the shortcut property font size does nothing).
In the properties->layout tab of the shortcut, set the screen buffer size
and window size to width=80 and height=25.

Regards,
Neil
Continue reading on narkive:
Loading...