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!

Thursday, May 3, 2018

Enhanced ImageCapture (an Imaging Capturing Tool)


I am currently working on a new project where I needed to capture images again for the Sellers to be used on their ID and on forms, so I fished out ImageCapture.prg which Gelson L. Bremm shared to us:  http://weblogs.foxite.com/vfpimaging/2006/03/20/capture-screen-portions/

But this time I decided to attempt to enhance it for my needs so I changed some approaches and used GDIPlus-X for the saving of the image instead of the original approach he has implemented.  Doing so, I was able to cut around 60% of the original codes too.   Check this for GDIPlus-X: https://github.com/VFPX/GDIPlusX in case you needed to download it.

Likewise incorporated here is a simple trick on form nudging capability so you can use the keyboard arrows to position the capture form which is easier than purely using mouse.  Also, when you adjust the form width and height, there is no need for you to worry adjusting the capture coordinates as well as that will also auto-adjust based on both form height and width set.

Here is the enhanced version of that:

* Enhanced version of ImageCapture.prg (May 3, 2018)
* Original Developer:  German L. Bremm
* http://weblogs.foxite.com/vfpimaging/2006/03/20/capture-screen-portions/

Lparameters toObject, cFileOutput
Public gToObject, gcFileOutput
gToObject = m.toObject
gcFileOutput = m.cFileOutput

Public oCapturaImg
oCapturaImg = Createobject("ImgCapture")
oCapturaImg.Show()

Define Class ImgCapture As Form
      Name = "ImgCapture"
      Height = 332
      Width = 300
      AutoCenter = .T.
      Caption = "Position over the Image you want to Capture"
      MaxButton = .F.
      MinButton = .F.
      AlwaysOnTop = .T.
      ShowWindow = 2
      BorderStyle = 0
      BackColor = Rgb(60,60,60)
      _nBorder = Sysmetric(10)
      _nTitleBarHeight = Sysmetric(9)
      _nFormWidth = 0
      _nFormHeight = 0

      Add Object cmdSnap As CommandButton With;
            Height = 28,;
            Caption = '\<Grab Image',;
            Width = 142,;
            Left = 5,;
            FontName = 'Arial',;
            FontSize = 14,;
            FontBold = .T.

      Procedure Init
            Declare Integer CombineRgn In "GDI32" Integer hDestRgn, Integer hRgn1, Integer hRgn2, Integer nMode
            Declare Integer CreateRectRgn In "GDI32" Integer X1, Integer Y1, Integer X2, Integer Y2
            Declare Integer SetWindowRgn In "user32" Integer HWnd, Integer hRgn, Integer nRedraw
            This.Resize()
      Endproc

      Procedure Resize
            With This
                  .cmdSnap.Left = .Width-.cmdSnap.Width-4
                  .cmdSnap.Top = .Height-.cmdSnap.Height-5
                  .cmdSnap.Tag = Allt(Str(.cmdSnap.Left))
                  .SetTransparent()
            Endwith
      Endproc

      Procedure SetTransparent
            Local lnInnerRgn, lnOuterRgn, lnRgnHandle
            With This
                  ._nFormWidth = .Width + (._nBorder * 2)
                  ._nFormHeight = .Height + ._nTitleBarHeight + ._nBorder
                  lnOuterRgn = CreateRectRgn(2, 2, ._nFormWidth+2, ._nFormHeight+2)
                  lnInnerRgn = CreateRectRgn(._nBorder+6,._nTitleBarHeight+8,._nFormWidth-._nBorder-4,._nFormHeight-._nBorder-34)
                  lnRgnHandle= CreateRectRgn(0, 0, 0, 0)
                  CombineRgn(m.lnRgnHandle, m.lnOuterRgn, m.lnInnerRgn, 4) 
                  SetWindowRgn(.HWnd , m.lnRgnHandle, .T.)
                  .BorderStyle = 1
            Endwith
      Endproc

      Procedure CopyToFile
            Do Locfile("system.app")
            Local locapturebmp As xfcbitmap, lcImage
            lcImage = m.gcFileOutput
            If Empty(m.lcImage)
                  lcImage = Getpict("png")
            Endif
            Clear Resources
            With _Screen.System.drawing
                  * Coordinates are X, Y, Width and Height
                  locapturebmp = .Bitmap.fromscreen(Thisform.HWnd,;
                        thisform._nBorder+6,;
                        thisform._nTitleBarHeight+8,;
                        thisform._nFormWidth-Thisform._nBorder-10,;
                        thisform._nFormHeight-Thisform._nBorder-Thisform.cmdSnap.Height-36,;
                        .F.)
                  locapturebmp.Save(m.lcImage, .imaging.imageformat.png,.imaging.imageformat.png)
            Endwith
            * Update target Image object
            gToObject.Picture = m.lcImage
            CLEAR RESOURCES m.lcImage
      Endproc

      Procedure KeyPress
            Lparameters nKeyCode, nShiftAltCtrl
            * Use Keyboard arrows to nudge frame
            Do Case
            Case m.nKeyCode = 24  && move down
                  Thisform.Top = Thisform.Top + 1
            Case m.nKeyCode = 5  && move up
                  Thisform.Top = Thisform.Top - 1
            Case m.nKeyCode = 19  && move left
                  Thisform.Left = Thisform.Left - 1
            Case m.nKeyCode = 4  && move right
                  Thisform.Left = Thisform.Left + 1
            Endcase
      Endproc

      Procedure cmdSnap.Click
            This.BackColor = Rgb(255,0,0)
            This.Caption = 'Capturing...'
            Thisform.CopyToFile()
            Thisform.Release()
      Endproc

      Procedure Destroy
            oCapturaImg = Null
            gToObject = Null
            gcFileOutput = Null
            Release oCapturaImg
            Release gToObject
            Release gcFileOutput
            Release CombineRgn
            Release CreateRectRgn
            Release SetWindowRgn
      Endproc
Enddefine

If you notice, I am passing two parameters.  First parameter is the image object to show the result of the capturing and the second one is the fullpath and name of the file to be saved.  Calling it is like this:

Do Form snagface With thisform.Image1, csrGrid.sellerid

So I can call that from anywhere on my form and immediately after grabbing an image, it gets displayed on an Image object.  And here is how it looks like (using my favorite cat as the model):




Darn, I really love that cat's expression.  Always makes me smile. :)

Special thanks to both Gelson L. Bremm and Cesar Chalom for this and other tools Cesar has shared to us.