Affichage des articles dont le libellé est Clipper. Afficher tous les articles
Affichage des articles dont le libellé est Clipper. Afficher tous les articles

vendredi 10 juillet 2015

Zebra + ZPL sous Clipper Windows - Harbour for beginner, une reference documentaire Clipper sour Windows

Déjà évoqué plusieurs fois, Harbour-Project permet de compiler des logiciels Clipper sous Win32 et ainsi de profiter pleinement des avantages de la plateforme Windows a partir d'un vieux logiciel (appel COM, impression, Mutex, WinSock, etc).

Harbour for Beginner
Je viens de trouver un chouette document "Harbour for Beginner" d'alexender Kresin (anglais) où il aborde des points très intéressantes:
  • Some language extensions
  • Classes and objects
  • Lang API (the language of the program)
  • Codepage API
  • Working with hrb - files
  • The built-in C
  • Hash arrays
  • Regular expressions
  • INET subsystem
  • Multithreading
  • Miscellaneous functions
Le point  "Lang API" et sa fonction hb_StrToUtf8() tombe bien, je dois justement créer des fichiers en UTF-8 pour envoyer un flux ZPL à ma petite zébra ... voyez l'article "Imprimante Zebra USB, ZPL et Spooler Windows - Sacré Windows!!!" .

C'est que la Zebra n'apprécie pas l'ANSI, elle fait sauter tous les accentués si le flux est ANSI mais en UTF-8 c'est impeccable.


Création d'un fichier ZPL et envoi Sur Zebra
Voici un petit programme clipper compilé avec Harbour Project qui crée un fichier ZPL puis l'envoi sur l'imprimante Zebra LP 2824 nommée ZEBRA_RAW (voyez l'article "Imprimante Zebra USB, ZPL et Spooler Windows - Sacré Windows!!!").
Pas le code le plus pure... mais le vilain proto marche très bien :-)

&& #include "mediator.ch"  Mediator - PostgreSql middleware
#include "fileio.ch"

LOCAL hDst := NIL 
LOCAL sOutFilename := 'demo.zpl'
LOCAL sPrinterName := 'ZEBRA_RAW' 

&& Mediator - PostgreSql middleware
&& request medntx
 
REQUEST HB_CODEPAGE_FRWIN
SET( _SET_CODEPAGE, "FRWIN" ) 

&& Mediator - PostgreSql middleware
&& RDDSETDEFAULT("MEDNTX")  && set default data source to MEDNTX RDD driver


* -- initialisation
set date british
set delete on
set confirm on
set escape on
set wrap on
set epoch to 1920

? 'Create a '+sOutFilename+' file encoded with UTF-8'

&& Open Destination Filename 
hDst := hb_FCreate( sOutFilename, FC_NORMAL, FO_READWRITE + FO_SHARED )
IF hDst == F_ERROR 
     sMsg = "Impossible de recréer FAReprint.txt!" 
     ALERT( HB_AnsiToOem(sMsg) ) && convert to "DOS String" 
     RETURN NIL
ENDIF

&& Surprenant, pas besoin de hb_StrToUtf8(), le fichier est déjà
&&    encodé en UTF8! Impression sur Zebra Parfaite
cBuf = '^XA'
fwrite( hDst, cBuf + hb_eol() )
cBuf = '^FO100,50^ADN,36,20^FDxyz*é&êà*^FS'
fwrite( hDst, cBuf + hb_eol() )
cBuf = '^XZ'
fwrite( hDst, cBuf + hb_eol() )

FCLOSE( hDst )

? 'WIN_PrintFileRaw: Send ZPL to Printer '+sPrinterName 
retCode = hb_ntos( WIN_PrintFileRaw( sPrinterName, (sOutFilename) ))
? "print retCode for "+sPrinterName+" = "+retCode
 

Ressources

mercredi 25 mars 2015

Harbour Project - Beginner Guide

Ce n'est pas la première fois que je parle d'Harbour-Project, un compilateur Clipper/DBase libre et multiplateforme que j'utilise depuis quelques années maintenant.

Je viens de trouver une référence intéressante pour les débutants et les moins débutant.
Il faut quand même avouer qu'Harbour est assez puissant.
 
Une petite info à partager donc ;-)

mercredi 27 novembre 2013

Bonne source d'information sur Harbour

Les développeurs Clipper sous Harbour Apprécierons ces information

Harbour related


MiniGui related


IDEs / Editors of choice
  • xMate Project Manager : The good-old IDE by Andy Wos, bundled with an excellent -and IMO the best Harbour oriented-, source code editor for Harbour developers!
  • HMGS-IDE (open source IDE) : MiniGui oriented IDE, with a good form designer.
  • Notepad++ : Excellent open-source & free (..as in "free speech" and also as in "free beer") source code editor.
  • Harbour IDE : Interesting multi-platform (Qt based) IDE. A very strong tool for Harbour developer.


Tutorials



Alexander Kresin pageA ne vraiment pas rater, la page Harbour/Clipper software development Alexander Kresin qui reprend également un DEBUGGEUR!!!

Source

mardi 25 septembre 2012

Clipper - OutputDebugString en Harbour

Parmi mes premiers articles relatifs au développement clipper sous Harbour, l'un me mes principaux problème était l'obtention de message de débuggogage.

Ce problème fut solutionné en mettant en place un fichier "debug" dans lequel j'envoyais les messages par l'intermédiaire d'une fonction DMSG.

Aujourd'hui j'ai amélioré la fonction DMSG avec un simple appel de fonction qui envoi également le message de débogage au Kernel de Windows.
Du coup, je peux tracer les activités de mon programme à l'aide du DebugView de SysInternals :-)
Trop Top!!!

Appel à l'API OutputDebugString
Aussi simple que :

WAPI_OUTPUTDEBUGSTRING( sMsg )

Résultat dans DebugView
Vous pouvez trouvez DebugView en tapant "debugview" dans une recherche Google.
N'oubliez pas de démarrer DebugView en mode Administrateur... sinon vous ne verrez aucun message!

Yes!!!

Harbour et l'API Window
Vous trouverez une liste complète de l'API Windows supportée dans le fichier
c:\hb30\include\HbWin.hbx
A titre d'exemple, voici une liste complète de ce que j'ai trouvé dans ma release 3.0 d'Harbour.
Pour savoir comment les utilisés... il suffit de faire une recherche dans tous les fichiers de c:\hb30\ , il y a généralement des exemples d'utilisation

...
DYNAMIC ANSITOWIDE
DYNAMIC CALLDLL
DYNAMIC CALLDLLBOOL
DYNAMIC CALLDLLTYPED
DYNAMIC CREATEOBJECT
DYNAMIC CREATEOLEOBJECT
DYNAMIC FREELIBRARY
DYNAMIC GETACTIVEOBJECT
DYNAMIC GETDEFAULTPRINTER
DYNAMIC GETLASTERROR
DYNAMIC GETPRINTERS
DYNAMIC GETPROCADDRESS
DYNAMIC LOADLIBRARY
DYNAMIC MESSAGEBOX
DYNAMIC OLE2TXTERROR
DYNAMIC OLEERROR
DYNAMIC PRINTEREXISTS
DYNAMIC PRINTERPORTTONAME
DYNAMIC PRINTFILERAW
DYNAMIC SETDEFAULTPRINTER
DYNAMIC SETLASTERROR
DYNAMIC TOLEAUTO
DYNAMIC WAPI_ABORTDOC
DYNAMIC WAPI_ADDFONTRESOURCEEX
DYNAMIC WAPI_APPENDMENU
DYNAMIC WAPI_ARC
DYNAMIC WAPI_CHECKMENUITEM
DYNAMIC WAPI_CHECKMENURADIOITEM
DYNAMIC WAPI_COMBOBOX_ADDSTRING
DYNAMIC WAPI_CREATEACCELERATORTABLE
DYNAMIC WAPI_CREATEDC
DYNAMIC WAPI_CREATEFONT
DYNAMIC WAPI_CREATEFONTINDIRECT
DYNAMIC WAPI_CREATEHATCHBRUSH
DYNAMIC WAPI_CREATEMENU
DYNAMIC WAPI_CREATEMUTEX
DYNAMIC WAPI_CREATEPEN
DYNAMIC WAPI_CREATEPOPUPMENU
DYNAMIC WAPI_CREATESOLIDBRUSH
DYNAMIC WAPI_CREATEWINDOWEX
DYNAMIC WAPI_DELETEMENU
DYNAMIC WAPI_DESTROYACCELERATORTABLE
DYNAMIC WAPI_DESTROYMENU
DYNAMIC WAPI_DESTROYWINDOW
DYNAMIC WAPI_DIALOGBOXPARAM
DYNAMIC WAPI_DRAWMENUBAR
DYNAMIC WAPI_DRAWTEXT
DYNAMIC WAPI_ELLIPSE
DYNAMIC WAPI_ENABLEMENUITEM
DYNAMIC WAPI_ENABLESCROLLBAR
DYNAMIC WAPI_ENDDIALOG
DYNAMIC WAPI_ENDDOC
DYNAMIC WAPI_ENDPAGE
DYNAMIC WAPI_EXTTEXTOUT
DYNAMIC WAPI_FILLRECT
DYNAMIC WAPI_FINDWINDOW
DYNAMIC WAPI_FORMATMESSAGE
DYNAMIC WAPI_FREELIBRARY
DYNAMIC WAPI_GETACP
DYNAMIC WAPI_GETACTIVEWINDOW
DYNAMIC WAPI_GETBKCOLOR
DYNAMIC WAPI_GETBKMODE
DYNAMIC WAPI_GETCOMMANDLINE
DYNAMIC WAPI_GETCURRENTPROCESS
DYNAMIC WAPI_GETCURRENTPROCESSID
DYNAMIC WAPI_GETCURRENTTHREAD
DYNAMIC WAPI_GETCURRENTTHREADID
DYNAMIC WAPI_GETDESKTOPWINDOW
DYNAMIC WAPI_GETDEVICECAPS
DYNAMIC WAPI_GETDLGITEM
DYNAMIC WAPI_GETDLGITEMTEXT
DYNAMIC WAPI_GETKEYSTATE
DYNAMIC WAPI_GETLASTERROR
DYNAMIC WAPI_GETLONGPATHNAME
DYNAMIC WAPI_GETMAPMODE
DYNAMIC WAPI_GETMENU
DYNAMIC WAPI_GETMENUDEFAULTITEM
DYNAMIC WAPI_GETMENUITEMCOUNT
DYNAMIC WAPI_GETMENUITEMID
DYNAMIC WAPI_GETMENUSTATE
DYNAMIC WAPI_GETMODULEHANDLE
DYNAMIC WAPI_GETOEMCP
DYNAMIC WAPI_GETPROCADDRESS
DYNAMIC WAPI_GETSCROLLINFO
DYNAMIC WAPI_GETSCROLLPOS
DYNAMIC WAPI_GETSCROLLRANGE
DYNAMIC WAPI_GETSHORTPATHNAME
DYNAMIC WAPI_GETSUBMENU
DYNAMIC WAPI_GETSYSTEMDIRECTORY
DYNAMIC WAPI_GETSYSTEMMENU
DYNAMIC WAPI_GETSYSTEMMETRICS
DYNAMIC WAPI_GETTEXTALIGN
DYNAMIC WAPI_GETTEXTCOLOR
DYNAMIC WAPI_GETTEXTFACE
DYNAMIC WAPI_GETWINDOWSDIRECTORY
DYNAMIC WAPI_IMAGELIST_ADD
DYNAMIC WAPI_IMAGELIST_ADDMASKED
DYNAMIC WAPI_IMAGELIST_BEGINDRAG
DYNAMIC WAPI_IMAGELIST_COPY
DYNAMIC WAPI_IMAGELIST_CREATE
DYNAMIC WAPI_IMAGELIST_DESTROY
DYNAMIC WAPI_IMAGELIST_DRAGENTER
DYNAMIC WAPI_IMAGELIST_DRAGLEAVE
DYNAMIC WAPI_IMAGELIST_DRAGMOVE
DYNAMIC WAPI_IMAGELIST_DRAGSHOWNOLOCK
DYNAMIC WAPI_IMAGELIST_DRAW
DYNAMIC WAPI_IMAGELIST_DRAWEX
DYNAMIC WAPI_IMAGELIST_DUPLICATE
DYNAMIC WAPI_IMAGELIST_GETBKCOLOR
DYNAMIC WAPI_IMAGELIST_GETICON
DYNAMIC WAPI_IMAGELIST_GETICONSIZE
DYNAMIC WAPI_IMAGELIST_GETIMAGECOUNT
DYNAMIC WAPI_IMAGELIST_GETIMAGEINFO
DYNAMIC WAPI_IMAGELIST_LOADIMAGE
DYNAMIC WAPI_IMAGELIST_MERGE
DYNAMIC WAPI_IMAGELIST_REMOVE
DYNAMIC WAPI_IMAGELIST_REPLACE
DYNAMIC WAPI_IMAGELIST_REPLACEICON
DYNAMIC WAPI_IMAGELIST_SETBKCOLOR
DYNAMIC WAPI_IMAGELIST_SETDRAGCURSORIMAGE
DYNAMIC WAPI_IMAGELIST_SETICONSIZE
DYNAMIC WAPI_IMAGELIST_SETIMAGECOUNT
DYNAMIC WAPI_INSERTMENU
DYNAMIC WAPI_ISICONIC
DYNAMIC WAPI_ISMENU
DYNAMIC WAPI_ISUSERANADMIN
DYNAMIC WAPI_ISWINDOW
DYNAMIC WAPI_ISZOOMED
DYNAMIC WAPI_LINETO
DYNAMIC WAPI_LOADIMAGE
DYNAMIC WAPI_LOADLIBRARY
DYNAMIC WAPI_LOADMENU
DYNAMIC WAPI_MESSAGEBEEP
DYNAMIC WAPI_MESSAGEBOX
DYNAMIC WAPI_MOVETOEX
DYNAMIC WAPI_MULDIV
DYNAMIC WAPI_OPENMUTEX
DYNAMIC WAPI_OUTPUTDEBUGSTRING
DYNAMIC WAPI_PLAYSOUND
DYNAMIC WAPI_RECTANGLE
DYNAMIC WAPI_RELEASEMUTEX
DYNAMIC WAPI_REMOVEFONTRESOURCEEX
DYNAMIC WAPI_REMOVEMENU
DYNAMIC WAPI_RESETDC
DYNAMIC WAPI_ROUNDRECT
DYNAMIC WAPI_SELECTOBJECT
DYNAMIC WAPI_SETACTIVEWINDOW
DYNAMIC WAPI_SETBKCOLOR
DYNAMIC WAPI_SETBKMODE
DYNAMIC WAPI_SETDLGITEMTEXT
DYNAMIC WAPI_SETERRORMODE
DYNAMIC WAPI_SETFOCUS
DYNAMIC WAPI_SETLASTERROR
DYNAMIC WAPI_SETMAPMODE
DYNAMIC WAPI_SETMENU
DYNAMIC WAPI_SETMENUDEFAULTITEM
DYNAMIC WAPI_SETPROCESSWORKINGSETSIZE
DYNAMIC WAPI_SETSCROLLINFO
DYNAMIC WAPI_SETSCROLLPOS
DYNAMIC WAPI_SETSCROLLRANGE
DYNAMIC WAPI_SETTEXTALIGN
DYNAMIC WAPI_SETTEXTCOLOR
DYNAMIC WAPI_SETWINDOWPOS
DYNAMIC WAPI_SHELLEXECUTE
DYNAMIC WAPI_SHOWSCROLLBAR
DYNAMIC WAPI_SLEEP
DYNAMIC WAPI_STARTDOC
DYNAMIC WAPI_STARTPAGE
DYNAMIC WAPI_TABCTRL_ADDITEM
DYNAMIC WAPI_TABCTRL_ADJUSTRECT
DYNAMIC WAPI_TABCTRL_CREATE
DYNAMIC WAPI_TABCTRL_DELETEALLITEMS
DYNAMIC WAPI_TABCTRL_DELETEITEM
DYNAMIC WAPI_TABCTRL_DESELECTALL
DYNAMIC WAPI_TABCTRL_GETCURFOCUS
DYNAMIC WAPI_TABCTRL_GETCURSEL
DYNAMIC WAPI_TABCTRL_GETEXTENDEDSTYLE
DYNAMIC WAPI_TABCTRL_GETIMAGELIST
DYNAMIC WAPI_TABCTRL_GETITEM
DYNAMIC WAPI_TABCTRL_GETITEMCOUNT
DYNAMIC WAPI_TABCTRL_GETITEMRECT
DYNAMIC WAPI_TABCTRL_GETROWCOUNT
DYNAMIC WAPI_TABCTRL_GETTOOLTIPS
DYNAMIC WAPI_TABCTRL_GETUNICODEFORMAT
DYNAMIC WAPI_TABCTRL_HIGHLIGHTITEM
DYNAMIC WAPI_TABCTRL_HITTEST
DYNAMIC WAPI_TABCTRL_INSERTITEM
DYNAMIC WAPI_TABCTRL_REMOVEIMAGE
DYNAMIC WAPI_TABCTRL_SETCURFOCUS
DYNAMIC WAPI_TABCTRL_SETCURSEL
DYNAMIC WAPI_TABCTRL_SETEXTENDEDSTYLE
DYNAMIC WAPI_TABCTRL_SETIMAGELIST
DYNAMIC WAPI_TABCTRL_SETITEM
DYNAMIC WAPI_TABCTRL_SETITEMEXTRA
DYNAMIC WAPI_TABCTRL_SETITEMSIZE
DYNAMIC WAPI_TABCTRL_SETMINTABWIDTH
DYNAMIC WAPI_TABCTRL_SETPADDING
DYNAMIC WAPI_TABCTRL_SETTOOLTIPS
DYNAMIC WAPI_TABCTRL_SETUNICODEFORMAT
DYNAMIC WAPI_TEXTOUT
DYNAMIC WAPI_TRACKPOPUPMENU
DYNAMIC WAPI_TREEVIEW_CREATEDRAGIMAGE
DYNAMIC WAPI_TREEVIEW_DELETEALLITEMS
DYNAMIC WAPI_TREEVIEW_EDITLABEL
DYNAMIC WAPI_TREEVIEW_ENDEDITLABELNOW
DYNAMIC WAPI_TREEVIEW_ENSUREVISIBLE
DYNAMIC WAPI_TREEVIEW_EXPAND
DYNAMIC WAPI_TREEVIEW_GETBKCOLOR
DYNAMIC WAPI_TREEVIEW_GETCHECKSTATE
DYNAMIC WAPI_TREEVIEW_GETCHILD
DYNAMIC WAPI_TREEVIEW_GETCOUNT
DYNAMIC WAPI_TREEVIEW_GETDROPHILIGHT
DYNAMIC WAPI_TREEVIEW_GETEDITCONTROL
DYNAMIC WAPI_TREEVIEW_GETFIRSTVISIBLE
DYNAMIC WAPI_TREEVIEW_GETIMAGELIST
DYNAMIC WAPI_TREEVIEW_GETINDENT
DYNAMIC WAPI_TREEVIEW_GETINSERTMARKCOLOR
DYNAMIC WAPI_TREEVIEW_GETISEARCHSTRING
DYNAMIC WAPI_TREEVIEW_GETITEM
DYNAMIC WAPI_TREEVIEW_GETITEMHEIGHT
DYNAMIC WAPI_TREEVIEW_GETITEMRECT
DYNAMIC WAPI_TREEVIEW_GETITEMSTATE
DYNAMIC WAPI_TREEVIEW_GETLASTVISIBLE
DYNAMIC WAPI_TREEVIEW_GETLINECOLOR
DYNAMIC WAPI_TREEVIEW_GETNEXTITEM
DYNAMIC WAPI_TREEVIEW_GETNEXTSIBLING
DYNAMIC WAPI_TREEVIEW_GETNEXTVISIBLE
DYNAMIC WAPI_TREEVIEW_GETPARENT
DYNAMIC WAPI_TREEVIEW_GETPREVSIBLING
DYNAMIC WAPI_TREEVIEW_GETPREVVISIBLE
DYNAMIC WAPI_TREEVIEW_GETROOT
DYNAMIC WAPI_TREEVIEW_GETSCROLLTIME
DYNAMIC WAPI_TREEVIEW_GETSELECTION
DYNAMIC WAPI_TREEVIEW_GETTEXTCOLOR
DYNAMIC WAPI_TREEVIEW_GETTOOLTIPS
DYNAMIC WAPI_TREEVIEW_GETUNICODEFORMAT
DYNAMIC WAPI_TREEVIEW_GETVISIBLECOUNT
DYNAMIC WAPI_TREEVIEW_HITTEST
DYNAMIC WAPI_TREEVIEW_INSERTITEM
DYNAMIC WAPI_TREEVIEW_SELECT
DYNAMIC WAPI_TREEVIEW_SELECTDROPTARGET
DYNAMIC WAPI_TREEVIEW_SELECTITEM
DYNAMIC WAPI_TREEVIEW_SELECTSETFIRSTVISIBLE
DYNAMIC WAPI_TREEVIEW_SETBKCOLOR
DYNAMIC WAPI_TREEVIEW_SETCHECKSTATE
DYNAMIC WAPI_TREEVIEW_SETIMAGELIST
DYNAMIC WAPI_TREEVIEW_SETINDENT
DYNAMIC WAPI_TREEVIEW_SETINSERTMARK
DYNAMIC WAPI_TREEVIEW_SETINSERTMARKCOLOR
DYNAMIC WAPI_TREEVIEW_SETITEM
DYNAMIC WAPI_TREEVIEW_SETITEMHEIGHT
DYNAMIC WAPI_TREEVIEW_SETITEMSTATE
DYNAMIC WAPI_TREEVIEW_SETLINECOLOR
DYNAMIC WAPI_TREEVIEW_SETSCROLLTIME
DYNAMIC WAPI_TREEVIEW_SETTEXTCOLOR
DYNAMIC WAPI_TREEVIEW_SETTOOLTIPS
DYNAMIC WAPI_TREEVIEW_SETUNICODEFORMAT
DYNAMIC WAPI_TREEVIEW_SORTCHILDREN
DYNAMIC WAPI_WAITFORMULTIPLEOBJECTS
DYNAMIC WAPI_WAITFORMULTIPLEOBJECTSEX
DYNAMIC WAPI_WAITFORSINGLEOBJECT
DYNAMIC WAPI_WAITFORSINGLEOBJECTEX
DYNAMIC WAPI_WNETGETLASTERROR
DYNAMIC WCE_SIM
DYNAMIC WCE_SIMDEINITIALIZE
DYNAMIC WCE_SIMDELETEPHONEBOOKENTRY
DYNAMIC WCE_SIMINITIALIZE
DYNAMIC WCE_SIMPHONEBOOKSTATUS
DYNAMIC WCE_SIMREADPHONEBOOKENTRY
DYNAMIC WCE_SIMWRITEPHONEBOOKENTRY
DYNAMIC WCE_SMSSENDMESSAGE
DYNAMIC WIDETOANSI
DYNAMIC WIN_ABORTDOC
DYNAMIC WIN_ANSITOWIDE
DYNAMIC WIN_ARC
DYNAMIC WIN_AXGETCONTROL
DYNAMIC WIN_AXINIT
DYNAMIC WIN_BITMAPDIMENSIONS
DYNAMIC WIN_BITMAPISSUPPORTED
DYNAMIC WIN_BITMAPSOK
DYNAMIC WIN_BITMAPTYPE
DYNAMIC WIN_BMP
DYNAMIC WIN_COM
DYNAMIC WIN_COMCLOSE
DYNAMIC WIN_COMDEBUGDCB
DYNAMIC WIN_COMDTRFLOW
DYNAMIC WIN_COMERROR
DYNAMIC WIN_COMERRORCLEAR
DYNAMIC WIN_COMFUNCLAST
DYNAMIC WIN_COMISVALID
DYNAMIC WIN_COMOPEN
DYNAMIC WIN_COMPURGE
DYNAMIC WIN_COMQUEUESTATUS
DYNAMIC WIN_COMREAD
DYNAMIC WIN_COMRECV
DYNAMIC WIN_COMRTSFLOW
DYNAMIC WIN_COMSETDTR
DYNAMIC WIN_COMSETQUEUESIZE
DYNAMIC WIN_COMSETRTS
DYNAMIC WIN_COMSETTIMEOUTS
DYNAMIC WIN_COMSTATUS
DYNAMIC WIN_COMWRITE
DYNAMIC WIN_COMXONXOFFFLOW
DYNAMIC WIN_CREATEDC
DYNAMIC WIN_CREATEFONT
DYNAMIC WIN_DELETEDC
DYNAMIC WIN_DRAWBITMAP
DYNAMIC WIN_ELLIPSE
DYNAMIC WIN_ENDDOC
DYNAMIC WIN_ENDPAGE
DYNAMIC WIN_ENUMFONTS
DYNAMIC WIN_FILLRECT
DYNAMIC WIN_GETCHARSIZE
DYNAMIC WIN_GETCOMMANDLINEPARAM
DYNAMIC WIN_GETDEVICECAPS
DYNAMIC WIN_GETDOCUMENTPROPERTIES
DYNAMIC WIN_GETEXEFILENAME
DYNAMIC WIN_GETOPENFILENAME
DYNAMIC WIN_GETPRINTERFONTNAME
DYNAMIC WIN_GETSAVEFILENAME
DYNAMIC WIN_GETTEXTSIZE
DYNAMIC WIN_HINSTANCE
DYNAMIC WIN_HIWORD
DYNAMIC WIN_HPREVINSTANCE
DYNAMIC WIN_LINETO
DYNAMIC WIN_LOADBITMAPFILE
DYNAMIC WIN_LOADRESOURCE
DYNAMIC WIN_LOWORD
DYNAMIC WIN_MAPISENDMAIL
DYNAMIC WIN_N2P
DYNAMIC WIN_NCMDSHOW
DYNAMIC WIN_OLEAUTO
DYNAMIC WIN_OLEAUTO___ONERROR
DYNAMIC WIN_OLEAUTO___OPINDEX
DYNAMIC WIN_OLECREATEOBJECT
DYNAMIC WIN_OLEERROR
DYNAMIC WIN_OLEERRORTEXT
DYNAMIC WIN_OLEGETACTIVEOBJECT
DYNAMIC WIN_OSIS2000
DYNAMIC WIN_OSIS2000ORUPPER
DYNAMIC WIN_OSIS2003
DYNAMIC WIN_OSIS7
DYNAMIC WIN_OSIS95
DYNAMIC WIN_OSIS98
DYNAMIC WIN_OSIS9X
DYNAMIC WIN_OSISME
DYNAMIC WIN_OSISNT
DYNAMIC WIN_OSISNT351
DYNAMIC WIN_OSISNT4
DYNAMIC WIN_OSISTSCLIENT
DYNAMIC WIN_OSISVISTA
DYNAMIC WIN_OSISVISTAORUPPER
DYNAMIC WIN_OSISWINXPORUPPER
DYNAMIC WIN_OSISXP
DYNAMIC WIN_OSNETREGOK
DYNAMIC WIN_OSNETVREDIROK
DYNAMIC WIN_OSVERSIONINFO
DYNAMIC WIN_P2N
DYNAMIC WIN_PRINTDLGDC
DYNAMIC WIN_PRINTEREXISTS
DYNAMIC WIN_PRINTERGETDEFAULT
DYNAMIC WIN_PRINTERLIST
DYNAMIC WIN_PRINTERPORTTONAME
DYNAMIC WIN_PRINTERSETDEFAULT
DYNAMIC WIN_PRINTERSTATUS
DYNAMIC WIN_PRINTFILERAW
DYNAMIC WIN_PRN
DYNAMIC WIN_RECTANGLE
DYNAMIC WIN_REGCLOSEKEY
DYNAMIC WIN_REGCREATEKEYEX
DYNAMIC WIN_REGDELETE
DYNAMIC WIN_REGDELETEKEY
DYNAMIC WIN_REGDELETEVALUE
DYNAMIC WIN_REGGET
DYNAMIC WIN_REGOPENKEYEX
DYNAMIC WIN_REGPATHSPLIT
DYNAMIC WIN_REGQUERY
DYNAMIC WIN_REGQUERYVALUEEX
DYNAMIC WIN_REGREAD
DYNAMIC WIN_REGSET
DYNAMIC WIN_REGSETVALUEEX
DYNAMIC WIN_REGWRITE
DYNAMIC WIN_REPORTEVENT
DYNAMIC WIN_RUNDETACHED
DYNAMIC WIN_SERVICEDELETE
DYNAMIC WIN_SERVICEGETSTATUS
DYNAMIC WIN_SERVICEINSTALL
DYNAMIC WIN_SERVICESETEXITCODE
DYNAMIC WIN_SERVICESETSTATUS
DYNAMIC WIN_SERVICESTART
DYNAMIC WIN_SERVICESTOP
DYNAMIC WIN_SETBKMODE
DYNAMIC WIN_SETCOLOR
DYNAMIC WIN_SETDOCUMENTPROPERTIES
DYNAMIC WIN_SETMAPMODE
DYNAMIC WIN_SETPEN
DYNAMIC WIN_SHELLNOTIFYICON
DYNAMIC WIN_SHFILEOPERATION
DYNAMIC WIN_STARTDOC
DYNAMIC WIN_STARTPAGE
DYNAMIC WIN_SYSREFRESH
DYNAMIC WIN_TEXTOUT
DYNAMIC WIN_UNICODE
DYNAMIC WIN_UUIDCREATESTRING
DYNAMIC WIN_WIDETOANSI
DYNAMIC XISPRINTER
DYNAMIC __AXDOVERB
DYNAMIC __AXGETCONTROL
DYNAMIC __AXREGISTERHANDLER
DYNAMIC __OLECREATEOBJECT
DYNAMIC __OLEENUMCREATE
DYNAMIC __OLEENUMNEXT
DYNAMIC __OLEGETACTIVEOBJECT
DYNAMIC __OLEPDISP
DYNAMIC __WAPI_DEVMODE_GET
DYNAMIC __WAPI_DEVMODE_NEW
DYNAMIC __WAPI_DEVMODE_SET
...

lundi 24 septembre 2012

Clipper - Gestion des Hash sous Harbour

Introduction
Les Hash (Hash Table) sont des structures qui, typiquement, permettent d'implémenter des dictionnaires.
Les dictionnaires permettent d'enregistrer des pairs CLE = VALEUR dans une liste... c'est pratique à de nombreux égards.

Le grand avantage d'un dictionnaire, c'est que l'on peut y lire une valeur grâce à une syntaxe simplifiée

ma_valeur := Le_dictionnaire[ "la_cle" ]

Un rapide coup d'oeil sur les fonctions Harbours
Voici quelques bouts de code ci-et-là qui permettent de se familiariser avec les instructions relatives au Hash.

 IF hb_isHash( xData ) .AND. hb_hHasKey( xData, "Today" )
      OutStd( xData[ "Today" ], hb_eol() )
   ENDIF

Il est possible de créer un hash grâce à l'instruction:
hParams := hb_Hash()

Mais j'ai le sentiment que l'instruction suivante produit aussi un Hash:
LOCAL hData := {=>}

Le fichier de compatibilité de Harbour (hbcompat.ch) nous apprend qu'il existe de nombreuses autre fonctions utilitaires autour des Hash:
   #xtranslate hb_HASH([<x,...>])          => HASH(<x>)
   #xtranslate hb_HHASKEY([<x,...>])       => HHASKEY(<x>)
   #xtranslate hb_HPOS([<x,...>])          => HGETPOS(<x>)
   #xtranslate hb_HGET([<x,...>])          => HGET(<x>)
   #xtranslate hb_HSET([<x,...>])          => HSET(<x>)
   #xtranslate hb_HDEL([<x,...>])          => HDEL(<x>)
   #xtranslate hb_HKEYAT([<x,...>])        => HGETKEYAT(<x>)
   #xtranslate hb_HVALUEAT([<x,...>])      => HGETVALUEAT(<x>)
   #xtranslate hb_HVALUEAT([<x,...>])      => HSETVALUEAT(<x>)
   #xtranslate hb_HPAIRAT([<x,...>])       => HGETPAIRAT(<x>)
   #xtranslate hb_HDELAT([<x,...>])        => HDELAT(<x>)
   #xtranslate hb_HKEYS([<x,...>])         => HGETKEYS(<x>)
   #xtranslate hb_HVALUES([<x,...>])       => HGETVALUES(<x>)
   #xtranslate hb_HFILL([<x,...>])         => HFILL(<x>)
   #xtranslate hb_HCLONE([<x,...>])        => HCLONE(<x>)
   #xtranslate hb_HCOPY([<x,...>])         => HCOPY(<x>)
   #xtranslate hb_HMERGE([<x,...>])        => HMERGE(<x>)
   #xtranslate hb_HEVAL([<x,...>])         => HEVAL(<x>)
   #xtranslate hb_HSCAN([<x,...>])         => HSCAN(<x>)
   #xtranslate hb_HSETCASEMATCH([<x,...>]) => HSETCASEMATCH(<x>)
   #xtranslate hb_HCASEMATCH([<x,...>])    => HGETCASEMATCH(<x>)
   #xtranslate hb_HSETAUTOADD([<x,...>])   => HSETAUTOADD(<x>)
   #xtranslate hb_HAUTOADD([<x,...>])      => HGETAUTOADD(<x>)
   #xtranslate hb_HALLOCATE([<x,...>])     => HALLOCATE(<x>)
   #xtranslate hb_HDEFAULT([<x,...>])      => HDEFAULT(<x>)

jeudi 30 août 2012

Clipper: Creer un GUID

J'avais besoin de créer un GUID à partir de Clipper.
J'ai mis un certain temps à trouver l'exemple \contrib\hbwin\tests\testrpc.prg

#include "simpleio.ch"

PROCEDURE Main()
/*
 * Harbour Project source code:
 *
 * Copyright 2010 Viktor Szakats (harbour.01 syenar.hu)
 * www - http://harbour-project.org
 *
 */

    ? win_UuidCreateString()

    RETURN

mercredi 22 août 2012

Clipper: Comment imprimer un Code barre avec une imprimante HP

Introduction
Nous disposons d'un vieux soft Clipper que j'ai migré en multi-poste sur une DB PostGreSql.
A peine croyable, grâce à Mediator et aux projets Open-Sources Harbour et PostGreSql, ce logiciel connait une seconde vie.

Nous imprimons nos notes d'envoi sur une imprimante HP (LasetJet P2055), ce qui permet de faire quelques formatages en utilisant le language PCL toujours supporté en 2012 :-)

L'étape suivante consiste à imprimer un Code barre sur la note d'envoi pour automatiser le processus de préparation et suivit de Colis.
Figurez-vous que grâce à PCL, cela est possible, sous Clipper SANS UTILISER DE CARTE MEMOIRE IMPRIMANTE stockant les fonts.

J'ai trouver un très vieux code sur OASIS permettant de générer du BarCode39 en PCL.
Cela est bien suffisant pour de nombreux cas d'utilisation et lisible par de nombreux scanner!

Après quelques modifications du programme et l'écriture de compile.bat (pour compiler sous Harbour + Visual Studio 2008), j'ai réussi à générer le PCL correspondant au BarCode dans un fichier grâce à l'instruction SET ALTERNATE... voir le contenu du fichier BarCodeHPFile.txt

Quelques-manipulation à l'aide de PSPAD (qui supporte le mode binaire) m'aura permi d'intégrer le code barre à l'endroit approprié d'une note d'envoi... Hé HOP... imprimé :-)
Avec l'aimable autorisation de
la société Guy Gerard SPRL

Code Source
J'ai reconstitué une archive avec le code source modifié.
C'est un peu brouillon car toujours à l'état de prototype mais cela compile et fonctionne parfaitement.
Le code génère une fichier BarCodeHPFile.txt contenant le PCL code pour le code barre (intégré dans l'image ci-dessus) :-)

Le code source: BarCode39HpPcl.zip

Compile.bat permet de compiler le programme avec Harbour-Project (version 30) et utilise Visual Studio Express 2008.
Il faut absolument démarrer la compilation "compile.bat" depuis un "prompt visual studio 2008" (Start Menu | Programmes | Visual Studio 2008 Express edition | utilities ... ou quelque-chose de très similaire)

PSPad (encore Open-Source) est un outil pratique vous permettant de visualiser facilement le contenu du fichier généré... il support un affichage de fichier Binaire ainsi que les opérations de copier/couper/coller bien nécessaire  pour faire ce type de prototypage :-)

Crédits
  • Merci à Bill Wood  Milwaukee pour le code en VB, 1985
  • Merci à George T. Neill pour la source Clipper (portage)... probablement en 1989
Comme quoi, même du code écrit en 1985 peut toujours être exploité 2012

jeudi 9 août 2012

Clipper: fonctions de traitement des dates

Rien de tel qu'une bonne référence.... voici une liste des fonctions permettant de traiter les dates en Clipper (et Harbour).

TRUE || FALSE       BETWEEN(<TargetData>, <FirstData>, <SecondData>)
cDayName            CDOW(<dExp>)
cMonth              CMONTH(<dDate>)
dDate               CTOD(<cDate>)
dSystem             DATE()
nDay                DAY(<dDate>)
nDay                DOW(<dDate>)
cDate               DTOC(<dDate>)
cDate               DTOS(<dDate>)
lEmpty              EMPTY(<exp>)
dDate               FT_ACCTADJ( [ <dGivenDate> ], [ <lIsEnd> ] )
aDateInfo           FT_ACCTMONTH( [ <dGivenDate> ], [ <nMonthNum> ] )
aDateinfo           FT_ACCTQTR( [ <dGivenDate> ], [ <nQtrNum> ] )
aDateInfo           FT_ACCTWEEK( [ <dGivenDate> ], [ <nWeekNum> ] )
aDateInfo           FT_ACCTYEAR( [ <dGivenDate> ] )
nTrueDays           FT_ADDWKDY( <dStart>, <nWorkDays> )
aRetVal             FT_CALENDAR ( [ <nRow> ], [ <nCol> ], [ <cColor> ], [ <lShadow> ] , [ <lShowHelp> ] )
cMILTIME            FT_CIV2MIL( <cCIVTIME> )
aDateInfo           FT_DATECNFG( [ <cFYStart> ], [ <nDow> ] )
aDateInfo           FT_DAYOFYR( [ <dGivenDate> ], [ <nDayNum> ], [ <lIsAcct> ] )
nDays               FT_DAYTOBOW( [ <dGivenDate> ] )
<nResult>           FT_DOY( <dDate> )
dEdate              FT_EASTER( <xYear> )
nMINUTES            FT_ELAPMIN( <cTIME1>, <cTIME2> )
aTimedata           FT_ELAPSED([ <dStart> ], [ <dEnd> ], ; <cTimeStart>, <cTimeEnd>)
cDiff               FT_ELTIME( <cTime1>, <cTime2> )
dFirstDay           FT_FDAY( [ <dDateToChk> ] )
dLastDay            FT_LDAY( [ <dDateToChk> ] )
dDate               FT_MADD( [ <dGivenDate> ], [ <nAddMonths> ], [ <lMakeEOM> ] )
dMILTIME            FT_MIL2CIV( <cCIVTIME> )
nMINUTE             FT_MIL2MIN( <cMILTIME> )
aDHM_               FT_MIN2DHM( <nMinutes> )
cMILTIME            FT_MIN2MIL( <nMINUTE> )
aDateInfo           FT_MONTH( [ <dGivenDate> ], [nMonthNum] )
aDateInfo           FT_QTR( [ <dGivenDate> ], [ <nQtrNum> ] )
cMILTIME            FT_SYS2MIL()
aDateinfo           FT_WEEK( [ <dGivenDate> ], [ <nWeekNum> ] )
nDays               FT_WORKDAYS( [ <dStart> ], [ <dStop> ] )
<nResult>           FT_WOY( <dDate> )
aDateInfo           FT_YEAR( [ <dGivenDate> ] )
dLarger             MAX(<nExp1>, <nExp2>) --> nLarger MAX(<dExp1>, <dExp2>)
dSmaller            MIN(<nExp1>, <nExp2>) --> nSmaller MIN(<dExp1>, <dExp2>)
nMonth              MONTH(<dDate>)
NIL                 QOUT([<exp list>]) --> NIL QQOUT([<exp list>])
nSeconds            SECONDS()
NIL                 SLEEP(<nSec>)
cTimeString         TIME()
cFormatString       TRANSFORM(<exp>, <cSayPicture>)
cType               TYPE(<cExp>)
cType               VALTYPE(<exp>)
nYear               YEAR(<dDate>)

mercredi 27 juin 2012

Clipper: Comment installer Harbour sous Ubuntu

Voici un article qui explique comment:
  • Installer les sources de Harbour
  • Le compiler
  • Compiler le premier programme clipper
SOUS UBUNTU.

Je n'ai pas encore testé cette référence... mais c'est toujours bon à prendre
http://www.elart.it/links/harbourhowto_deb_en.php

mardi 12 juin 2012

Clipper: Définition des classes en Harbour

La documentation Harbour reprend bien des informations relative à la définition des classes.
Si vous trouverez des exemples dans le guide de référence Harbour, ce dernier ne contient pas d'exemple d'implémentation (Erreur HTTP 404).

Références de base
Voici un petit récapitulatif d'information:
  • CLASS - Définition de la classe (incluant les objets de données et les méthodes) (guide de référence)
  • DATA - Définition des données de la classe (guide de référence)
  • METHOD - Définition des méthodes de la classe (guide de référence).
Exemple d'implémentation
Voici un exemple partiel d'implémentation de classe issu des sources d'Harbour (fichier drawimg.prg)
CLASS wPaintObj FROM wGUIObj
   * image like wvtimage
   DATA cImage
   DATA lTransp

   METHOD New()
   METHOD Draw()
   METHOD Undraw()
   METHOD Hide()
   METHOD Show()
ENDCLASS //wPaintOBJ

METHOD New(nWinNum, nType, cId, nRow1, nCol1, nRow2, nCol2, aOffTLBR, lTransp) CLASS wPaintObj
   default aOffTLBR to {0,0,0,0}
   default lTransp to .f.

   ::nWinNum := nWinNum
   ::lVisible := .t.

   ::nType := nType
   ::cId := cId
   ::nRow1 := nRow1
   ::nCol1 := nCol1
   ::nRow2 := nRow2
   ::nCol2 := nCol2

   if !(valtype(aOffTLBR)=="A")
      aOffTLBR := {0,0,0,0}
   endif

   ::aOffTLBR := aclone(aOffTLBR)

   ::lTransp := lTransp
RETURN Self

METHOD Draw() CLASS wPaintObj
   if !::lVisible
      return NIL
   endif

   do case
      case ::nType==WPAINTOBJ_IMAGE
         if !empty(::cImage)
            WVW_DRAWIMAGE( ::nWinNum, ::nRow1, ::nCol1, ::nRow2, ::nCol2, ;
                           ::cImage, ::aOffTLBR, ::lTransp )
         endif

      otherwise
         * lBoxErrMessage()
   endcase

RETURN NIL  //DRAW()


Et cet exemple est accompagné du code utilisant cette classe

oWPaint := wPaintObj():New(0, WPAINTOBJ_IMAGE, "TOPLEFT", ntop+1, nleft+1, nmidver-1, nmidhor-1, NIL, ltransp)
oWPaint:cImage := cpict


Constructeur New
Une classe contient généralement un constructeur (appelé New).
Ce dernier retourne une référence vers l'instance de la classe nommé Self

Self et ::
Dans la définition (et l’implémentation) d'une classe, Self fait référence à l'instance de la classe (un objet donc).
Self dispose aussi d'une notation raccourcie qui est ::

Classe et Héritage
Voici un autre exemple qui démontre l'utilisation de l'héritage des classes en Harbour.
Cet exemple est issus de classinh.ch (dans les sources de Harbour)

/*
 * $Id: clasinh.prg 2186 2000-02-14 08:11:56Z vszel $
 */

#include "hbclass.ch"

function main()
   local oObject, oBase
   oObject := TAnyClass():New()
   oBase := TClassBase():New()
return nil

class TClassBase
   method New()
   method Test() INLINE Alert( "Test" )
endclass

method New() class TClassBase
return Self

class TAnyClass from TClassBase
   method New()
endclass

method New() class TAnyClass
   super:New()
   super:Test()
return Self

lundi 11 juin 2012

Clipper: Réference Clipper/Harbour

Besoin de faire du clipper mais vous manquez de référence?
Voici quelques liens vraiment utiles:

Clipper: Integration de la souris sous Harbour

Aussi simple que:

  // enable mouse events in CL53/Harbour
  set( _SET_EVENTMASK, INKEY_ALL )
  mSetCursor( .t. ) 

Pour avoir un exemple plus complet sur le test souris, je vous propose la lecture de:
Source:

Clipper: Comprendre les CodePage & Unicode en Harbour

Voici un excellent Article sur le sujet:
J'y ai trouvé de nombreuses réponses.

jeudi 7 juin 2012

Clipper: Conversion Dos-Windows avec Harbour

Introduction
Porter et maintenir un ancien soft Clipper sous Harbour c'est aussi faire face à quelques problèmes de conversions. Argf.

En effet, votre vieux logiciel fonctionne sous un environnement "Dos" (même si c'est Compiler avec Harbour pour être compatible avec Win7) et répond donc à la codification DOS.

Nous avons par exemple un produit qui est du "2.5 mm²"... il s'affiche très bien dans l'application Clipper... mais une fois exporté vers Excel ou imprimé sur une étiquette code barre (vie OleAutomation avec Harbour) notre beau "2.5 mm²" (sous Dos) devient "2.5mmÿ" (sous Windows).

Il faut avouer que c'est un peu "vilain".
Ce qu'il faudrait, c'est convertir notre  "2.5 mm²" Dos en "2.5 mm²" Windows!

Conversion de chaine de caractère entre Dos-Windows
C'est en fouillant sur le net que je découvre l'existence de OemToCharA et CharToEomA dans la bibliothèque User32.
OemToCharA est utilisé pour convertir une chaine de caractère Dos -> Windows.
CharToOemA est utilisé pour convertie une chaine de caractère Windows -> Dos.
Ces deux articles suivants furent une source d'inspiration salvatrice
Conversion Dos-Windows en Clipper (Harbour Project)
Armé de ces information je fais des recherches dans le répertoire de Harbour Project et je trouve une relation entre "CharToEom" et "OemToAnsi" (humm intéressant).
En faisant une nouvelle rechercher sur "OemToAnsi" dans les source d'Harbour je trouve alors l'exemple suivant dans DbfToPg.PRG:
oRecord:FieldPut( i, hb_oemtoansi( cValue ) )

HOURRA!!!!!!

La mise en pratique de la fonction hb_oemtoansi() me permet d'imprimer immédiatement mes étiquettes code-barre (sous imprimante Windows) avec une conversion correcte de mon "²" de Dos vers Windows :-)
Pour résumer donc:
  • HB_OEMTOANSI() conversion Dos -> Windows
  • HB_ANSITOOEM() conversion Windows -> Dos



jeudi 31 mai 2012

Clipper: Comment retrouver les paramètres en ligne de commande

Si vous utilisez Harbour pour compiler votre code Clipper, vous pourrez trouver le petit bout de code ci-dessous vraiment utile :-)

   IF int_ParamCount > 0
     FOR int_LoopCounter = 1 TO int_ParamCount
       ? arr_Parameters[int_LoopCounter] 
     NEXT
   ENDIF


J'ai trouvé cette information sur ce Thread.

Je n'ai jamais cru que je retournerais vers un aussi vieux langage... il était pourtant si bien pensé.
C'est poursuivant le développement de notre application que je m’aperçoit que ni Dot.Net ni Python ne sont vraiment révolutionnaires.
Tout ce que je trouvais vraiment bien dans ces environnements existe aussi dans mon bon vieux Clipper d'il y a 20 ans.
Je sais même:
  • Imprimer en réseau
  • Faire de l'OleAutomation avec Excell !!!
  • Imprimer des étiquettes codes barres
  • Faire des appels stored/proc

Vive Harbour Project!


mardi 8 mai 2012

Clipper: Imprimer des étiquettes Code Barre sur un imprimante QL-570

C'est possible grâce à la combinaison:
  1. du pac-SDK de Brother, 
  2. Technologie COM 
  3. Harbour (compilateur Clipper Open-Source)
Harbour est un compilateur Clipper Open Source.
Il utilise lui même un compilateur C pour générer un exécutable Win32.
Pour notre part, nous utilisons MSVC (Visual C++ 8.0) puisque nous intégrons aussi Mediator (pour remplacer DBF par une DB PostGreSql).

Le projet Harbour dispose de nombreuses contributions, entre autre une concernant l'impression en mode RAW (super pour piloter une imprimante HP depuis du code Clipper) mais aussi une autre contribution  relative aux appels OLE (comprenez, aussi "COM").

L'exemple TestOle.prg d'Harbour
Le projet Harbour contient la contribution:
c:\hb30\contrib\hbwin\tests\testole.prg
qui démontre l'usage de COM depuis un projet écrit CLIPPER et compilé avec Harbour.

Croyez le ou pas MAIS CA MARCHE DU TONNERRE!!!
Ouvrir une feuille Excel, Ouvrir un document Word ou OpenOffice, démarrer InternetExplorer et naviger vers la page du projet Harbour. De petits exemple mais franchement bluffant pour une technologique qui date quand même de 20 ans!

Le plus dur est encore d'arriver à compiler le PRG en exécutable.
Je vous propose le petit fichier Batch suivant qui effectue toutes les étapes nécessaires.

Ses particularités sont:
  1. D'utiliser MSVC comme compilateur (il ***faut absolument*** lancer le batch depuis une "Invite de Commande Visual Studio 2008")
  2. De linker les bonnes librairies OLE (cherchez après OleAut32.lib & Ole32.lib)
  3. Link les librairies Mediator (MedNtx). Vous n'en aurez probablement pas besoin, vous pouvez donc enlever les références à
    %MEDDIR%\harbour\lib\%HBBUILD%\vc80\medntx.lib
    %MEDDIR%\harbour\lib\%HBBUILD%\vc80\cmnnet32.lib
Voici le batch ZZD-TestOle.bat qui compile le projet TestOle.PRG

rem RUN IT BY using the Visual Studio C++ compiler COMMAND LINE (via start menu)
rem   http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express

REM set HBDIR to the directory where HARBOUR is installed
SET HBDIR=c:\hb30
REM set MEDDIR to the directory where Mediator is installed
SET MEDDIR=c:\medcl
REM set HBBUILD to the name of the xHarbour build (for ex. build80)
SET HBBUILD=build3000

%HBDIR%\bin\harbour -m testole.prg /i%HBDIR%\include/i%MEDDIR%\xharbour\include /dHBCL 
if errorlevel 1 goto error_end

cl -c /w /TP /GA /Gs /Zl /nologo /I%HBDIR%\include /dHBCL testole.c 
if errorlevel 1 goto error_end

link /OUT:TestOle.exe /subsystem:CONSOLE testole.OBJ %HBDIR%\lib\win\msvc\hbwin.lib %HBDIR%\lib\win\msvc\hbdebug.lib %HBDIR%\lib\win\msvc\hbvm.lib %HBDIR%\lib\win\msvc\hbrtl.lib %HBDIR%\lib\win\msvc\rddntx.lib %HBDIR%\lib\win\msvc\hblang.lib %HBDIR%\lib\win\msvc\hbrdd.lib %HBDIR%\lib\win\msvc\hbmacro.lib %HBDIR%\lib\win\msvc\hbpp.lib %HBDIR%\lib\win\msvc\hbcommon.lib %HBDIR%\lib\win\msvc\gtwin.lib %HBDIR%\lib\win\msvc\hbsix.lib %HBDIR%\lib\win\msvc\rddfpt.lib winspool.lib wsock32.lib kernel32.lib user32.lib advapi32.lib OleAut32.lib Ole32.lib %MEDDIR%\harbour\lib\%HBBUILD%\vc80\medntx.lib %MEDDIR%\harbour\lib\%HBBUILD%\vc80\cmnnet32.lib
if errorlevel 1 goto error_end

goto end

:error_end
echo !!!!!!!!!!!!!! ERROR IN ZZD-testole.BAT !!!!!!!!!!!!!!!!!!!!

:end


Une fois compilé, il est facile de s'apercevoir que les appels OLE fonctionnent assez bien.
J'ai personnellement fait mes test sous Win 7 64 bits (programme compilé en 32 bits)

Impression d'étiquettes sur une QL-570
L'article "QL-570: utilitaires pour imprimer facilement des étiquettes" présentait un bout de code vbs permettant d'imprimer une étiquette via l'interface COM du b-pac SDK de Brother.


Fort de mes premiers résultats, j'ai ajouté une fonction CLIPPER dans le programme TestOle.PRG me permettant de faire les appels COM depuis Clipper.
Cette fonction  Exm_PrintPac mime le fonctionnement du VBS en utilisant les capacités COM de harbour.
 STATIC PROCEDURE Exm_PrintPac()
    IF ( oObjDoc := win_oleCreateObject( "bpac.Document" ) ) != NIL
      ? oObjDoc:Open( "C:\Program Files (x86)\Brother bPAC3 SDK\Templates\NamePlate1.lbx" )
      
      oComp := oObjDoc:GetObject("objCompany")
      oComp:Text := "Brother Industries, Ltd."
      
      oComp2 := oObjDoc:GetObject("objName")
      oComp2:Text := "myself, Dodo"
      
      && ObjDoc.SetMediaByName ObjDoc.Printer.GetMediaName(), True
      oPrinter := oObjDoc:Printer
      mediaName = oPrinter:GetMediaName()
      ? mediaName
      
      oObjDoc:SetMediaByName( mediaName, .T. )
       
      oObjDoc:StartPrint( "Brother QL-570", 0 ) && Nom du document dans le spooler
      oObjDoc:PrintOut( 1, 0 ) && 1= nbre de copies
      oObjDoc:EndPrint()
      oObjDoc:Close()
      
   ELSE
      ? "Error: bpac.document not available. [" + win_oleErrorText()+ "]"
   ENDIF

   RETURN

Et comme attendu... une fois appelée, cette fonction sort la bonne étiquette.

Merci OTC!
Notre société migre un logiciel vieux de 20 ans vers PostGreSql (grâce à la technologie RDD), Harbour et Mediator.
Mediator est un produit OTC qui nous fournit la technologie RDD dont nous avons besoin et nous permet d'utiliser une base de données relationnel PostGreSql (à la place des fichiers DBFs).
Médiator est un produit très aboutit et performant!
Notre logiciel est d'ores et déjà en test sur Win 7 64 bits dans un environnement multi-utilisateurs.


Pour la première fois de ma vie de développeur j'ai rencontré un service support à classer dans la catégorie  "exceptionnel".
OTC fournit un support de qualité, compétant et endurant! (notre cas ne fût certainement pas l'un des plus simples).
A chaque embûche j'y ai trouvé de l'aide, que cela soit un problème de migration ou de compilation.
Si je remercie OTC aujourd'hui c'est parce que la compilation de OleTest.PRG regroupe une grande partie des connaissance que OTC m'a prodigué ces derniers mois (quand je parle d'endurance, ce n'est pas pour rien).
Mes remerciements vont plus particulièrement à Miss Bozena Potempa du service Support.

lundi 7 mai 2012

QL-570: utilitaires pour imprimer facilement des étiquettes

Dans mon long processus de migration de Clipper vers Harbour, je suis face à un problème en apparence épineux... en effet, il me faut imprimer des étiquettes Code Barre sur notre QL-570 en réseaux.

P-Touch Template & ESC/P
Au cours de mes recherches, je me suis aperçu que la méthode ci-dessous n'est pas compatible avec les QL-570. Il existe cependant une alternative (voir autre point plus bas)

Au cours de mes recherches, j'ai trouvé le logiciel P-Touch (visiblement de Brother) accompagné de PTouch Template et PTouch ESC/P (permettant de piloter l'imprimante avec des séquences d'échappement).

Vous trouverez plus d'informations depuis la section développement du site de brother.

Je me suis personnellement penché plus attentivement sur la vidéo suivante:


C'est de bon présage :-)

P-Touch Editor et b-pac SDK
L'option ESC/P n'est visiblement pas applicable pour une QL-570. C'est bien dommage car cela semblait pourtant parfait.
Visiblement, cela serait causé par le fait qu'une QL-570 fonctionne uniquement en mode raster (comprenez par envoi de données point-à-point/sous forme d'image). Dans ce cas, il est bien évidement difficile de commander l'imprimante avec des séquences d'échappement.

Par contre, il est possible de contourner le problème à l'aide d'une interface COM.
Brother propose P-Touch Editor, un éditeur d'étiquette qui permet de préparer ses étiquettes et de nommer les différentes zones. Une fois sauvée, cette étiquette peut devenir un modèle (template pour les initiés).

Il est possible de se procurer séparément b-pac SDK. Ce dernier est une interface COM permettant de piloter l'impression de P-Touch editor (recharger le modèle, modifier le contenu des zones nommées, lancer l'impression).

Des exemples fournis avec le SDK, j'ai tiré  NamePrn.vbs, exemple qu'il m' fallut modifié pour le faire fonctionner.
Pour cause, le répertoire mentionné par sDataFolder n'était pas correct (le (x86) pour un Windows 64 bits). et j'ai également précisé le nom de l'imprimante dans StartPrint (le nom tel que connu par Windows dans le volet Configuration|imprimante).
Sinon cela fonctionne :-)

' b-PAC 3.0 Component Sample (Instant Name Plate)
' (C)Copyright Brother Industries, Ltd. 2009
'
'<SCRIPT LANGUAGE="VBScript">
 ' Data Folder
 Const sDataFolder = "C:\Program Files (x86)\Brother bPAC3 SDK\Templates\"
 DoPrint(sDataFolder & "NamePlate1.lbx")

 '*******************************************************************
 ' Print Module
 '*******************************************************************
 Sub DoPrint(strFilePath)
  Set ObjDoc = CreateObject("bpac.Document")
  MsgBox( strFilePath )
  bRet = ObjDoc.Open(strFilePath)
  If (bRet <> False) Then
    MsgBox("OPEN :-) ")
   ObjDoc.GetObject("objCompany").Text = "Brother Industries, Ltd."
   ObjDoc.GetObject("objName").Text = "John Smith"
   ObjDoc.SetMediaByName ObjDoc.Printer.GetMediaName(), True
   ObjDoc.StartPrint "Brother QL-570", 0
   ObjDoc.PrintOut 1, 0
   ObjDoc.EndPrint
   ObjDoc.Close
  End If
  
    MsgBox("Hello world")
  Set ObjDoc = Nothing
 End Sub


Ressources utiles

jeudi 29 mars 2012

Debug file en Clipper

Introduction
Pouvoir disposer d'un outil de debugging minimal peut revêtir une importance capitale.
C'est encore plus vrai lorsque l'on maintient un vieux logiciel en Clipper (re-compilé avec Harbour + Visual Studio C++ 2008).

Comme je compile le soft en ligne de commande, je n'ai pas cette chance de pouvoir disposer d'un déboggeur ARFF!
Je voulais donc utiliser d'un fichier de déboggage et d'une fonction DMSG (Debug Message) me permettant de laisser des traces dans ce fichier de trace. Fichier bien utile car il permet de capturer des informations sur le fonctionnement du programme.

Clipper à prévu le coup avec les commandes "SET ALTERNATE TO" permettant de rediriger la sortie de la console vers un fichier. Idéal pour laisser une trace :-)
Malheureusement pour moi, cette fonctionnalité est déjà utilisé à d'autres fins... a moi donc d'utiliser un autre procédé pour y arriver.

FT_FUSE - manipulation de fichier
Il existe heureusement les fonction FT_FUSE et consort!
Voici l'implémentation de la procédure DMSG, une fonction qui écrit des message dans un fichier "debug.log".
Cette fonction utilise également la variable globale dbgLineCount pour incrémenter le numéro de ligne.
#include "fileio.ch" 

...

&& DMSG - Debugging Message 
&&  line counter for DMSG procedure
PUBLIC dbgLineCount 
dbgLineCount = 0   

...

*****************
PROCEDURE DMSG
*****************
*  Write a debug.log file by inserting records on the top of the file
*  If the file is not present, nothing is written into it
*     see FT_USE   @ http://www.ousob.com/ng/nanfor/ng2319d.php
*     see FILE I/O @ http://www.itk.ru/clip-doc.en/categfileio.html
*     beautiful sample @ http://www.groupsrv.com/computers/about324430.html   
*     
*  27/03/2012 - WARNING function is buggy and may turns into infinite loop !
*  29/03/2012 - Fixed :-)
  parameters sMsg   

  private hFile
  private sToWrite

  dbgLineCount = dbgLineCount + 1 && Line counter
    
  dbgFilename = "c:\stock\debug.log"
    
  ft_fselect(1) 
  hFile := fopen(dbgFilename, FO_READWRITE + FO_SHARED)
  hFile := ft_fuse(dbgFilename)      
  if hFile < 0
    return
  endif

  * Data to write in the Debug File (place CR/LF at the end of file)  
  sToWrite = Str(dbgLineCount) + " " + TIME() + " " + sMsg + chr(13) + chr(10)    
  
  * Write a buffer
  fwrite(hFile,sToWrite)   

  * close file
  FT_FUSE()
  
return

L'appel se résume à:

DO DMSG WITH "L477:replace FAMI with TheResult"
Note: le "DO" n'est normalement pas nécessaire, il passe les arguments par référence.

Et le contenu du fichier debug ressemble à ceci:
         3 11:35:05 ------------------- STARTING STOCK ------------------------
         4 11:35:12 0000, main menu exit, SET PRINT OFF
         5 11:35:15 SAYA050 : Say Article - ENTER
         6 11:35:15 before call xaFami(Fami) - validation of fami
         7 11:35:15 L477:replace FAMI with TheResult
         8 11:35:15 after call xaFami(Fami)
         9 11:35:15 SAYA050 : Say Article - LEAVE
        10 11:35:18 BEFORE SUIVANT - will exec skip

En savoir plus sur la manipulation de fichier en Clipper
Vous trouverez des informations sur les opérations fichier dans les références suivantes
J'ai aussi déniché l'excellent article "Comparing input to database fields" posté par Mack Barss.
Je me permet de reprendre le contenu ci-dessous (car il est trop précieux pour prendre le risque qu'il soit perdu!)
//*
//* privsmnu.prg source code
//*
#include "fileio.ch"

//* function load temporary privilege dbf
Function Prv_qProcess
local iEmpnum, iCcde, iUsrid, iSysid
local iPrecust, iSecpack, iUsrpriv

local prvEmpnum, prvCcde, prvUsrid, prvSysid
local prvPrecust, privSecpack, prvUsrpriv

local cntmsg, qUsr, dUsr, mycnt := 0
local mrt, mrb, mcl, mcr, msg_scrn
local rFilename, tmpFilename


tmpFileName := popupdir('C:\IAREVAL\INPUT\*.txt','D','Select Compare file',;
"w+/b,w+/r",.t.)


rFilename := "C:\IAREVAL\INPUT\" + tmpFilename
gFilename := "C:\IAREVAL\REPORTS\GAPFILE.TXT"
mFilename := "C:\IAREVAL\REPORTS\INMASTER.TXT"


if varlen(rFileName) < 20
return
end


ft_fselect(1)
rfile := ft_fuse(rFilename)

ft_fselect(2)
gFile := fcreate(gFilename,FO_READWRITE)
gFile := fopen(gFilename, FO_READWRITE + FO_SHARED)
gFile := ft_fuse(gFilename)

ft_fselect(3)
mFile := fcreate(mFilename,FO_READWRITE)
mFile := fopen(mFilename, FO_READWRITE + FO_SHARED)
mFile := ft_fuse(mFilename)

qUsr := ft_dispmsg( { { "Press [Y] to continue with", ;
"process. Press any other ", ;
"key to abort the process. " }, ;
{ "r/w", "r/w", "r/w" } } , ;
"Y" )

if qUsr = .t.

use PRIVQDBF index PRIVQDBF shared new

plswait(.t.,"Processing compare...")

ft_fselect(1)
rFile := ft_fuse(rFilename)
ft_fgotop()

do while ! ft_feof()

* read line
rline = ft_freadln(rFile)
mycnt = mycnt + 1

iEmpnum := substr(rline, 1, 6)
iCcde := substr(rline, 18, 3)
iUsrid := substr(rline, 28, 20)
iSysid := substr(rline, 49, 1Cool *** probablement iSysid := substr(rline, 49, 18)
iPrecust := substr(rline, 68, 20)
iSecpack := substr(rline, 89, 16)
iUsrpriv := substr(rline,106, 45)
iRevFile := substr(rline,152, 44)

select PRIVQDBF
dbgotop()

do while !eof()
BEGIN SEQUENCE
if iEmpnum = Empnum .and. iCcde = Ccde .and. iUsrid = Usrid ;
.and. iSysid = Sysid .and. iSecPack = Secpack .and. iUsrpriv =
Usrpriv

//* write dbf record to txt file *//
tmplne := empnum + ccde + usrid + sysid + precust + secpack +
usrpriv + revfile
fwrite(mfile,tmplne)
BREAK
else
forget()
skip
endif
End
end

//* record not found - write to gap file *//
tmplne := iEmpnum + iCcde + iUsrid + iSysid + iPrecust + iSecpack +
iUsrpriv + iRevfile
fwrite(gfile,tmplne)

tmplne := ""
ft_fselect(1)
ft_fskip()
enddo

close all
plswait(.f.)
msg_scrn = savescreen(0,0,Maxrow(),79)
msgcolor = "n/w,n/w,,,n/w"
setcolor(msgcolor)

mrt := maxrow()/2-2
mrb := maxrow()/2+1
mcl := maxcol()/2-9
mcr := maxcol()/2+9
clearbox(mrt,mcl,mrb,mcr,'Single')
@mrt+1,mcl+1 say " # Records read:"
@mrt+2,mcl+3 say " ==> " + ltrim(str(mycnt))

inkey(20)
setcolor(defColor)
restscreen(0,0,Maxrow(),79,msg_scrn)
endif
return nil

*: Eof: privsmnu.prg 

jeudi 22 mars 2012

Guide de référence du langage Clipper

Si un jour vous avez besoin de référence sur la programmation clipper, allez donc jeter un œil ici.

Simple et efficace.

mercredi 21 mars 2012

Gestionnaire de Version sous Windows

Aujourd'hui, je cherchais un gestionnaire de version sous Windows, libre de préférence.
Je n'ai pas de grands besoins, juste celui de pouvoir revenir en arrière sur un développement en Clipper sous Win7 64 bit.

Je n'ai donc pas besoin d'un canon pour tuer une mouche.


Bien malheureusement, il m'a fallut presque une demi-journée pour trouver un produit approprié à mes besoins tout en restant simple d'emploi (et mise en œuvre facile).

C'est qu'en fin de compte, entre produit inutilisable, usine à gaz et soft devenu payant, il ne reste plus grand chose de praticable (facile à prendre en mains et prêt à l'emploi en quelques minutes).

J'ai fini par trouver mon bonheur dans le couple Tortoise + SubVersion (pour Windows).
Avec un excellent manuel de mise en place disponible sur Developpez.Com (merci Eric Reboisson!)

Besoin d'une solution de gestion de version pour vos codes sources, commencez par cette option.