Wednesday, March 31, 2021

VFPA, the way forward for VFP Lovers!

Some of us (including yours truly) finds it very hard to move away from VFP.  Not because I can’t learn a new language but the moment I started trying to learn a new one, my mind always compares the syntax with VFP which seems to be embedded already in my being.  So I always ended up with thoughts like “if it is done in VFP9, there are only fewer lines to do such!” or “Heck, why did they made it like this when in VFP9…”.  In the end I lose interest in the new language.  Not to mention that there really is no demand for me on said language.

Still, learning and knowing more than VFP is really beneficial to us as developers.  Anyway, finally I tried VFPA by Chuanbing Chen, basically because I want its protection against decompilation; of course at first with some inhibitions.  So I decided to try and use that for a new client.

The moment I realized that it actually does not overwrite the copy of my VFP9 SP2 and instead creates its own folder, I said to myself “Hey, this is great!  I can run both VFP9 and VFPA in a single machine and in case something goes wrong, I can simply reopen the project back to VFP9 and recompile there!”.  

So that was the plan!  A plan that never happened because I observed VFPA to be more stable than VFP9.  And that is not a surprise considering Chen has fixed a lot of bugs that remain with VFP9.   So since I started using VFPA, I never went back to VFP9 anymore.  And when my other client requested new enhancements on my existing app, I moved them as well to VFPA.

Right now, I am still using just VFPA-32 bit.  But Chen offers more than that such as VFPA-64 bit and VFPCompiler.

If you are interested in checking Chuanbing Chen’s VFPA in its original language, please click this link.  

If you want to read his site in English, you can use this link  

Also the list of Fixed VFP9 Bugs in VFPA:  

If you want to learn further about VFPA, you can view this video  

Anyway, the purpose of this entry here is to introduce VFP Advanced to my readers, if you still are not aware of it.  Personally?  Though I have just recently used VFPA, and by recently I mean since December 2020 only, I am very much satisfied with it.  As a parting words, move to VFPA.


Saturday, June 6, 2020

Drag, Drop and Restrict

I have just read a problem inside foxite where when a user accidentally moves the mouse beyond the form boundaries, then drag and drop fails because the objects disappear on the areas beyond the form. 

The solution to that is to restrict the drag and drop movements within your form, or dimension within objects in your form.  Here are two samples showing how to achieve that:

Sample 1:

* Restricting drag and drop within the form

Local oForm As Form
oForm = Createobject('TestForm')
oForm.Show(1)
Return

Define Class TestForm As Form
      AutoCenter = .T.
      Width = 900
      Height = 440
      Caption = 'Drag, Drop & Restrict Inside Form'
      Add Object container1 As Mycontainer With Top = 30, Left = 50
Enddefine

Define Class Mycontainer As Container
      Height = 100
      Width = 100
      Procedure MouseMove
      Lparameters nButton, nShift, nXCoord, nYCoord
      If m.nButton = 1 And Between(m.nYCoord,0,Thisform.Height-This.Height) And ;
                  BETWEEN(m.nXCoord,0,Thisform.Width-This.Width)
            This.Move(m.nXCoord, m.nYCoord)
      Endif
      Endproc
Enddefine

Sample 2:

* Restricing within objects on form, in this case above or below the lines
Local oForm As Form
oForm = Createobject('TestForm')
oForm.Show(1)
Return

Define Class TestForm As Form
      AutoCenter = .T.
      Width = 900
      Height = 440
      Caption = 'Drag, Drop & Restrict'
      Add Object Shape1 As shape With Top = 30, Left = 0, Width = 900, height = 1
      Add Object Shape2 As shape With Top = 200, Left = 0, Width = 900, height = 1
      Add Object Command1 As MyButton With Caption='Move Me outside of the lines', Top = 35, Left = 5, width = 200, height = 30
Enddefine

Define Class MyButton As CommandButton
      Procedure MouseMove
            Lparameters nButton, nShift, nXCoord, nYCoord
            If m.nButton = 1 AND BETWEEN(m.nYCoord,30,171)
                  This.Move(m.nXCoord, m.nYCoord)
                  WAIT WINDOW m.nYCoord nowait
            Endif
      Endproc
Enddefine

In case you need it.  Cheers!

Friday, November 22, 2019

IE inside the Form

Unlike with placing internet explorer browser inside our form via Internet Explorer Shell, this is similar to my other blogs of opening the URL directly on a browser like Chrome and Firefox, capturing its window handle, adjusting window style and placing said browser inside of our form.  This time though, it is by using Internet Explorer as the Browser as we have more handles on it.  Not to mention that IE automatically comes with the OS unlike the other browsers which our clients may not choose to have.

So why am I suggesting to do it this way when we can do the same via Shell.Explorer?   Well, it is not quite the same actually.  Shell.Explorer for one adjusts the site to the basic design without CSS applied.  So the display you will see will not be entirely the same when you open it via a browser.  Sometimes also, JavaScript hampers its execution especially with the new OS now in place.  Now, opening the browser itself will ensure that it has the latest features, based on your browser version. 

The reason I created this entry is because there is a question inside Foxite forum that if we do it this way, then how to position IE inside our form at specific coordinates and  not as a full screen filling the entire form?   So I am showing here how we can achieve that, as a guide.  Improve it further based on your needs.  Codes follow:

Thursday, September 12, 2019

Enumerating Path Links and Installed Apps

A friend requested for my assistance as they were recently hit by a ransomware so he wants to reformat all machines.  But before that, since there are around 60 machines to be reformatted, he wants to create a list of the path location of the shortcuts on its Desktop plus a list of all installed apps; so he can bring those back properly after reformatting and re-installation. 

Anyway, here is what I am able to come up with based on his request and desire, in a simplified way.  I will add this here in my blogs as this may be useful for others too.  You may adjust it further to suit your needs.

Getting paths of shortcut items (.lnk) as well as enumerating installed Apps

Local loShell, loReg, lcFolder, loFolder, lcUnit, lnLoop, loFile, lcFile, loLink, lcKey, lcApp

Create Cursor LinksNApps (xUnit c(20), xType c(4), Link c(40), xPath c(200))

* Get Links
lcFolder = Getenv("USERPROFILE")+'\Desktop\'
loShell = Createobject("Shell.Application")
loFolder = loShell.Namespace(m.lcFolder)
lcUnit = Getenv("COMPUTERNAME")
Set Default To (m.lcFolder)
For lnLoop = 1 To Adir(aLink,m.lcFolder+'*.lnk')
      lcLink = aLink[m.lnLoop,1]
      loFile = loFolder.ParseName(m.lcLink)
      loLink = loFile.GetLink
      Insert Into LinksNApps Values (m.lcUnit,'Link', m.lcLink, loLink.Path)
Endfor

* Get installed apps
#Define HKLM 0x80000002
Set Procedure To Locfile(Home(2)+"classes\registry.prg"
Dimension akeys(1)
loReg = Createobject('REGISTRY')
lcKey ='SOFTWARE\WOW6432Node'
loReg.OpenKey(lcKey,HKLM,.F.)
loReg.EnumKeys(@akeys)
For lnLoop = 1 To Alen(akeys)
      lcApp = akeys(1,m.lnLoop)
      If !Inlist(m.lcApp,'Classes','Clients','Policies','RegisteredApplications') And Left(m.lcApp,1) <> '{'
            Insert Into LinksNApps Values (m.lcUnit, 'App',akeys(1,m.lnLoop),'')
      Endif
Next

Go Top
Browse NORMAL




Friday, August 17, 2018

CtrlBox on Left Side

Since some are using Arabic/Urdu which deals with the right-to-left reading and data entry, then this trick might be useful to them. Which is to transpose too the position of the ControlBox of Titlebar.

This trick is really quite simple requiring only 3 lines of codes involving GetWindowLong and SetWindowLong.  I just added some codes to show how it looks like.  See if this can come handy to you:


loTest = Createobject("Form1")
loTest.Show(1)
Read Events


Define Class form1 As Form
      AutoCenter = .T.
      Caption = 'ControlBox on Left side'
      ShowWindow = 2

      Add Object label1 As Label With ;
            top = 20,;
            left = 10,;
            FontSize = 16,;
            width = Thisform.Width -20,;
            height = Thisform.Height - 20,;
            WordWrap = .T.,;
            Caption = "This shows how to reverse the title bar's OBJECT positions such as "+;
            "controlbox, icon and labels while leaving the inside of the form on normal left to right positions"

      Procedure Load
            Declare Integer SetWindowLong In user32 Integer HWnd, Integer nIndex, Integer dwNewLong
            Declare Integer GetWindowLong In user32 Integer HWnd, Integer nIndex
            SetWindowLong(Thisform.HWnd, -20, Bitor(GetWindowLong(Thisform.HWnd, -16), 0x80000))
      Endproc

      Procedure Destroy
            Clear Events
      Endproc
Enddefine





Cheers!

Wednesday, June 27, 2018

Grabbing UNC path from a Mapped Drive

I am among those who stores only the fullpath() of the outside files into a field as I do not want to store the actual files inside the tables as that will make the tables huge as time goes by.

I am also not an admirer of a mapped drive as that will lead to a lot of problems later such as giving users easy access to the folder for the app, issue of sleeping mapped drives, or workstations using different mapped drive letters.

Anyway, this is so in case you have mapped drives in your workstations and you want to get a fullpath() of a file using GETFILE(), then you can always get the UNC path if file is coming from a network drive.  For instance, if you have a mapped drive Z:\ and you point to a file there, instead of getting Z:\myFile.jpg you will get \\192.168.1.1\YourFolder\myFile.jpg or something like that instead; where drive Z: will be replaced by the actual UNC path.

Here is a code for that:


Local lcFile
lcFile = GETUNC(Getfile())
Messagebox(m.lcFile)

********
Function GETUNC(cFile)
********
Local lcFullPath, lcDrive, lcUNC, lnSize
If !Empty(m.cFile)
      lcDrive = Justdrive(m.cFile)
      lcFullPath = Fullpath(m.cFile)
      If Drivetype(m.lcDrive) = 4
            lnSize = 600
            lcUNC = Space(lnSize)
            Declare Integer WNetGetConnection In WIN32API String @lcDrive, String @lcUNC, Integer @lnSize
            WNetGetConnection(@lcDrive, @lcUNC, @lnSize)
            lcFullPath = Strtran(m.lcFullPath,m.lcDrive,Left(m.lcUNC,Len(Alltrim(m.lcUNC))-1))
            Clear Dlls WNetGetConnection
      Endif
Endif
Return(m.lcFullPath)

What it will do is if you get a file that is stored on your local drive, then it will just show the normal fullpath(). If you get a file on a mapped drive, then it will replace the mapped drive with the actual UNC Path and combine that with the file to present you with a new fullpath using UNC path instead. The advantage of this is it won't be tied up to a mapped drive which may change from workstation to workstation.  Even if on one workstation, it is mapped to z:\ and on another to x:\, inside your app since it will be stored using the UNC path, it will always point to the proper location.

Cheers!