SQLExpress - Xb2.NET     ot4xb  
xfree.resources (readonly)
Phil Ide Packages
Thread Starter: Pablo Botella Started: 5/7/2008 1:45 PM UTC
Replies: 19
Phil Ide Packages
Hello,

In this thread you can found the packages rescued from the web site of Phil Ide

As this site is readonly, to add a package you can use the following NG
news://news.xb2.net/xfree.tmp_unedited
and reply to the corresponding thread with the package attaches as a ZIP file.

Thanks,
Pablo Botella
------------------------------------------------------------------------
Hola,

En este hilo podeis encontrar los paquetes que se han podido rescatar de la web de Phil Ide
Como este sitio es READONLY, para añadir un paquete podeis usar el siguiente NG
news://news.xb2.net/xfree.tmp_unedited
y responder al hilo correspondiente adjuntando el packete como fichero ZIP

Gracias,
Pablo Botella

 

------------------------------------------------------------------------
Hello guys
In this area, we want to post all Phil Ide source' code that we found it.
So, please if some want to share, send it to me and I will upload ASAP.
Thanks Phil

Best Regards
Osvaldo Ramirez
------------------------------------------------------------------------
XML
XML [ Modified by Javier (Syga System) ]
This code is based on the XML work from Phil, this class was changed by Javier from Syga System, S.L and try to use XSD files and convert it to XML

HTH
Osvaldo Ramirez

-------------------------------------------------

Codigo para usar XML y mejorado por nuestro amigo Javier de Syga System, S.L. el cual permite usar Documentos XSD y convertirlos en XML

Espero que les sirva
Osvaldo Ramirez

This message includes the following attachments:

XbFPT
Rescued by: Hector Pezoa, Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
--------------------------------------------------------------------
  Author: Phil Ide
  Special thanks to:
     Mike Grace for finding most of the bugs
     John Caswell for finding another bug
     John Caswell for supplying the sendCommand method to send
          arbitrary commands to the server.
--------------------------------------------------------------------

This message includes the following attachments:

XbSSL - SSL Wrapper for OpenSSL and ASINET
Rescued by: Hector Pezoa
--------------------------------------------------------------------
Author : Phil Ide
Created: 07/04/2004
--------------------------------------------------------------------
XbSSL  - SSL Wrapper for OpenSSL and ASINET

Introduction
  This library will provide SSL capability to Alaska's ASINET internet protocols communications library. Provisionally it will concern itself with HTTPS, and at some later stage will provide SSL capability to FTPS, SMTPS etc.

It uses the OpenSSL libraries to achieve this. If you do no already have these, you should read the next section.  

Installing OpenSSL
  You need to get the Win32 OpenSSL binaries. Once you have them, run the installation package and select the default installation options. Once installed, you can (perversely) uninstall them. The uninstallation leaves the required DLL's in your %windows%\system32  directory, but removes the source code (which you probably don't want).    The two DLL's are called libeay32.dll and ssleay32.dll. You can copy these to an application directory if you wish, or bundle them with your application.  

Caveats
  At this stage, the XbSSL() class is experimental. Each release will certainly work under at least one or more circumstances, but only testing will prove whether it will work under all circumstances. Additionally, since it is experimental, the exposed methods may change to incorporate a more generic or easier to use interface. Further, it is likely that a base class will be created in the future, with child classes to cater specifically for each of the various protocols.  

Update History
  v0.1
  Basic connection to HTTPS servers.    By default uses v3 contexts for clients.
  This will change in th future to use    Does not properly implement SERVER contexts --------------------------------------------------------------------

This message includes the following attachments:

ABS182
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 09-Feb-2005
--------------------------------------------------------------------
Xbase++ 1.90 changes the architecture of the class system in a subtle
but important way.

The ACCESS ASSIGN METHOD NoIvarCallback is no longer supported.  In
future projects, you should use getNoIvar(), setNoIvar().  However, to
minimise the amount of changes you have to make to your source code so
it compiles (and runs properly) with 1.90, follow the instructions
below.

NOTE:  This is ONLY necessary if you have implemented the NoIvarCallback
in your classes.

To include this class, simply add it to your projects, and when you
declare a class definition, make this class part of the inheritance
chain.  This is best achieved at the most senior level of class.

For example:

CLASS myClass FROM AbstractCompatibility182
...
ENDCLASS

Now myClass and any class that inherits from it will be compatible
with Xbase++ 1.82's architecture.
--------------------------------------------------------------------

This message includes the following attachments:

AJAX
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 18-Jun-2005
--------------------------------------------------------------------
Using AJAX with WAA and javascript

This message includes the following attachments:

Smart Object
Rescued by: Hector Pezoa, Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Versions: 2005.09.05 and 2003.12.18
--------------------------------------------------------------------
Author: Phil Ide
--------------------------------------------------------------------

Current version: 1.4

SmartObjects is a term I coined to describe classes of objects that utilise the inbuilt
error handling of the class system in XBase++ to do two things:

1.  Require the object to interpose between the program and the data
   for both inbound (assign) and outbound (read) access.

2.  To protect the raw data from the program whilst still providing a
   property (iVar) interface.

There are probably lots of ways where this could prove useful, but as an example
(and remember, this is not the only use) I have created a series of classes which
emulate C/C++ structures.  For other examples, checkout:

   GPContainer() is a general purpose container class for arbitrary
   collections of data.  It is compatible with all versions of Xbase++.

   GPContainerPGSql() builds on the properties and features of
   GPContainer(), to provide automatic creation of SQL statements and
   firing them at the PostgreSQL server.

Now, back to SmartObjects...

Note that these classes are not complete (I'll leave that as an excercise for you),
and therefore do not handle the following:

   a) Unions
      This could be implemented, but as yet I don't have the need and
      I have too many other projects demanding my attention.

   b) Members by reference
      You cannot create individual members as pointers.

   c) Callbacks
      This is another facet of 'Members by reference'.

So what does the Structure() classes give?

1.  Strict typing at runtime.  Create a ULONG and it must be both numeric     and positive, and it's value must fit in 32 bits.  Assign any other value,     and you'll get an error.

2.  The ability to emulate many WinAPI structures, or create your own.  With the
   exceptions that the classes cannot handle (see above), there is only one other
   caveat:

      Occassionaly, a C/C++ compiler will extend a structure to a boundary.  When
      passing a structure to a WinAPI function, the structure must be of the        expected size.  The classes here cannot determine under what conditions
      this resizing occurs, and therefore the structures are predetermined by the
      accumulated size of the members.

   Other than this occassional problem, creating structures and using them seems
   to work fine.

In addition, the Structure() classes contain a .cargo slot.  This member variable
does not form part of any structure, but is always available for storing
arbitrary information.

There is also a sizeOf() method, which can be used to determine the
current size of the structure.  Some structures contain a variable
length member at the end of the member list, and if so the size of the
structure is affected by the current length of this member, otherwise
sizeOf() will return a constant value for each structure definition.

 e.g.:  myStruct.sizeOf() -> nSize


To create a structure, you use this syntax:

STRUCTURE <structName>
  <type> <membername> [SIZE <nSize>]
  [<type> <membername> [SIZE <nSize>]]
  [STRUCT <membername> AS <structureName>]
ENDSTRUCT

The supplied example classes offer member types of:
     WORD
     DWORD
     HANDLE
     INT
     UINT
     SHORT
     USHORT
     LONG
     ULONG
     CHAR

The test project creates an executable called SOTEST.EXE.  Running this will cause a
few lines of output followed by a runtime error.  You should run the application
through a debugger to find out what is going on.  The first time, simply F10 to step
through each statement in the test program, then if you are interested, try F8 to step into the classes themselves and see why they behave the way they do.

Remember, the classes supplied here and the test program are only to show you how
things can be made to work.  SmartObjects is a philosophy, not a set of classes.

If you find any other interesting uses for SmartObjects, please let me know.
Any examples supplied could also find themselves in this package, so please feel
free to show me what you've done.

Regards
-- Phil Ide.

This message includes the following attachments:

Gradient
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 09-Apr-2003
--------------------------------------------------------------------
CLASS TriGradientForm FROM GradientForm
  EXPORTED:
     METHOD init
     METHOD create
     METHOD buildVertex
ENDCLASS
--------------------------------------------------------------------
CLASS GradientForm FROM XbpDialog
  EXPORTED:
     VAR aColor
     VAR gRect
     VAR gradientDirection
     VAR vertex
     VAR bVertex

     METHOD init
     METHOD create
     METHOD subpaint
     METHOD TriVertEx
     METHOD setColor
     METHOD buildVertex
ENDCLASS
--------------------------------------------------------------------

Function Dialog1( aMetric, nWidth, nHeight )
  local aPos[2]
  local oDlg

  aPos[1] := (aMetric[1] - (nWidth/2)) - 20
  aPos[2] := aMetric[2] + 20

  oDlg := GradientForm():new(,,aPos,{nWidth,nHeight})
  oDlg:title := "[Rectangle] graduate from left to right"
  oDlg:sysmenu := TRUE
  oDlg:tasklist := TRUE

  oDlg:setColor(1,14,23,92)
  oDlg:setColor(2,198,205,254)

  oDlg:create()
  return oDlg

This message includes the following attachments:

capwin
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 17-Oct-2003
--------------------------------------------------------------------
There are three functions:

CaptureWindow(hWnd) -> oXbpBitMap

 returns a bitmap object of the selected window

 hWnd can either be the handle of the window (oDlg:getHWnd()), or
 you can just pass the window object in and the function will resolve
 the handle itself.

CaptureWin2File( oDlg, cFile, nImgType ) -> lSuccess

 return TRUE if the file was successfully saved.

 oDlg is either a window object or a window handle.

 cFile is the name of a file to save to.  This is optional, and
 the default will be 'ScreenDump'.  The file extension is dependant
 upon the image format requested.

 nImgType is one of the image types supported by Xbase++. Use one
 of the XBPBMP_FORMAT_* constants.

 If the file extension is specified, it will be used regardless of
 whether it matches the requested format.

 If the file already exists, it will be overwritten.

PrintWindow( hWnd ) -> NIL

 hWnd must be a valid window handle.  This is a C function which captures
 the selected window as a bitmap and copies it to the clipboard.

 To use this function, you must include this line in your source:

     #include "printWin.ch"

Note that you can pass controls instead of windows.  The example code shows
firstly a capture of a window, then the capture of a pushbutton.

This message includes the following attachments:

FReader
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 04-Jun-2005
--------------------------------------------------------------------
FileReader
Author  : Phil Ide
Copyright Phil Ide 2004-2005, All Rights Reserved

Version 1.0
  Basic API's implemented for:
     Generic Dynamic Read
     TBrowse
     XbpBrowse
     XbpQuickBrowse

Purpose:
  Create a generic class for reading individual lines from an ASCII text
  file, where lines (or records) are delimited by some token.  Usually
  the token would be a Carriage-Return/Line-Feed pair, but this is
  configurable.  The class attempts to minimise and optimise the loading of
  data by caching unread lines and storing information about line offsets
  and their length.  The cache is nominally 4Kb in size, and will not
  usually grow beyond 8Kb at most, although this is dependant upon the data
  you are attempting to access.

  The class opens a file for reading in shared mode, and will work in one
  of two basics modes:

  Mode #1 - Dynamic Access
  ------------------------
  In this mode, the reader knows very little about the file except that it
  has successfully opened it, and the records/lines are delimited by a
  known token.  As each line is requested, the class determines whether
  it knows anything about that line (i.e. the starting offset within the
  file, and the length of the line).  If it knows about the line - i.e. it
  has read the line before - then it can easily reload the data for that
  line.  If it does not know about the line, then it must load any lines
  between the last line it knows about and the requested line.  As it loads
  each line, it accumulates knowledge about the file, aiding fast
  navigation to parts of the file it already knows about.

  Mode #2 - Examined Access
  -------------------------
  In this mode, the class must perform an examination of the file before it
  can be properly used (this is achieved via the ::examine() method).  This
  build a list of line offsets from which it is possible to browse the data
  based purely on line numbers.  Once examined, the class can be used in
  TBrowse, XbpBrowse and XbpQuickBrowse.

Basic Navigation:
-----------------
Navigation through the data is achieved through the ::skip(<n>) method,
where <n> is NIL or any positive or negative number.  Like dbSkip(), it will
only advance/recede where there are lines of data to traverse, so if
the current line number is 2 and you ::skip(-5), the resulting current line
will be line #1.  The same goes for attempts to skip past the end of file.

The current line number can usually be determined by the iVar ::curLine.

An alternative to ::skip(-1) is ::rewind(), which performs exactly the
same operation.  Note that neither ::skip() nor ::rewind() actually read
data (except where ::skip() takes the file pointer beyond any data the class
has so far read).  ::skip(0) does not do anything - it does not re-align the
data pointer, the file cursor or re-read the current line.

To fetch the data for the current line, use the method ::readLine().
Using this method automatically advances the ::curLine pointer to the
next line after the data has been read.

You can go to a specific line using ::goTo(<n>), but only if the file has
previously been ::examine()'d or the target line has already been read.

METHODS and IVARS
=================
Class Methods
-------------
:new(<cFile> [,<cEOLToken>]) -> oFileReader

  Creates an instance of the FileReader() class.

  <cFile> is the name of the file to access, and may include a full path.

  <cEOLToken> is an option string defining the end-of-line token that
  delimits lines/records.  The default is a carriage-return/line-feed pair.

Configuration
-------------
:stripEOL
  This logical value indicates whether the return value of :readLine()
  should strip the end-of-line token from the result.  The default is TRUE,
  ensuring the end-of-line token is not returned.

:dataWidth
  This numeric value is used in XbpQuickBrowse to determine the fixed-width
  of the return value.  The default is 72 (chars), and :readLine() will
  right pad the the return value to this length.

Life Cycle
----------
:configure() -> self

  Resets the object to the pristine state as is it had just been created
  with FileReader():new().  This releases buffered data and and destroys
  any knowledge about the current file.  It will continue to use the same
  file.

:close() -> self

  As for :configure() but also closes the file handle.


Navigation Methods
------------------
:goBottom() -> self

  Sets the last (known) line as the current line.

:goTo(<n>) -> lSuccess

  Sets the current line pointer to line <n>.  Returns TRUE if successful.

:goTop() -> self

  Sets the first line as the current line.

:rewind() -> lSuccess

  Decrements the current line pointer.  Returns TRUE if successful.

:skip(<n>) -> nSkipped

  Advances the current line pointer by <n> lines if positive, or
  decrements the line pointer if negative.  Returns the actual number of
  lines it was possible to skip.

:goPosition(<n>) -> nCurrentLine

  Sets the current line using a percentage - i.e. :goPosition(25) will
  locate theline which is at the position 25% from the start of the file.
  Note that this is only an approximation.  Returns the actual line
  number that is set as the current line.


Methods
-------

:eofPos() -> nEofPos

  Returns the offset of the end-of-file - in other words, the file size.

:examine() -> self

  Causes the object to build a list of information about the lines of
  data in the file.  This must be called before using any type of browse (
  TBrowse, XbpBrowse, XbpQuickBrowse).  Note that for XbpBrowse, the method
  :configureXbpBrowse() automatically calls :examine().

  Depending upon file size, this can be a time consuming processes.
  Files of 12Mb will usually take around 2-3 seconds, depending upon CPU
  speed, memory etc.

:lineNo() -> nCurLine

  Returns the current line number.

:reexamine() -> lDataAdded

  This causes the object to check the file to see if any new data has
  been added to the file by another process/thread, and if there is new
  data to perform a mini :examine() to add the information on te new data
  to the object.  The method returns TRUE is new data is available.

:readLine() -> cLine

  Returns the current line of data.  The pointer indicating the current
  line is advanced by one.

:position() -> nPos

  Returns the current line number as a percentage of the total number of
  lines.  You must have called :examine() for this method to return a
  meaningful result.

:currentLine() -> cLine

  Rereads the data for the current line without advancing the current
  line pointer.

:fileName() -> cFile

  Returns the full name (including path if supplied) of the file being
  accessed.

:baseFileName() -> cFileName

  Returns the file name of the file being accessed without any path
  information.

XbpBrowse specific methods
--------------------------
:configureXbpBrowse( <oBrowse> ) -> self

  Having initialised an XbpBrowse, call this method passing the
  browse ojbect as a parameter, before the browse is :create()'d.

  This method installs the correct skip blocks and performs an automatic
  :examine() of the FileReader() object (this allows the scroll bars to
  work correctly).


XbpQuickBrowse specific methods
-------------------------------
The following methods are used to emulate the DacPagedDataStore class, and
should not be used directly.

  :getRowData()
  :getRowInfo()
  :bindView()
  :setAbsolutePageSize()
  :getPos()
  :getRelativePageSize()
  :scrollDown()
  :scrollUp()
  :isFirst()
  :isLast()
  :rowCount()
  :getRowCount()
  :goFirst()
  :goLast()
  :goPrev()
  :goNext()

This message includes the following attachments:

iniedit
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Author : Phil Ide
Created: 30-Jul-2003
--------------------------------------------------------------------
Application: IniEdit.exe
    Author: Phil Ide
 Copyright: Phil Ide 2003, All Rights Reserved

Additional Code:
    Program: TINIFILE
     Author: Matt Hamilton  (Corrections to ':ReadString' by Terry Wolfe)
                            ( Down loaded from TheOasis )
  Copyright: Released to Public domain by Original Author Matt Hamilton
               Corrections to ':ReadString' released to public domain
               by Terry Wolfe of Service Education, Inc.
       Date: 11/22/99
    Purpose: A Class to handle the .INI files
==========================================================================

IniEdit is written chiefly as an example of how to make an XbpTreeView
co-operate with an MLE and an SLE (and the MLE co-operate with the SLE
and the XbpTreeView etc.).

For another example, please see Folder Browser, also available from my
site. http://www.idep.org.uk/xbse/foldbrow.zip

You can simply run IniEdit, in which case it will prompt you for an
ini file to edit, else you can pass the filename on the command line.
If you use the command line option, then you must pass the extension.

By default, Windows expects ini files to be in the %windir% directory
unless you supply a full path.  IniEdit however, always checks the
current directory, and only falls back on %windir% if the file is not
found.

If the file is not found (and if no path is supplied and it is not in
%windir%), then IniEdit will simply quit without notification.

You can use the treeview to browse the entire file.  If you highlight
a section, then the entire section appears within the MLE.

You can navigate within a section using either the treeview or the MLE -
to use the MLE, simply click on a line containing a value.

To edit a value, click on the SLE, type the new value and press the
enter key. The ini file is updated immediately, and the MLE will reflect
the change immediately too.

To delete either a key or a section, highlight it in the treeview and
right-click to bring up a context menu.

The 'Cancel' button will restore the original file and then quit the
application.


Regards,
--
Phil Ide
http://www.idep.org.uk/xbase

This message includes the following attachments:

INI Files
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
   Program: TINIFILE
     Author: Matt Hamilton  (Corrections to ':ReadString' by Terry Wolfe)
                            ( Down loaded from TheOasis )
  Copyright: Released to Public domain by Original Author Matt Hamilton
               Corrections to ':ReadString' released to public domain
               by Terry Wolfe of Service Education, Inc.
       Date: 11/22/99
    Purpose: A Class to handle the .INI files
--------------------------------------------------------------------
TIniFile for XBase++ by Mab (Matt Hamilton)
==============================================

This is a direct port of the TIniFile class from Borland Delphi.
It encapsulates the GetPrivateProfile* and WritePrivateProfile* functions
in the Windows API.

This is free! Use it at your own risk, but I'm fairly sure its safe!

Cheers,
Mab
mhamilton@bunge.com.au

----------------------------------------------
The methods included are:

init(AFilename)
Creates a new TIniFile with the given filename. If the full path is
not given, then the file is created/found in the windows directory.

Example: IniFile := TIniFile():New("win.ini")

ReadSections(AList)
Returns in AList an array of all the section names in the inifile.
AList must have already been initialised to {}.

Example: IniFile:ReadSections(SectionList)

ReadSection(ASection, AList)
Returns in AList an array of all the key names in the given section.
AList must have already been initialised to {}.

Example: IniFile:ReadSections("Desktop", KeyList)

ReadSectionValues(ASection, AList)
Returns in AList an array of all the key names and their values in
the given section.
Each element in the resulting list will have the form "key=value".
AList must have already been initialised to {}.

Example: IniFile:ReadSectionValues("Desktop", KeyList)

ReadString(ASection, AKey, ADefault)
Returns the string specified in AKey and ASection. If the key or
section are not found, returns ADefault. ADefault must be specified.

Example: LastUser := IniFile:ReadString("Options", "LastUser", "Mab")

ReadInteger(ASection, AKey, ADefault)
Returns the integer specified in AKey and ASection. If the key or
section are not found, returns ADefault. ADefault must be specified.

Example: Width := IniFile:ReadInteger("Options", "Width", 80)

ReadBool(ASection, AKey, ADefault)
Returns the logical value specified in AKey and ASection. If the key or
section are not found, returns ADefault. ADefault must be specified.

Example: IsNew := IniFile:ReadBool("Options", "New", .t.)

WriteString(ASection, AKey, AString)
WriteInteger(ASection, AKey, AnInteger)
WriteBool(ASection, AKey, ABool)
Writes the given data back to the ini file.

Example: IniFile:WriteString("Options", "LastUser", "Mab")

DeleteKey(ASection, AKey)
Removes the given key from the ini file.

Example: IniFile:DeleteKey("Options", "LastUser")

EraseSection(ASection)
Removes the given section from the ini file.

Example: IniFile:EraseSection("Options")

This message includes the following attachments:

IPC Signal
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Class      : IPCSignal()
Description: Inter-Process Signal() class
Author     : Phil Ide
--------------------------------------------------------------------
Within a process (application), you can use the Signal() class to
cause one thread to wait for another.  Both threads have to have a
reference to a single instance of the Signal() class.

One thread issues an oSignal:wait(), which puts the thread to sleep
until it recieves a signal.  The signal is issued by the other thread by
calling oSignal:signal().

If you have 3 threads, two can be placed into a sleep state, but when
the signal is issued, both sleeping threads come alive again.

The Signal() class can be used to synchronize two or more threads within
a single application, but you cannot 'queue' requests (i.e. the sleeping
threads come alive one at a time) and you cannot use the class to
synchronize two (or more) sperate applications.

The IPCSignal() class resolves these issues. When you create an instance
of this class, it attempts to create a MUTEX, and then it tries to
gain control over it.  Only one thread across all applications can
gain control of a mutex.

When the controlling thread has finished with the mutex, it releases it,
and control is automatically passed to the next thread waiting to gain
control, no matter which application that thread is in.

This fine control of mutexes is available through the WinAPI.

Since it uses mutexes, there is no need to pass instances of the
IPCSignal() class either between threads or applications.

Synposis:

  create object, define mutex name
  The mutex name must be exactly the same in all applications
  which wish to use this mutex.
 
  oSignal := IPCSignal():new('MY_MUTEX')

  create() gets handle to mutex
 
  oSignal:create()

  after create, we may actually already have control.
  we can test this easily:
 
  oSignal:isOwner()

  wait() will put thread to sleep until control is gained
  if we already have control, returns immediately
 
  oSignal:wait()

  when we have finished blocking other threads/applications
  we need to pass control to next waiting thread
 
  oSignal:signal()

You can pass a numeric parameter to the wait() method, which defines its
behaviour:

  Value    Meaning
  ----------------
  -1       Attempt to gain control, return immediately
           (use oSignal:isOwner() to see if you have control)

   0       Wait forever until control is gained

  0       Timeout period in seconds
           use oSignal:isOwner() to see if you have control
           test oSignal:lTimeOut to see if timeout occurred

Additional methods:

  :name()     returns name of MUTEX (or NIL if not defined)
  :handle()   returns handle of mutex (or 0 if not available)

This message includes the following attachments:

JS Recruiter
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Application: JSR.EXE
Author     : Phil Ide
(c) Copyright Phil Ide 2006
---------------------------

WARNING:
-------------------------------------------------------------
To compile and link the source code, you'll need a developer edition
of HRF2 (you cannot use the version of HRF2 that comes with xbHCL unless
you have also purchased a seperate licence for HRF2).
-------------------------------------------------------------

This is an example application using HRF2. It fetches all the
'recruiter' names and addresses from Jobserve (www.jobserve.com) in
the IT section. The recruiters are usually recruitment agencies, but
may also be a company (e.g. ABN AMRO).

There is a filter you can use to collect just recruiter info for Great
Britain, just Australia, or both.

Usage:
  jsr              // default = GB recruiters
  jsr gb           explicitely gb recruiters
  jsr au           just au recruiters
  jsr gbau         both au and gb recruiters (mixed)

The program works by requesting a 'start' page - a start page is the
first page in each alphabetic category, i.e. the first page of
recruiters beginning with 'A', the first page of recruiters beginning
with 'B' etc. (the 'A' page also contains non-alpha recruiters, such
as @its, 100% group etc.).

It extracts the list of recruiter names from the page, plus the link
to the details page for each recruiter, which it then fetches and
extracts the address and contact details for the recruiter.

Once it has extracted all the details for all the recruiters on the
page, it then checks to see if there are any additional pages in this
category by looking for hyperlinks at the bottom of the page to
subsequent pages, and repeats the process for each of those.

Details are recorded in a file named 'recruiter_x.dbx', where x is 'gb',
'au' or 'gb_au' depending upon which data it has been asked to fetch.
This is a plain text file, with records delimited by CRLF+'=='+CRLF.
Fields for the record are named with a colon following the name and
the data immediately afterward and the field terminated by CRLF. The
exception to this are the Address: fields, which have the data
starting on the next line.

Example:

Access Computer Consulting Plc
JS-ID=18258
Contact: Ed Turvey
Phone: 01256 368800 Fax: 01256 368811
Email: info@accessplc.com

Address:
25-29 Church Street
Basingstoke
Hampshire
RG21 7QQ
England
==

Note that the recruiter name has no 'Name: ' tag. The JS-ID is the
Jobserve unique id for this recruiter.

This format allows some data to be missing (e.g. some recruiters have no
address or contact details), whilst still allowing the records to be
extracted programmatically using Xbase++ or Perl.

Using a 2Mb broadband connection, it took 10 minutes to fetch all the GB
details, and 1 minute 22 secs to fetch all the AU data.

You'll note the DOM addresses used in the code to fetch various nodes
from the currently downloaded page. These addresses were determined by
examining the page in httpAnalyze.exe, which is also written using
HRF2 and allows you to view the page source in a treeview.

At the time this code was written, these DOM addresses returned the
required nodes (html elements) from the page, but Jobserve may change
the layout or structure of the page at any time in the future, in
which case the DOM addresses will probably change.

This message includes the following attachments:

Load From URL
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
Function: LoadFromUrl.prg
Author  : Phil Ide
Copyright Phil Ide 2004-2005, All Rights Reserved

Version 1.15
  Fix to LoadFromUrlObject() not passing through the bFtpCallBack
  code-block.

Version 1.14
  Allows news:// url's to be called.  Requires ASINET or Xb2.NET to
  access news url's, but can be compiled without either.

  WARNING: lfromurl.ch has been updated!

Version 1.13
  Allowed callback in HTTP/HTTPS to allow progress display and to allow
  these types of transfers to be aborted.

  Partial implementation of gopher protocol - doesn't seem to want to
  work, so don't use it - however, if you can see what is wrong, please
  let me know!  There are two different attempts within the source:

    GetGopherFileAAA() - uses WinInet Gopher...() routines
    GetGopherFile()    - uses InternetOpenUrl() for direct access

Version 1.12
  Allowed FTP callback to be called even when the remote filesize
  cannot be determined.
Version 1.11
  Fixed BasicAuth authentication - no longer requires the base64
  encoding routine, so bit-twiddle.lib has been removed.

  Now supports FTP addresses as well. Please see explanation of
  parameters for feedback/progress callback.

Version 1.10
  Made a proper fix for chunked transfers

Version 1.9
  Added 13th parameter (aSendHeaders) which must be passed by
  reference.  This allows the request HTTP headers to be returned.  The
  class has been updated to reflect this.  Note that request headers
  automatically include any suitable cookies.

  Added half-second delay between fetching headers and fetching message
  body when the headers indicate a chunked transfer.  This isn't
  foolproof, as the delay may in some cases need to be longer, but in
  most cases this is sufficient to allow the chunks to arrive.

  This can easily be resolved in W2K3 and XP/SP1 machines by
  switching the WinHTTPAPI interface (instead of the HttpAPI
  interface), which automatically handles chunked transfer encoding.
  However, since that itsn't available on W2K, and Win9x machines, that
  causes a problem.  I might encode some optimisation branching to
  switch between interfaces based on the current OS.

Version: 1.8
  Added LoadFromUrlStatus() function.
  This can be called after LoadFromUrl() to get the result status of
  the query.

  Added LoadFromUrlObject() class.  This makes it easier to handle
  the huge number of parameters.  Some of the new parameters are
  proving very useful and interesting, and making sure the correct
  number of parameters are skipped can be error prone.

  This class always fetches the http headers and the result status,
  so it is not necessary to pass all parameters.  The object created
  has iVars with the same name as each of the parameters to
  LoadFromUrl(), so if you want to set the method you can do this:

    o := LoadFromUrlObject():new(cUrl) all params can be passed here
                                       // the same as in LoadFromUrl()
    o:cMethod := 'POST'
    o:cPostString := 'NAME1=Fred&NAME2=Ginger'

    fire query
    o:exec()

    o:status()                            // 200=ok, 404=Not Found etc.
    AEval( o:aHeaders, {|e| QOUT( e ) } ) print headers
    cData := o:cResource                  // get data


Version: 1.7
  fix for https requests

This version of LoadFromUrl() is 100% compatible with the function of the
same name in Alaska's ASINET library, plus it has some extended
functionality.  Importantly, ASINET is NOT required to either use it or
recompile it.  It is written in pure Xbase++.

In order to use the function, you will also need a copy of XbPCRE, the
Perl Compatible Regular Expression Library and Xbase++ wrappers. This is
available from my site at http://www.idep.org.uk/xbase.

There are 8 basic extensions to the original LoadFromUrl(), which are
identified by the 7 additional parameters detailed below. In addition to
this, there is an external interface to pre-configure additional HTTP
headers.

LoadFromUrl(  cURL         , ;
              [nPortNumber] , ;
              [nProtocol]   , ;
              [cProxyUrl]   , ;
              [acByPass]    , ;
              [cMethod]     , ;
              [cPostString] , ;
              [cHttpHeaders], ;
              [bPreCall]    , ;
              [lHeadersOnly], ;
              [@aHeaders]   , ;
              [aAuthInfo]   , ;
              [@aSendHeaders],;
              [bFTPCallBack])

cUrl
  This is the URL (or URI) of the resource you wish to download.  It should
  be in the form:
     [http[s]://]server[:port][/path_to_resource]

  Note that the URL will take highest priority when setting protocol and
  port options, overriding other parameters.

nPortNumber
  This is the port number that the server is listening on for requests.  If
  it is specified in the URL, the port in the URL takes precedence.

  You can use a constant to specify this value:

     INTERNET_DEFAULT_HTTP_PORT - for HTTP protocol
     INTERNET_DEFAULT_HTTPS_PORT - for HTTPS protocol (secure socket layer)

  If omitted, this parameter defaults to the default port for the specified
  protocol.

nProtocol
  You can specify the protocol to use - note that this setting is
  deprecated if a protocol is specified in the URL.

     INTERNET_COMMUNICATION_PUBLIC selects HTTP protocol
     INTERNET_COMMUNICATION_SECURE selects HTTPS protocol

  If this parameter is missing, and the protocol is not specified in the
  URL, the protocol will default to INTERNET_COMMUNICATION_PUBLIC.

cProxyUrl
  This is the address (name or IP address) of a server to use as a
  proxy.  This takes the same format as the URL, but without a final
  path_to_resource component.

  You can specify more than one proxy to handle different protocols.  To do
  this, use the form:

     protocol=url [protocol=url]

  Example:

     http=http://mydomain.htproxy https=https://mydomain.hsproxy

  If you do not supply this parameter, the function will determine and
  use the system proxy settings (if any).

acByPass
  This is used in conjunction with cProxyUrl, and specifies addresses which
  should bypass the proxy - in other words, if a URL is matched against one
  of the acByPass addresses, the proxy will not be used.  This is useful
  when targetting local network resources.

  acBypass is an array of addresses either in name or IP address format.

cMethod
  By default, the function will use the GET method to transmit data to
  the server.  You can set this value to 'POST', useful for submitting form
  data.  When set to POST, cPostString is mandatory.

cPostString
  This is a CGI encoded string, usually form data, which you want
  transmitted to the server along with the request URL.

cHttpHeaders
  You can pass additional HTTP headers, which will be sent with the request
  to the server. HTTP headers precede any POST data.  You can use this to
  specify language preferences etc.

  You can specify more than one header, by seperating each header with a
  carriage-return/line-feed pair.

bPreCall
  This parameter is a code block which acts as a call-back.  After
  setting up the internet connection and preparing a path to the host
  server, but prior to sending the request data, this code-block gets
  evaluated.  It is passed a handle to the specific internet connection
  negotiating with the host server.

  The purpose of this is chiefly so you can call AddRequestHeadersA() (see
  below).  This is more powerful and flexible than using cHttpHeaders,
  but not as simple to use.

  Example:

     {|h| SetHeaders( h ) }

lHeadersOnly
  When TRUE, this forces the function to only fetch the HTTP headers
  for the resource.  This doesn't request the resource, fetch the
  headers then abort, it specifically requests only the headers for
  the resource.  To fetch the resource as well you must make a second
  call to LoadFromUrl() with lHeadersOnly to false.  The default for
  this parameter is FALSE.  Note that the return type changes if this
  is TRUE.
aHeaders
  This parameter must be passed by reference.  If passed, it will be
  populated with an array containing the HTTP headers for the resource.
  This can be used to fetch the HTTP headers AND the resource in a
  single call (lHeadersOnly must be FALSE).  The function is
  optimised to NOT fetch the headers if this parameter is not passed.

aAuthInfo
  When used, this parameter supplies the Basic Authentic credentials for a
  URI which is in a protected realm and using AuthBasic authentication.
  The first element is the username, and the second element is the
  password.  Note that these are passed to the server in plain text.

aSendHeaders
  When passed by reference, this is filled with an array of the HTTP
  headers sent with the request.

  By collecting and examining both the send and receive headers, it
  is usually possible to identify errors.

bFTPCallBack
  You can use this parameter to install a callback to monitor
  progress of the download.  This should be a code-block which
  accepts two parameters.  The first parameter is the total size of the
  file being downloaded, and the second is the total number of bytes
  downloaded so far.

  If LoadFromUrl() is unable to determine the file size from the
  server, then the first parameter passed to the callback will be zero.

  The code-block should return a logical value indicating whether the
  transfer should continue.

     TRUE  - continue download
     FALSE - abort download immediately

  If the download is aborted by the callback, then any data already
  downloaded is returned.

  (note: since v1.13 this callback is used by HTTP/HTTPS requests as
  well as FTP)

RETURNS:
  LoadFromUrl() returns either the resource requested (as a string) or
  NIL on failure.  If lHeadersOnly is TRUE and the function succeeds,
  the return value is an array of HTTP headers for the resource.  There
  is one array element for each header, which is returned as a simple
  string.  If you wish to seperate the header token from it's value,
  you must perform that operation yourself.

Additional Functions:

  SetHttpDefaultHeaders()
  AddRequestHeadersA()
  Array2File()
  vBase64()

SetHttpDefaultHeaders( cHeaders )
  This function allows you to pre-set additional HTTP headers which are
  then subsequently used whenever LoadFromUrl() is called.

  You can either use this instead of the <cHttpHeaders> parameter of
  LoadFromUrl(), or set default headers withthis function and context
  specific headers with <cHttpHeaders>.

  The headers should be formatted in the same way as <cHttpHeaders>.  To
  clear the headers from the cache (so they won't be used in the future),
  call SetHttpDefaultHeaders() without any parameters (or explicitly pass
  NIL).

AddRequestHeadersA( hConnect, lpszHeaders, dwHeadersLength, dwModifiers )
  This is a WinAPI/WinInet function which can be used to selectively add,
  delete, replace or merge HTTP headers.  The semantics of the function are
  set by the dwModifiers parameter.

  hConnect
     [in] Handle returned by bPreCall in LoadFromUrl()

  lpszHeaders
     [in] Pointer to a string variable containing the headers to append to
     the request. Each header must be terminated by a CR/LF (carriage
     return/line feed) pair.

  dwHeadersLength
     [in] Size of lpszHeaders, in TCHARs. If this parameter is -1L, the
     function assumes that lpszHeaders is zero-terminated (ASCIIZ), and the
     length is computed.

  dwModifiers
     [in] Controls the semantics of this function. This parameter can be a
     combination of the following values.

     HTTP_ADDREQ_FLAG_ADD
        Adds the header if it does not exist. Used with
        HTTP_ADDREQ_FLAG_REPLACE.

     HTTP_ADDREQ_FLAG_ADD_IF_NEW
        Adds the header only if it does not already exist; otherwise, an
        error is returned.

     HTTP_ADDREQ_FLAG_COALESCE
        Coalesces headers of the same name.

     HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA
        Coalesces headers of the same name. For example, adding "Accept:
        text/*" followed by "Accept: audio/*" with this flag results in the
        formation of the single header "Accept: text/*, audio/*". This
        causes the first header found to be coalesced. It is up to the
        calling application to ensure a cohesive scheme with respect to
        coalesced/separate headers.

     HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON
        Coalesces headers of the same name using a semicolon.

     HTTP_ADDREQ_FLAG_REPLACE
        Replaces or removes a header. If the header value is empty and the
        header is found, it is removed. If not empty, the header value is
        replaced.

  Returns TRUE if successful

Array2File(cFile, a)
  Takes a simple one-dimensional array (a) and writes it to a file
  (cFile).

vBase64( cString )
  Base64 encodes a string.  There is no decode function available.
  If you prefer, you can use Xb2.NET's xbBase64Encode() or Asinet's
  toBase64() functions.
   

ADDITIONAL NOTES:
-----------------
LoadFromUrl() will masquerade as Internet Explorer 6 running on an XP
machine.  Most web servers and web applications do not make demands about
which browser you use.  However, a small number do, and unsurprisingly
they nearly all demand that you use IE.  Therefore I've set the function
to pretend to be IE in the hope that it will absolutely minimise the chances
of a server rejecting it.

If a server DOES reject it BECAUSE it thinks it is IE, you can use
AddRequestHeadersA() to change the USER_AGENT string sent to the server, or
you can just modify LoadFromUrl() - the USER_AGENT string is set using a
#define very near the top of the source file.

For brave and adventurous people, there is a static function in the source
called ChopUrlIntoLittleBits(). You might find it useful in other
situations, in which case just remove the STATIC declaration to make it
globally visible.

This function accepts a URL and - well, it chops it into little bits.  It
returns those bits in an array.  You can use the following constants to
examine the array:

  URL_PROTOCOL      'http','https','gopher','ftp','news' or NIL
  URL_HOST          server name or NIL
  URL_PORT          port number or NIL
  URL_URI           resource identifier (e.g. '/xbase/tencomm.html') or NIL

The values (or lack of!) are obviously dependant upon the information
contained within the URL.

The last five elements of the array are used by LoadFromUrl() as temporary
data storage and should be ignored.

Fetching NEWS Url's:
--------------------
Note that this isn't a full
implementation of the news:// url specification, since it doesn't
handle local url's.  According to the specification, 'local' url's
take the form:

  news://newsgroup/message

Note that the news-server host name has not been specified in the
url.

This implementation recognises and can handle 'remote' url's, that
is urls which contain the host address (which of course can be an
IP address or one of the local machine names).

Remote addresses take this form:

  news://host/newsgroup/message

If you need to refer to the current machine, you can use any of the
usual addresses/names, such as 127.0.0.1, 'localhost' etc.

The [message] can be a message-id without the enclosures:

  For a message who's message-id header looks like this:

     Message-ID: <15h6c878vias2.dlg@idep.org.uk>

  Use:
     15h6c878vias2.dlg@idep.org.uk

The [message] can also be a message number, but since message numbers
are specific to a particular server, you would first have to query
the server in order to retrieve the message number.  However, this
URL is valid (even if it doesn't point to a message!)

  news://news.alaska-software.com/alaska-software.news.3pp/27

...and returns the 27th message in the 3pp newsgroup.

By default, LoadFromUrl.prg will compile without news:// capability.  In
order to enable it, you require ASINET or Xb2.NET.  At the top of the
source, you will see these definitions:

#define __ILIB_INOLIB__     No sockets library
//#define __ILIB_ASINET__   ASINET library
//#define __ILIB_XB2NET__   Xb2NET library


Comment out __ILIB_INOLIB__ and uncomment one of the other two as
appropriate to the library you wish to use.

This message includes the following attachments:

piCommon - general purpose command extensions
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
* Source : piCommon.ch
* System : general
* Author : Phil Ide * Created: 13/02/2002
* Purpose: general purpose command extensions
--------------------------------------------------------------------- DLLFUNCTION command enhanced
--------------------------------
superior type checking
these checks can be used in pre-processor statements even when the value
to be tested does not exist.
--------------------------------

This message includes the following attachments:

piWis - emulate some of the functionality of WIS
/*****************************
* Source : piWis.prg
* System : <unkown>
* Author : Phil Ide
* Created: 29/10/2003
*****************************/


This demonstrates how you can emulate some of the functionality
of WIS to download an updated file from the internet via http.

In this (real-life) example, the ABI codes (insurance groupings
for vehicles in the UK) is tested.

The web page with the link is downloaded and decomposed using HRF,
and the link to the file and the date it was last updated are extracted
and the date tested.

The date is tested against the file-creation date of the last version
downloaded, and if the web version is newer then it is downloaded and
saved to a unique filename.

I run this from a WAA application, in which I have installed a
scheduler thread, and is run once per day.  The functionality for
calling this routine, extracting the data from the self-extracting
zip and importing into our own database is not supplied as part of this
sample since it is fairly much irrelevant.

If you want to test the routine, the url to use is:
  http://www.abi.org.uk/carinsurance/download.asp

Note that whilst downloading web pages is pretty good, the downloading
of the data file is quite slow, even though it is very small.  This is
because of their server setup, and is not an issue either with this code
or with ASINET or HRF.

Please note that you require ASINET and HRF to run this sample.

Additional Notes:
-----------------
Careful examination of the code will show some strange things.
For example, calling the following functions seems needless:

    ExtractUrlFromAnchorInCell()
    ExtractFileSizeFromCell()
    ExtractFileDateFromCell()

You could for example, just do this:

  aTables[1]:childList()[1]:href

...to get the url from the anchor.  Also,

  GetAllRootElementsByName( oTable, "tr" )

..may seem pointless too, because all the children of oTable are
in fact rows.

The first example simply makes the code more readable, and in fact
is simply easier to debug.

The second example ensures that spurious tags between rows are removed.
In the web page for downloading the ABI codes, this is not an issue, but
I have seen (and even used myself) <span> and <div> tags which are made
hidden/visible by JScript, and besides, the specification for HTML does not
preclude non-table tags being used between rows.

Note that GetAllRootElementsByName() may fail if there is text not enclosed
by tags - this is untested, and you should proceed with care.  If you get an
error when examining a page, this is probably the point where the failure
will occur.

This message includes the following attachments:

Printer API
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
PrinterAPI
Program  : <none, general>
Source   : printerAPI.prg
Author   : Phil Ide
Copyright: Phil Ide 2002-2003, All Rights Reserved

Additional Code
Source   : Inifiles.prg
Author   : Matt Hamilton, Terry Wolfe
Copyright: Released to Public domain by Original Author Matt Hamilton
          Corrections to ':ReadString' released to public domain
          by Terry Wolfe of Service Education, Inc.
Date     : 11/22/99


Special Notes

The #define value BRENT_DUBS_MIN is named for Brent who discovered the following:

If Microsoft Word is not maximised when closed, subsequent calls to Word to print a document using the Windows ShellExecute "print" command will cause Word to briefly display either it's logo or it's document window, unless undocumented mode 12 is used.

Many thanks to Brent for finding this.


--------------------------------------------------------------------------------

Index
Purpose WinApiOpen() WinApiPrint() GetDefaultPrinter() SetDefaultPrinter() EnumPrinters() GetPrinterNameFromString() History 18th Sep 2003 28th Jly 2003 27th Jly 2003 25th Jly 2003 23rd Jly 2003 10th Feb 2003 Acknowledgements  

--------------------------------------------------------------------------------
Purpose

These routines allow you to manipulate the default printer without being forced to get the user to assert changes for you. Usually, you would be forced to offer the user an XbpPrintDialog in order for them to select the printer to print on. In some circumstances though, you enough about their system to make that decision for them. In other cases, you might want to integrate the choice of printer with one of your own dialogs.

These routines offer you that flexibility, and even allow you to do such things as ask Windows to print a document for you, in which case Windows will print the document using the application which is registered with Windows as the default application for that file type.

For example, you might have a Rich Text Format (RTF) document which you have dynamically created, changed or selected. By asking Windows to print it for you, it will load WordPad, Word or Write (or whichever application is launched when you double-click on such a document), print the document and then unload that application. In this way you can avoid having to write the code which interprets RTF codes and outputs the properly formatted document to a printer.

In such cases, the printer used is always the default printer. If you wish to ensure that a specific printer is used and cannot gurantee that it is the default printer, these routines will enable you to:  

Get the name of the current default printer Get the name of all printers installed on the system Set the default printer Notify automatically all currently running applications that the default printer has changed (requires that such applications are compliant with Windows specifications in this regard) Windows NT/W2K/XP use a different method for storing, registering and applying the default printer from Win9x/ME, and Win9x/ME also use a different method for notifying currently running applications that a change has been made. These routines automatically recognise whether the current application is running on an NT class machine or otherwise, and modify their behaviour accordingly to produce the correct results.


--------------------------------------------------------------------------------
WinApiOpen()

WinApiOpen( cFile, [cParms], [cDirectory], [nOpenMode] ) -> lOk
cFile is the name of the file you wish to edit/view

cParms is a comma seperated list (as a string) of any additional parameters you wish to pass to the called application

cDirectory is the name of the directory that should be used as the current directory by the called application

nOpenMode indicates the mode of the application (minimised etc.)
Various modes can be selected using the #define's in printerAPI.ch. You should use the default (see below).

Returns TRUE if successful

This function accepts a file name, and instructs Windows to open the file using the default application using file-type associations.

In most instances, the only parameter you need to pass is the name of the file you wish to open in edit/view mode. Unless you have a particular reason to use the other parameters, they are best left alone.

Examples:   WinAPIOpen("default.html") load the file into a web browser
 WinAPIOpen("default.rtf")  // load the file into a rich-text editor
 WinAPIOpen("MyDialog.XFF") edit a Dialog definition in Xbase++'s Form Designer!

WinApiPrint()

WinApiPrint( cFile, [cParms], [cDirectory], [nOpenMode] ) -> lOk
cFile is the name of the file you wish to print

cParms is a comma seperated list (as a string) of any additional parameters you wish to pass to the printing application

cDirectory is the name of the directory that should be used as the current directory by the printing application

nOpenMode indicates the mode of the printing application (minimised etc.)
Various modes can be selected using the #define's in printerAPI.ch

Returns TRUE if successful

This function accepts a file name, and instructs Windows to print the file using the default application using file-type associations.  

GetDefaultPrinter()

GetDefaultPrinter() -> cPrinter
Returns the name of the current default printer

Win9x Under Win9x/ME, this returns a device string in the format "name, driver, port"  

SetDefaultPrinter()

SetDefaultPrinter( cPrinter ) -> lOk
cPrinter is the name of the printer to make the default printer

Returns TRUE if the named printer was successfully set as the default printer

The parameter should have been derived from a previous call to either EnumPrinters() or GetDefaultPrinter()  

Win9x Under Win9x/ME cPrinter should be a device string. See GetDefaultPrinter() for details.  

EnumPrinters()

EnumPrinters() -> aPrinters
Returns an array of printer names of all installed printers

WinNT e.g. {"HP Laserjet 4i", "Epson Stylus C600" }

Win9x e.g. {"HP Laserjet 4i,HPLDRV,\\srv1\hplj4", "Epson Stylus C600,EPSDRV,LPT2"}  

GetPrinterNameFromString()

GetPrinterNameFromString( cPrinter ) -> cPrinterName
Returns a printer name

This function accepts both a WinNT/W2K/XP printer name, and a Win9x/ME device string (which also includes the driver name and port name), and returns just the printer name. This allows you to retrieve a printer name without having to consider which version of Windows is running.  

e.g. print names of all installed printers
// does not print device and port names on Win9x/ME
aPrinters := EnumPrinters()
for i := 1 to len(aPrinters)
  ? GetPrinterNameFromString( aPrinters[i] ) e.g. "HP Laserjet 4i"
next


--------------------------------------------------------------------------------
History

18th Sep 2003 Added WinAPIOpen() routine, which will cause the file to be opened in view/edit mode by the application registered to handle the filetype. (e.g. .html to IE/Mosaic etc, .doc to WinWord etc. as appropriate for your system) 28th Jly 2003 Fix to C++ routine - I'd forgotten to close the printer
- thanks to Michael Hoffman for spotting this. 27th Jly 2003 Fix to C++ routine (I'd accidentally deleted the line which freed memory allocated from the Windows heap) 25th Jly 2003 Fixed potential GC problem by gathering Win9x printer info via C++ routine.

Since the C++ routine cannot be compiled unless you have a suitable compiler, the package now creates PrinterAPI.DLL, which should make it easier to use and install. 23rd Jly 2003 Initial Win9x compatible release 10th Feb 2003 Original release, worked only on NT class machines  

--------------------------------------------------------------------------------
Acknowledgements

My thanks to those who tested the Win9x compatibility routines for me (alphabetical): Edgar Borger
Regan Cawkwell
Greg Doran
Osvaldo Ramirez
Terry Wolfe

This message includes the following attachments:

Print Screen App
Rescued by: Jimmy ( AUGE_OHR)
--------------------------------------------------------------------
********************************************************************
*  CLASS MxPrintScreen
********************************************************************
*  Copyright:
*      Joe Carrick - 03/07/2000
*
*  Note: This implementation clears the Windows Clipboard.
*        This is necessary to avoid printing the Window continuously.
********************************************************************

This message includes the following attachments:

Page 1 of 2 Next >