The LOADPICTURE() Function – (Some) ALL Myths Revealed!

Version: 0.02.02 - last update: Thursday, April 26, 2011, 14:35:00

Previous EntryTips & Tricks Home (TOC)Next Entry 


All you have to know about VFP’s LOADPICTURE() function

Intro

VFP’s LOADPICTURE() creates a COM picture object and returns a fancy ‘crippled’ interface reference! VFP’s LOADPICTURE() function is nothing more than a wrapper around the Windows API function called OleCreatePictureIndirect(), which in turn creates a COM picture object. These COM–wrapped objects are used by many ActiveX controls. You can find out more about OleCreatePictureIndirect() OffSiteLink here. There are some VERY GOOD reasons to use VFP’s LOADPICTURE() functionality! After all, carelessly using COM image objects created by VFP’s LOADPICTURE() function in conjunction with VFP’s native Image controls will introduce some almost non-trappable very tricky malfunctions! If you want to get the best out of it, without spending hours on debugging what seems to be impossible, read the rest of this post!

This is the syntax of the API call wrapped by VFP’s LOADPICTURE() function:

OleCreatePictureIndirect(pPictDesc,; && Pointer to the structure of parameters for picture
			   Riid	  ,;&& Reference to the identifier of the interface
			   fOwn	  ,;&& Whether the picture is to be destroyed
			   ppvObj     && Address of output variable that receives the 
				        && Interface pointer requested in riid

As we all know, the right way to call a COM object’s implementation (inside a DLL) is using one of its interfaces. To figure out the interfaces that are available within a picture COM object, use VFP’s Object Browser. You can load either the “StdTypes” DLL itself (at <windir>\SYSTEM32\OLEPRO32.DLL), or its type library file (<windir>\SYSTEM32\STDOLE2.TLB).

ObjectBrowser_StdType

COM Interfaces

As you can see, in VFP’s Object Browser the interface called “PICTURE” is VFP’s default interface that is returned each time we are using some command like:

oPicture = LOADPICTURE(GETPIC())
ObjectBrowser_TLB

The oPicture reference above is a COM object reference of an interface named “Picture” through which we can access our image’s properties and methods.

Let VFP’s IntelliSense help us and type opicture. into the command window after we created a picture instance like shown above. IntelliSense shows us a list of five properties and one method accessible through this primary interface. BTW: The same popup can be shown within your debugger:

IntelliDebugger

This Picture interface is suitable in cases where we only want to pass a COM object reference to another ActiveX control, or we want to display the image using VFP’s own native image class like this:

_Screen.AddObject("oImage","IMAGE")
oPicture = LOADPICTURE(GETPIC())
_SCREEN.oImage.PictureVal = m.oPicture
_SCREEN.oImage.Visible = .T.

However, if we try to use the COM object’s render() method directly, bypassing the use of VFP’s  Image object, we will only receive an OLE error complaining about non-optional parameters.

OleErrorDialog

Without any further investigations, we are stuck at this point!

By The Way 1,2,3

  1. There is a BUG in the VFP online documentation for the image object’s PictureVal property! Actual writing reads: “If eExpression is an object, the object must be in an IPicture interface format. The IPicture interface format is the same format returned by the LOADPICTURE( ) Function. This is wrong! It should be “If eExpression is an object, the object must implement one of the following interfaces: “Picture” OR “iPicture”, which both _*do*_ work! The Picture interface is the same returned by VFP’s LOADPICTURE() function. If you need the iPicture-interface, you can retrieve it by the help of VFP’s GETINTERFACE() function.
  2. VFP’s SAVEPICTURE() function is nothing more than a wrapper around the SaveAsFile() function of the COM picture object (accessible by VFP through the iPicture interface)!
  3. You can read one sentence in VFP’s online help about the LOADPICTURE() function: „If cFileName is omitted, the null picture is returned“. This sounds Greek. However, as you can read OffSiteLink here, it is nothing more than a parameterization option defined in the OleCreatePictureIndirect() function of the underlying Windows API. The NULL-Picture-Object is nothing else, but an uninitialized object which can initialize itself through the Load() method of its IPersistStream interface. Got it? No? Do not hesitate – nothing we have to deal with (in the next future:-)

To make a long story short

… Let me show you how to get the darn thing work. As you should have guessed, we must not use the Picture interface that we get back using the LOADPICTURE() function, but the other (hidden) interface: IPicture is the right one to use! And this is how to get the right COM-Object reference:

oPicture = LOADPICTURE(GETPIC())
oIPicture = GETINTERFACE(oPicture, “iPicture”)

Typing in the first line in VFP’s command window, you will get some similar GETPIC() dialogue like below:

OpenPicture Dialog

I have a little image on my disk called “tree.jpg” – a 100 x 100 pixels JPEG file that I will use during this walkthrough. Now, if we are using VFP’s Intellisense on oIPicture it shows us a longer list of properties and methods (see Object Browser screen shot below). The biggest point is that we now can use our COM object’s render() method directly!

ObjectBrowser_Interfaces

 

The COM Object’s Render() Method

This is how the render() method’s signature reads in VFP’s Object Browser followed by a short description of each parameter:

IntelliRender

Render(hdc As Integer, x As Long, y As Long, cx As Long, cy As Long, xSrc As Long, ySrc As Long, cxSrc As Long, cySrc As Long, lprcWBounds As Void) As H Result

[target] hdc := the device context handle (a pointer to something like a canvas)
There are two Windows API functions to retrieve a handle to an existing device context: GetDC() and GetWindowDC().

[target] x:= left-property of output-rectangle (top left corner’s X-coordinate)

[target] y:= top-property of output-rectangle (top left corner’s Y-coordinate)

[target] cx:= width-property of output-rectangle (the width of output)

[target] cy:= height-property of output-rectangle (the height of output)

Up to this point all coordinates are measured in pixel (we VFP developers are used to use) and could be mapped
to LEFT, TOP, WIDTH and HEIGHT properties of an imaginary VFP image object.

[source] xSrc:= X-offset into image source (from where column-copy starts)

[source] ySrc:= Y-offset into image source (from where line-copy starts)

[source] cxSrc:= Width of each line to copy (#no of columns)

[source] cySrc:= Height of each column to copy (#no of lines)

HiMetric

To make things a little bit more “interesting” one have decided to use HiMetric units for some of the COM object’s properties (those dealing with the image source dimensions). That is why a 100x100 pixels image loaded from disk ends up in our internal COM in-memory representation having 2646 x 2646 units!

Coordinates

“HiMetric” scaling must have been not difficult enough for some of them, someone decided to move the coordinate-origin (0, 0-point) from the top-left corner of the COM-Image source to the lower-left corner (maybe to spice things up ;-)

Some manual testing

Let’s have a look at my original source image:

Testbild

Let us now assume, that we already have a valid handle to a device context to render our image on. The following call to render()

WITH oIPic
   = .Render(m.hDC, 0, 0, 100, 100, 0, 0, .Width, .Height, NULL)
ENDWITH

would then produce the following output:

ComTestbild

The origin of the COM coordinate system is somehow rotated in memory by 180° After some wild guesses one may find out that the following code produces the expected output:

WITH oIPic
   = .Render(m.hDC ,;
             0,    0   ,   100 ,   100     ,;
             0, .Height, .Width, .Height*-1,;
             NULL)
ENDWITH

We have to understand what’s going on internally to see things a little bit clearer! The image loaded into memory is nothing more than a memory block filled with pixel related color values. This memory block can be abstractly treated as a rectangle. During rendering, which internally is the process of transferring data from the source rectangle to the destination rectangle, our COM object uses different values which are passed in through parameter #6 to #9 (the [source] parameters) to control the process:

  1. The origin of the source rectangle, one could name “copy starting point”.
  2. The width and the height of the source rectangle to support cases when we do not want to render out a source image completely!
  3. The direction in which to “read-out” the source data (bytes).

It is important to know, that the very first source pixel (the one that is the origin of the source rectangle) always gets rendered out at position 1,1 of the target rectangle. The second source pixel (what exact pixel will be copied next depends on the read-out direction) gets renders out at position 2,1 and so on. Thus, by selecting the appropriate origin to start from, it is possible to render a mirrored image into the destination device context.

The xSrc und ySrc Parameter

The 6th and 7th parameter value of the render() function determine where the starting point of the copy process within the image source lays. One of the 4 corners of the source rectangle will become the origin. Below, we can see the memory based COM – image with a given source rectangle (the red frame). In this case the source rectangle’s size matches the whole image. The coordinate pairs of all four valid xSrc/ySrc – combinations are also depicted. The values shown reflect HiMetric scaling (a 100x100 pixels square on a 96 dpi device context)

Nullpunkte

Through determining the origin of where to start reading out the source pixel values, we also determine the direction of read out indirectly! The direction of read out is established by the sign of the last two input parameters (cxSrc and cySrc) of the render() method. (Don’t be surprised, just take it as read :-)

The cxSrc und cySrc Parameter

On the one hand, the 8th und 9th parameter determine width and height of the source rectangle, on the other hand they also determine the read direction during the rendering data transfer. The absolute values  ABS(cxSrc) and ABS(cySrc) define the width and height of the source rectangle, the sign of both values (+/-) the direction of read out. The picture below might help to shed some light on that: 

Ausleserichtung

The [source] coordinate parameters of the oIPic.Render() call (see above) tell us: “Position the ‘copy from – origin’ at x = 0, y=2646 (see 2nd pic from the left within the image just above) and start the line-wise transfer from there. Each transferred line in –> x direction with a pixel-width defined by ABS(HiMetric-Units) of the cxSrc parameter. Proceed with next line in -y direction. Loop until as much pixel lines were transferred as defined in ABS(HiMetric-Units) of the cySrc parameter. Now, we are able to mirror any image during rendering along both axis:

Spiegelungen

Solving the Hourglass Problem

There is another weird VFP behavior most of us already encountered in the past: the “hourglass problem”! Sometimes, we want VFP to refresh some form content which results in a cascading refresh. Controls that have to be refreshed sometimes have images assigned to their .Picture properties. Such image references always point to a file on the disk (or the app/exe which makes no difference). In other words, VFP has to access the disk in one way or another. If these disk accesses last more than a few milliseconds, then the operating system changes the mouse cursor to an hourglass! And sometimes VFP isn’t aware of that change. As long as the user doesn’t touch the mouse, VFP doesn’t refresh (reset) the mouse cursor symbol. Thus, for the user it seems like VFP still is busy. With the help of VFP’s LOADPICTURE() function (and the newly introduced .PictureVal property) it is now possible to avoid a wrong hourglass cursor display. Using code like the following one

_Screen.AddObject("oImage","IMAGE") 
oPicture = LOADPICTURE(GETPIC()) 
_SCREEN.oImage.PictureVal = m.oPicture 
_SCREEN.oImage.Visible = .T.

never ever again will display the wrong hourglass mouse cursor, because there no longer is any disk access! Before you now shout: “That’s COOL!”, read on; there is a severe drawback caused by a VFP bug!

Solving the PictureVal Bug

This is a short excerpt taken from one of my elder VFP projects. First, the INIT() of one of my VFP Image classes is the place where I load the COM-Images

LOCAL lcPicture AS String
WITH THIS
   IF .EnableMultiStatePictures
	*\\ reassure we have pictures to display 
	lcPicture = JUSTFNAME(.Picture)
	IF EMPTY(.PictureEnabled)
		.PictureEnabled = m.lcPicture
	ENDIF
	IF EMPTY(.PictureDisabled)
		.PictureDisabled = m.lcPicture
	ENDIF
	IF EMPTY(.PictureMouseOver)
		.PictureMouseOver = m.lcPicture
	ENDIF
	IF EMPTY(.PicturePressed)
		.PicturePressed = .PictureMouseOver
	ENDIF
	IF EMPTY(.PictureSelected)
		.PictureSelected = .PicturePressed
	ENDIF
	*\\ set basic state
	.ImageState = IIF(.Enabled, 1, 0)
	*//
   ENDIF
   IF .EnableComPictureHandling
	*\\ The reason for using COM instances of JPG-images in conjunction with Image.PictureVal properties
	*\\	is, that we no longer have disk access. Thus, the hourglas mouse cursor never appears when
	*\\	clicking or hovering in/out on an image (refreshing it). BUT we have to be very carefully NOT
	*\\	to assign the same COM interface to THIS.PictureVal _twice_in_a_row!!! Doing so, will result in
	*\\	VFP looses the COM-reference to that picture object randomly. For more details see
	*\\	THIS._old_oPictureDisabled_Access() method.
	.PictureEnabled = LOADPICTURE(LOCFILE(JUSTSTEM(.PictureEnabled),JUSTEXT(.PictureEnabled),"Locate image"))
	.PictureDisabled = LOADPICTURE(LOCFILE(JUSTSTEM(.PictureDisabled),JUSTEXT(.PictureDisabled),"Locate image"))
	.PictureMouseOver = LOADPICTURE(LOCFILE(JUSTSTEM(.PictureMouseOver),JUSTEXT(.PictureMouseOver),"Locate image"))
	.PicturePressed = LOADPICTURE(LOCFILE(JUSTSTEM(.PicturePressed),JUSTEXT(.PicturePressed),"Locate image"))
	.PictureSelected = LOADPICTURE(LOCFILE(JUSTSTEM(.PictureSelected),JUSTEXT(.PictureSelected),"Locate image"))
   ENDIF
ENDWITH

This is the content of the _old_oPictureDisabled_Access() method:

*\\	It took me hours to find out what was going wrong! 
*\\	These are my findings:
*\\	Assigning an interface reference of a COM-ImageObject 
*\\	(created using VFP's LOADPICTURE() function) to 
*\\	This.PictureVal property will work properly as long as 
*\\	you do not *reassign* the same reference to .PictureVal again!!
*\\	Reassignment may work many times flawlessly, but (and that's for sure!) 
*\\	eventually VFP looses its internal COM reference completely 
*\\	after a reassignment! Apart from the fact that reassignments
*\\	aren't necessary at all (coz the picture already is shown), 
*\\	they might occur, especially if one had coded COM-image reference 
*\\	assignments to .PictureVal properties all over the place generously 
*\\	without knowing about this issue!
*//
*\\ My solution now is to use a new integer property <.ImageState> 
*\\ that may hold one of the following values: 0=Disabled; 1=Enabled; 
*\\ 2=MouseOver; 4=Pressed; 8=Selected (a bit field). This property tells 
*\\ me exactly which COM-ImageObject reference is assigned to 
*\\ the .PictureVal property at any moment. In all places where I 
*\\ have to assign another COM-Image reference, I carefully test 
*\\ against the <.ImageState> property value before assigning the 
*\\ new reference to eliminate reassignments completely!

The bottom line is: THIS IS A VFP BUG!
But, luckily, a solution (a workaround) is pretty easy to implement. In fact, it may even help to speed up your executable/application.
I have to stress it here once more: The buggy behavior does only appear if one is reassigning the same COM interface reference to an image-object’s PictureVal property more than once in a row!

The the first loop of following code works flawlessly: 

LOCAL lnLoop AS Integer, oComPic1 AS olePic
oComPic1 = LOADPICTURE(GETFILE())
oComPic2 = LOADPICTURE(GETFILE())
TRY
	_Screen.Addobject("oImage","IMAGE")
CATCH
FINALLY
	_Screen.oImage.Visible = .T.
ENDTRY
FOR lnLoop = 1 to 100
	_Screen.oImage.PictureVal = m.oComPic1
	_Screen.oImage.PictureVal = m.oComPic2
NEXT 
*//
*\\ whereas the next loop will break somewhere down the road:
FOR lnLoop = 1 to 100
	_Screen.oImage.PictureVal = m.oComPic1
	_Screen.oImage.PictureVal = m.oComPic1
	_Screen.oImage.PictureVal = m.oComPic2
	_Screen.oImage.PictureVal = m.oComPic2
NEXT

You will receive the following error, leaving you with a superficially valid COM object!

1

Believe me, that’s no fun to debug! Trauriges Smiley

ToDOs

Now, we really have some work to do before displaying our COM images directly:

  • We have to get a device context handle
  • We have to get our current display resolution (DPI)
  • We have to know all about “dots per inch” and HiMetric units
  • We have to convert pixels to HiMetric units and vice versa (before we can use them)

The rest of this post is the content of my OffSiteLink VFPX Help file project contribution.

LOADPICTURE([cFileName])

Parameters

cFileName
Specifies the image file on disk for which an object is created. The following image types are supported:

Image Type Groups

Filename Extensions

bitmaps

.bmp, .jpg, .jpeg, .jpe, .jfif, .gif, .giff, .gfa

icons

.ico

windows metafiles

.wmf

windows enhanced metafiles

.emf

cursor

.cur

Table 1 Supported Image Types

The following restrictions (tested with VFP 9 SP2 and OlePro32.dll Version 6.0.6002.18005) exist:

Image Type Groups

Restrictions & Issues

bitmaps

Loading .tif and .png formats will cause an OLE error.

icons

Icons are allowed with sizes up to 128x128 and must not have more than 256 colors. Even if there is more than one icon stored in the icon file, always only the smallest icon gets displayed. The icon file may contain much more icons - even with more colors and larger sizes - as long as there is at least one that complies with the rules above, then no exception is thrown.

cursor

Cursor files must not have more than 1K of file size, otherwise an OLE error is generated. Cursor files containing 16 color cursors can be loaded flawlessly, but only monochrome output is supported. Loading an animated cursor (.ani) causes an OLE error to be raised.

Table 2 Known Limitations

Null Picture Support

If cFileName is omitted, an uninitialized “null picture” object is returned.

You can include GETPICT( ) as cFileName to display the Open dialog from which you can choose a bitmap file.

Return Value

VFP’s LOADPICTURE() function returns a Picture type COM object reference that can be assigned to ActiveX controls and VFP’s Image object’s PictureVal property. However, the real primary interface iPicture only can be retrieved using code like this:

oIPicture = GETINTERFACE(LOADPICTURE(GETPICT()), "iPicture")

Remarks

Picture objects provide a language-neutral abstraction for bitmaps, icons, and metafiles. As with the standard font object, the system provides a standard implementation of the picture object. Its primary interfaces are iPicture and iPictureDisp. A picture object is created with OleCreatePictureIndirect and supports both the iPicture and the iPctureDisp interfaces. The OLE-provided picture object implements the complete semantics of the iPcture and iPictureDisp interfaces. In other words, there’s no need to use another interface than iPicture!

VFP’s LOADPICTURE() function internally wraps the OleCreatePictureIndirect() function implemented in OleAut32.dll. Thus, all you can read about that function (above and online) is also true for VFP’s LOADPICTURE() function. LOADPICTURE () was added to VFP’s vocabulary to make it easier to load images with COM interfaces that many presentation properties of ActiveX controls require for their settings. For example, the ActiveX Outline control has a PictureOpen property that requires a COM object image reference for its setting.

The COM object returned by VFP’s LOADPICTURE() function hides its primary interface iPicture. In contrast to the reference returnd by VFP’s LOADPICTURE(), the OLE-image’s primary iPicture interface is the only fully functional one. In other words, only iPicture can be used in VFP programms without generating any OLE errors. Because iPicture is a superset of Picture it may be, better, it should be used everywhere instead of the one returnd by LOADPICTURE() ! Example #1 in the examples section below proves that it makes no difference which OLE image interface gets assigned to a VFP oIMAGE.PICTUREVAL property.

The IID of the iPicture interface is defined as “{7BF80980-BF32-101A-8BBB-00AA00300CAB}”. Thus, the following two lines of code both create a null picture OLE image object:

oIPicture1 = GETINTERFACE(LOADPICTURE(GETPICT()), "iPicture")
oIPicture2 = CREATEOBJECTEX("StdPicture","","{7BF80980-BF32-101A-8BBB-00AA00300CAB}")


Interface Members

The following table summarizes the PEMs (with prefix P: = property, M: = method) of the iPicture interface. ‘Green’ PEMs are read/writable, all others are readonly.

PEM

Used for

ValueType

P: Attributes

The current set of the picture's bit attributes.

DWORD (int)

P: CurDC

The current device context into which this picture is selected.

HDC (long)

P: Handle

Handle to the picture managed within this picture object.

OLE_Handle (int)

P: Height

The current height of the picture in the picture object.

OLE_XSIZE_HIMETRIC (long)

P: hPal

The current palette of the picture (if any).

OLE_Handle (int)

P: KeepOriginalFormat

The current value of the picture object's KeepOriginalFormat property.

Bool

P: Type

The current type of the picture.

Short (int)

P: Width

The current width of the picture in the picture object.

OLE_XSIZE_HIMETRIC (long)

M: PictureChanged

Notifies the picture object that its picture resource changed.

 

M: Render

Draws the specified portion of the picture onto the specified device context, positioned at the specified location.

 

M: SaveAS File

Saves the picture's data into a stream in the same format that it would save itself into a file.

 

M: SelectPicture

Selects a bitmap picture into a given device context, returning the device context in which the picture was previously selected as well as the picture's handle.

 

Table 3 iPicture Interface Members

The Attributes property is said to hold the picture’s bit attributes. Actually, there are only two, which can be set alone, or additive. The following table lists both possible values:

Constant

Description

Value

PICTURE_SCALABLE

The picture object is scalable, such that it can be redrawn with a different size than was used to create the picture originally. Metafile-based pictures are considered scalable; icon and bitmap pictures, while they can be scaled, do not express this attribute because both involve bitmap stretching instead of true scaling.

1

PICTURE_TRANSPARENT

The picture object contains an image that has transparent areas, such that drawing the picture will not necessarily fill in all the spaces in the rectangle it occupies. Metafile and icon pictures have this attribute; bitmap pictures do not.

2

Table 4 PictureAttributes Enumeration

The following table lists all possible values of the iPicture.Type property:

Constant

Description

Value

PICTYPE_UNINITIALIZED

The picture object is currently uninitialized. This value will never be returned within VFP!

-1

PICTYPE_NONE

A new picture object is to be created without an initialized state. This value is returned from VFP if LoadPicture() is used without a parameter.

0

PICTYPE_BITMAP

The picture type is a bitmap.

1

PICTYPE_METAFILE

The picture type is a metafile.

2

PICTYPE_ICON

The picture type is an icon.

3

PICTYPE_ENHMETAFILE

The picture type is an enhanced metafile.

4

Table 5 Type Property Values

The most interesting method of the COM image object’s iPicture interface ist render() which also works flawlessly only when called on the iPicture interface. The following table summarises the parameters of the render() method:

Parameter

Used for

Scale Unit

hdc

A handle of the device context on which to render the image.

------

x

The horizontal coordinate in hdc at which to place the rendered image (X-position of upper left corner of output rectangle).

pixel

y

The vertical coordinate in hdc at which to place the rendered image (X-position of upper left corner of output rectangle).

pixel

cx

The horizontal dimension (width) of the destination rectangle (with of output rectangle).

pixel

cy

The vertical dimension (height) of the destination rectangle (height of output rectangle).

pixel

xSrc

The horizontal offset in the source picture from which to start copying.

HiMetric

ySrc

The vertical offset in the source picture from which to start copying.

HiMetric

cxSrc

The horizontal extent to copy from the source picture (width of image source’s clipping region AND direction of readout).

HiMetric

cySrc

The vertical extent to copy from the source picture (height of image source’s clipping region AND direction of readout).

HiMetric

lprcWBounds

If hdc is a metafile device context, the lprcWBounds parameter points to a RECTL structure specifying the bounding rectangle in the underlying metafile. The rectangle structure contains the window extent and window origin. These values are useful for drawing metafiles. The rectangle indicated by lprcBounds is nested inside this lprcWBounds rectangle; they are in the same coordinate space. If hdcDraw is not a metafile device context, lprcWBounds will be NULL. If hdcDraw is a metafile device context, lprcWBounds cannot be NULL!

------

Table 6 Render() Parameter Galore

The method returns standard values like E_FAIL, E_INVALIDARG and E_OUTOFMEMORY, as well as S_OK, E_POINTER and CTL_E_INVALIDPROPERTYVALUE. These values are described on OffSiteLink MSDN.

Applications

The render function has plenty of parameters. Some of them passing in pixel values, others HiMetric values. Example #3 has some useful conversions as well as other supporting functions and definitions. To figure out how render() works try the VFP code below; type it in line by line into VFP’s command window:

* locate an image with round about 100 x 100 pixels 
goPic = LOADPICTURE(GETPICT()) 
gIP = GETINTERFACE(m.goPic, "iPicture") 
goForm = CREATEOBJECT("Form") 
goForm.Show() 
* declare access to the _client_area_ of a window 
DECLARE Integer GetDC IN USER32 integer HWnd 
* hDC should be <> 0 (otherwise that's an error)! 
hDC = GetDC(goForm.HWnd) 
* render your image directly onto form's client area 
gIP.Render(m.hDC,0,0,100,100,0,gIP.Height,gIP.Width,- gIP.Height,NULL) 
* declare release function 
DECLARE Integer ReleaseDC IN USER32 integer HWnd, integer hDC 
* next line should print 1 on the form's background >> "Okay" 
? ReleaseDC(m.goForm.HWnd, m.hDC) 
* declare access to the _whole_ window 
DECLARE Integer GetWindowDC IN USER32 integer HWnd 
* hDC now references form's caption an border areas as well! 
hDC = GetWindowDC(goForm.HWnd) 
* render out partially overwriting form's border and caption 
gIP.Render(m.hDC,0,0,100,100,0,gIP.Height,gIP.Width,- gIP.Height,NULL) 
* never forget to free an allocated device context 
? ReleaseDC(m.goForm.HWnd, m.hDC)

Direct input into VFP’s command window

iPicture.Render() qualifies for painting on otherwise unreachable form regions, like titlebar or borders. Another interesting application for direct rendering stems from the fact that no VFP object reference is necessary for painting. The render() method solely uses a common windows handle. Thus, one can render on any known device context.

Drawback

iPicture.Render() does its work outside of - and unnoticed by – the VFP engine itself. That’s why VFP has no idea of what was painted “between the lines”. Each time VFP refreshes the form’s area (we’ve just rendered our picture onto), will clear out our image. To make rendered output persistent measures have to be taken against VFP wiping it out!

Examples

Example #1

The following example shows that both interfaces (Picture and IPicture) of a COM image instance can be assigned to VFP’s Image.PictureVal property:

PUBLIC goPic AS Object, goIPic AS Object
goPic = LOADPICTURE(GETPICT()) 
goIPic = GETINTERFACE(m.goPic, "iPicture") 
_SCREEN.AddObject("oPic1","IMAGE") 
_SCREEN.AddObject("oPic2","IMAGE") 
WITH _SCREEN.oPic1 
	.VISIBLE = .T.
	.PICTUREVAL = m.goPic && "Picture"-Interface 
ENDWITH
WITH _SCREEN.oPic2
	.LEFT = 110 
	.VISIBLE = .T.
	.PICTUREVAL = m.goIPic && "IPicture"-Interface
ENDWITH 
HIDE WINDOWS ALL 
WAIT WINDOW "Press any key..." 
_SCREEN.RemoveObject("oPic1") 
_SCREEN.RemoveObject("oPic2") 
STORE NULL TO goPic, goIPic 
CLEAR 
SHOW WINDOWS ALL 

Example #2

The following example shows how to query the iPicture interface of a COM image instance. Intentionally, there are no Try…Catch…Endtry sections in this demo code, so that OLE errors may occur. You have to run the code snippet multiple times with different image types to see them.

goPic = LOADPICTURE(GETPICT()) 
IF VARTYPE(m.goPic) == "O"
	goIPic = GETINTERFACE(m.goPic, "iPicture")
	IF VARTYPE(m.goIPic) == "O" 
		CLEAR && just some informal output: 
		WITH m.goIPic 
			? 
			? "Properties of 'IPicture'-Interface:" 
			? "Attributes" ,.Attributes 
			*\\ next line will fail if an ICOn loaded 
			? "CurDC" ,.CurDC 
			? "Handle" ,.Handle 
			? "Height" ,.Height 
			*\\ next line will fail if an ICOn loaded 
			? "hPal" ,.hPal 
			? "KeepOriginalFormat",.KeepOriginalFormat 
			? "Type" ,.Type 
			? "Width" ,.Width 
			? 
		ENDWITH 
	ENDIF 
ENDIF 

Example #3

The following code is a collection of supporting functions and declarations that come in handy while programming OLE image objects.

* Supporting Functions & DEFINEs
#DEFINE INCH2MILLIMETER 25.4 && 1 Inch = 25.4 millimeters
#DEFINE INCH2HIMETRICS (INCH2MILLIMETER * 100) && 1 HIMETRIC = 0.01
FUNCTION PXL2HIME(tnPixel AS Integer) AS Integer
	* Pixel to HiMetric conversion
	LOCAL lnPixelsOnOneHiMetricUnit AS Integer
	lnPixelsOnOneHiMetricUnit = INCH2HIMETRICS / GetDPI()
RETURN ROUND(lnPixelsOnOneHiMetricUnit * m.tnPixel, 0)
ENDFUNC
FUNCTION HIME2PXL(tnHimetric AS Integer) AS Integer
	* HiMetric to Pixel conversion
	LOCAL lnPixelsOnOneHiMetricUnit AS Integer
	lnPixelsOnOneHiMetricUnit = INCH2HIMETRICS / GetDPI()
RETURN ROUND(m.tnHimetric / m.lnPixelsOnOneHiMetricUnit, 0)
ENDFUNC
FUNCTION GetDPI(tnHDC AS Integer) AS Integer
      * retrieve dots per inch resolution 
      * for VFP's _SCREEN device context
	DECLARE Integer GetDeviceCaps IN GDI32 integer hdc, integer nIndex
	DECLARE Integer GetWindowDC IN USER32 integer HWnd
	DECLARE Integer ReleaseDC IN USER32 integer HWnd, integer hDC
	* For simplicity, we assume X- and Y- dimensions 
      * using the same DPI resolution.
	#DEFINE LOGPIXELSX 88 && Logical pixels/inch in X	
      #DEFINE LOGPIXELSY 90 && Logical pixels/inch in Y
	* Get VFP's _Screen-hDC to calculate resolution:
	LOCAL lhDC AS Integer, lnDPI AS Integer
	STORE 0 TO lhDC, lnDPI
	lhDC = GetWindowDC(_Screen.HWnd)
	IF NOT m.lhDC = 0
		lnDPI = GetDeviceCaps(m.lhDC, LOGPIXELSX)
	ELSE
		lnDPI = 96 && default to 96 DPI
	ENDIF
	* Free device context
	= ReleaseDC(_Screen.HWnd, m.lhDC)
RETURN m.lnDPI
ENDFUNC
FUNCTION GetCanvas(tnHWND AS Integer, tlChild AS Boolean) AS Integer
	* Retrieve hDC (handle DeviceContext) of window handle
	* tlChild = TRUE  := Use GetDC()
	* tlChild = FALSE := Use GetWindowDC()
	DECLARE Integer GetDC IN USER32 integer HWnd
	DECLARE Integer GetWindowDC IN USER32 integer HWnd
	LOCAL lnHDC AS Integer
	IF m.tlChild
		lnHDC = GetDC(m.tnHWND)
	ELSE
		lnHDC = GetWindowDC(m.tnHWND)
	ENDIF
RETURN m.lnHDC
ENDFUNC
FUNCTION ReleaseCanvas(tnHWND AS Integer, tnHDC AS Integer) AS Integer
	* Releases a borrowed hDC
	DECLARE Integer ReleaseDC IN USER32 integer HWnd, integer hDC
RETURN ReleaseDC(m.tnHWND, m.tnHDC)
ENDFUNC
* The following function is not bullet-proof, as it fails on forms with scrollbars ;
(oForm.Scrollbars > 0) See Example #4 for a working solution! FUNCTION GetChildAreaCanvas(tnhWnd AS Integer) AS Integer * VFP ‘TopLevelForms’ (oForm.ShowWindow = 2) have * a secondary window inside the outer one. * This is also true for forms showing scrollbars! LOCAL lnVfpHANDLE AS Integer, lnClienthWnd AS Integer, lnHDC AS Integer * Convert the given Windows hWnd to an internal VFP WHANDLE lnVfpHANDLE = SYS(2326, m.tnhWnd) * Retrieve the Windows hWnd for a client window * (WCLIENTWINDOW) of a specified Visual FoxPro parent window lnClienthWnd = SYS(2325, m.lnVfpHANDLE) * Check if there is a WCLIENTWINDOW IF lnClienthWnd = lnVfpHANDLE * No such WCLIENTWINDOW, return child’s client area lnHDC = GetCanvas(m.tnhWnd, .T.) ELSE * There IS a WCLIENTWINDOW! * Get the device context handle for the * whole client area of that window: lnHDC = GetCanvas(lnClienthWnd) ENDIF RETURN m.lnHDC ENDFUNC

Example #4

The following example demonstrates how to render an image on different types of forms. Copy the code to a PRG file, then compile and run it.

The first section of the program can be seen as a testing setup. You will be asked four times to select a picture from your local disk. Then, a form will be created and the chosen picture will be rendered inside it. The MyForm class definition holds all functionality. At the end of this listing there are three supporting subclasses of MyForm called MyScrollableForm, MyDockableForm, and MyTopLevelForm which gets instantiated to test all kinds of form types. You may want to run the demo several times while changing/varying the base form’s (MyForm) Scrollbars and MDIForm property values. In addition to that you may uncomment the DEBUGOUT lines in MyForm.HandleWinMsg1() and HandleWinMsg2() to watch WinMessages in your debugger. The method MyForm.ImageAttribs() is called at the end of MyForm.RetrievePicture() method. If you like to see additional information about the loaded image, uncomment the invocation there.

CLEAR
*** SET STEP ON 
RELEASE ALL LIKE goForm*
PUBLIC goForm1, goForm2, goForm3, goForm4
*//
*\\ Try rendering on a form in SCREEN
goForm1 = CREATEOBJECT("MyForm")	&& IN_SCREEN (MDIForm = .T.)
IF VARTYPE(m.goForm1) == "O"
	goForm1.Show()
	goForm1.Caption = "goForm1 => IN_SCREEN (MDIForm = .T.)"
	goForm1.Name = "goForm1"
ENDIF
*//
* SET STEP ON
*\\ Try rendering on a dockable form
goForm2 = CREATEOBJECT("MyDockableForm") && IN_SCREEN (dockable = 1)
IF VARTYPE(m.goForm2) == "O"
	goForm2.Show()
	goForm2.Caption = "goForm2 => IN_SCREEN (dockable = 1)"
	goForm2.Name = "goForm2"
ENDIF
*//
* SET STEP ON 
*\\ Try rendering on a TopLevelForm (TLF)
goForm3 = CREATEOBJECT("MyTopLevelForm") && AS_TOPLEVEL_FORM
IF VARTYPE(m.goForm3) == "O"
	goForm3.Show()
	goForm3.Caption = "goForm3 => AS_TOPLEVEL_FORM"
	goForm3.Name = "goForm3"
ENDIF
*//
* SET STEP ON 
*\\ Try rendering on a regular (child) form (with scrollbars)
goForm4 = CREATEOBJECT("MyScrollableForm") && IN_SCREEN (scrollbars = 3)
IF VARTYPE(m.goForm4) == "O"
	goForm4.Show()
	goForm4.Caption = "goForm4 => IN_SCREEN (scrollbars = 3)"
	goForm4.Name = "goForm4"
ENDIF
*//
RETURN && >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Bye, bye!

***********************************************************
*** SYS(602,0) && set off-screen bitmaps to "OFF"
*\\ 	setting of off-screen bitmaps may have some impact
*\\ 	but only, if one does not take care of all oddities.
*\\ 	!!!!! This demo program is side effect free !!!!!
*** SYS(602,1) && set off-screen bitmaps to "ON"
***********************************************************

DEFINE CLASS MyForm AS Form
	*\\ ----------------------------------
	AllowOutput = .F.	&& ? will be echoed on form while active
	ShowWindow = 0 	&& 0 := In Screen, 1 := In TLF, 2:= AS TLF
	Scrollbars = 0	&& 0 : = None, 1 := horizontal, 2:= vertical, 3 := both
	MDIForm = .T. 	&& .T. := form is a MDI form
	*\\ user defined ---------------------
	oPic = NULL		&& VFP's LOADPICTURE() COM object reference
	oIPic = NULL	&& promary iPicture interface reference
	cPicturePath = ""	&& full qualified DOS path to image
	lEventsBound = .F.&& flag
	nhDC = -1		&& device context to render the image on
	nHwnd = 0		&& window handle of rendering device context (.nhDC)
      *** HWnd = ....	&& thisform's native window handle which must not always
				&& be the window handle of the rendering device context!
	xDPI = 0		&& VFP's _SCREEN X-Resolution
	yDPI = 0		&& VFP's _SCREEN Y-Resolution
	iWindowProc1 = 0	&& Buffer 
	iWindowProc2 = 0	&& Buffer
	nWidth = 0		&& Ole-Image property: Image width (pixels)
	nHeight = 0		&&  dito : Image height (pixels)
	nTop = 0		&&  dito : Image top position (pixels)
	nLeft = 0		&&  dito : Image left position (pixels)
	nXOffset = 0	&&  dito : Horiz.Offset in source (where copying starts)
	nYOffset = 0	&&  dito : Vert.Offset in source (where copying starts)
	nCopyWidth = 0	&&  dito : Horiz.Extend to copy from + readout direction
	nCopyHeight = 0	&&  dito : Vert.Extend to copy from + readout direction
	*// ----------------------------------
	
	PROTECTED FUNCTION INIT() AS BOOLEAN
		*\\ call public implementation
		THIS.INITIALIZE()
		*// 
	RETURN .T. && always allow form to stay in memory
	ENDFUNC

	PROCEDURE INITIALIZE() AS VOID
		WITH THIS
			*\\
			.DeclareWinAPI()
			.RetrieveDPI()
			.RetrieveWinHandle()
			.RetrieveWinProcs()
			.RetrieveHandleDC()
			.RetrievePicture()
			.DoBind()
			*//
		ENDWITH
	ENDFUNC

	PROCEDURE PAINT() AS VOID
		*\\ common entry point to render our COM pictures
		THIS.RenderImages()
		*// Secondary entry points (even more important) see HandleWinMsg1 & 2
	ENDPROC

	PROTECTED PROCEDURE DESTROY() AS VOID
		WITH THIS
			.UnbindAll()
			.ResetAll()
			.ReleaseDeviceContext()
			*\\ release the public variable
			_SHELL = "RELEASE " + .Name
		ENDWITH
	ENDPROC

	PROTECTED PROCEDURE UnbindAll() AS VOID	
		UNBINDEVENTS(THIS)
		WITH THIS
			IF .lEventsBound
				*\\ restore form's message loop
				UNBINDEVENTS(.HWnd)
				UNBINDEVENTS(.nHWnd)
				*\\ .T. when BINDEVENT(hWnd,...) was successful
				.lEventsBound = .F.	
			ENDIF
		ENDWITH
	ENDPROC
	
	PROTECTED PROCEDURE ResetAll() AS VOID
		WITH THIS
			.oPic = NULL
			.oIPic = NULL
			.cPicturePath = ""
			.nHwnd = 0
			.xDPI = 0
			.yDPI = 0
			.iWindowProc1 = 0
			.iWindowProc2 = 0
			*\\ parameter for oIPic.Render()
			.nWidth = 0
			.nHeight = 0
			.nTop = 0
			.nLeft = 0
			.nXOffset = 0
			.nYOffset = 0
			.nCopyWidth = 0
			.nCopyHeight = 0
			*//
		ENDWITH
	ENDPROC
	
	PROTECTED PROCEDURE ReleaseDeviceContext() AS VOID
		*\\ Release .nHDC
		WITH THIS
			IF .nHDC <> 0 && handle of device context
				ReleaseDC(.nHWnd, .nHDC)
				.nHDC = 0
			ENDIF
		ENDWITH
	ENDPROC
	
	PROTECTED PROCEDURE DeclareWinAPI() AS VOID
	*\\ Register WINAPI declarations
	*\\ WIN32API: Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll, and Advapi32.dll
	    DECLARE INTEGER CallWindowProc	IN WIN32API INTEGER lpPrevWndFunc, INTEGER HWND,INTEGER Msg, INTEGER wParam, INTEGER LPARAM
	    DECLARE INTEGER GetDC 		IN WIN32API INTEGER HWND
	    DECLARE INTEGER GetDeviceCaps 	IN WIN32API INTEGER hDC, INTEGER nIndex
	    DECLARE INTEGER GetWindow		IN WIN32API INTEGER HWND, INTEGER wFlag
	    DECLARE INTEGER GetWindowDC	IN WIN32API INTEGER HWND
	    DECLARE INTEGER GetWindowLong	IN WIN32API INTEGER HWND, INTEGER nIndex
	    DECLARE INTEGER ReleaseDC		IN WIN32API INTEGER HWND, INTEGER hDC
	    *// some more unused (but useful) at the end of this listing
	ENDPROC

	PROTECTED PROCEDURE RetrieveDPI() AS VOID
	*\\ calculate X/Y _screen resolutions
	*\\ retrieves dots per inch resolution for VFP's _SCREEN device context
		#DEFINE LOGPIXELSX 88 && Logical pixels/inch in X
		#DEFINE LOGPIXELSY 90 && Logical pixels/inch in Y
		*//				
		LOCAL lhDC AS Integer, lnDPI AS Integer
		lhDC = GetWindowDC(_Screen.HWnd)
		IF m.lhDC <> 0
			THIS.xDPI = GetDeviceCaps(m.lhDC, LOGPIXELSX)
			THIS.yDPI = GetDeviceCaps(m.lhDC, LOGPIXELSY)
			= ReleaseDC(_Screen.HWnd, m.lhDC)
		ELSE
			*\\ fallback defaults
			STORE 96 TO ._xDPI, ._yDPI
		ENDIF
	ENDPROC

	PROTECTED PROCEDURE RetrieveWinHandle() AS VOID
		#DEFINE GW_CHILD 5
		WITH THIS
			*\\ default: THISFOEM.HWnd
			.nHWnd = .hWnd
			*//
			*\\ handle different scenarios:
			DO CASE
				CASE .Dockable > 0
					*\\ dockable forms do not have any child windows
				CASE .ShowWindow = 2
					*\\ If the parent form is a TopLevelForm then
					*\\	there must be another child window, thus
					*\\	drill down to get inner-most child
					.nhWnd = GetWindow(.nHWnd, GW_CHILD)
					*\\ TopLevelWindow with additional scroll bars
					IF .Scrollbars > 0
						*\\IF there are scrollbars enabled, there is 
						*\\an additional view port window. Thus,
						*\\drill down and get this window's handle
						.nhWnd = GetWindow(.nHWnd, GW_CHILD)
						*//
					ENDIF
				CASE .Scrollbars > 0
					*\\ Regular VFP form with scroll bars enabled
					.nhWnd = GetWindow(.nHWnd, GW_CHILD)
			ENDCASE
		ENDWITH
	ENDPROC

	PROTECTED PROCEDURE RetrieveWinProcs() AS VOID
		#DEFINE GWL_WNDPROC		(-4)
		*\\ retrieves the WIN Message handler ID for a given window 
		*\\ 	which defaults to THISFORM
		WITH THIS
			THIS.iWindowProc1 = GetWindowLong(.Hwnd, GWL_WNDPROC)
			THIS.iWindowProc2 = GetWindowLong(.nHwnd, GWL_WNDPROC)
		ENDWITH
		*//
	ENDPROC

	PROTECTED PROCEDURE RetrieveHandleDC(tlAll AS Boolean) AS VOID
		WITH THIS
			*\\ force parameter default to boolean FALSE
			IF NOT VARTYPE(m.tlAll) == "L"
				tlAll = .F.
			ENDIF
			*//
			IF m.tlAll
				*\\ the full window device context
				.nHDC = GetWindowDC(.nHwnd)
			ELSE
				*\\ the child area device context
				.nHDC = GetDC(.nHwnd)
			ENDIF
		ENDWITH
	ENDFUNC

	PROCEDURE RetrievePicture(tcFileName AS String) AS VOID
		*\\ Load picture from disk.
		*\\ Initializes .oPIC and .oIPIC
		IF (NOT VARTYPE(m.tcFileName) == "C")
			tcFileName = ""
		ELSE
			tcFileName = ALLTRIM(UPPER(m.tcFileName))
		ENDIF
		IF EMPTY(m.tcFileName)
			*\\ prompt user
			m.tcFileName = GETPICT("windows bitmap files:bmp;"+;
							"windows icon files:ico;"+;
							"run-length encoded files:rle;"+;
							"metafiles:wmf;"+;
							"enhanced metafiles:emf;"+;
							"JPEG files:jpg,jpeg",;
							"Render from file:", "Load" )
		ENDIF
		*\\ load the picture
		TRY
			loPic = LOADPICTURE(IIF(EMPTY(m.tcFileName), THIS.cPicturePath, m.tcFileName))
		CATCH
			loPic = NULL
		ENDTRY
		*//
		IF VARTYPE(m.loPic) == "O"
			WITH THIS
				*\\ save VFP's COM ref.
				.oPic = m.loPic
				*\\ save pimary COM pic ref
				.oIPic = GETINTERFACE(m.loPic, "IPicture")
				*//
				*\\ calculate pixel based width and height
				.nWidth = .HIME2PXL(.oIPic.Width, "X")
				.nHeight = .HIME2PXL(.oIPic.Height, "Y")
				.nTop = 0
				.nLeft = 0
				*//
				*\\ Next section positions a 1x1 pixel line object on the form
				*\\ at lower right corner of the rendered image. Scrollbars
				*\\ will appear if form is smaller than the picture loaded
				IF .Scrollbars > 0
					*\\ Make the scrollbars appear if secessary
					IF (.nWidth + .nLeft > .WIDTH) AND BITTEST(.Scrollbars, 0) OR ;
						(.nHeight + .nTop > .HEIGHT) AND BITTEST(.Scrollbars, 1)
						IF NOT PEMSTATUS(this,"_oPixel",5) 
							.AddObject("_oPixel","LINE")
							._oPixel.top = .nHeight + .nTop
							._oPixel.left = .nWidth + .nLeft
							._oPixel.DrawMode = 11 && NOP: In effect, this setting turns drawing off
							._oPixel.Visible = .T. && Must be set visible! Due to .DrawMode it is not rendered!
						ENDIF
					ENDIF
					*//
				ENDIF
				*//
				*\\ Want to echo some of the extended COM attributes?
				*\\	Uncomment next line (will echo to VFP's desktop)
				*** .ImageAttribs()
				*//
				*\\ finally render new image the 1st time
				.RenderImages()
				*//
			ENDWITH
		ENDIF
	ENDPROC

	PROTECTED PROCEDURE DoBind() AS VOID
		#DEFINE WM_ERASEBKGND	0x0014
		*\\ Bind to WIN-Messages
		WITH THIS
			*\\ the regular case: simple VFP form IN SCREEN
			BINDEVENT(.nhWnd, WM_ERASEBKGND, THIS, "HandleWinMsg2", 4)
			*//
			*\\ TopLevel form -or- simple form with scrollbars -or-
			*\\		a combination of both
			IF .ShowWindow = 2
				*\\ Some VFP forms receive "erase_background" message
				*\\		at their "outer" window
				BINDEVENT(.hWnd, WM_ERASEBKGND, THIS, "HandleWinMsg1", 4)
				*//
			ENDIF
			.lEventsBound = .T.
		ENDWITH
	ENDPROC

	FUNCTION HandleWinMsg1(tnHWnd AS INTEGER, tnMsg AS INTEGER, tnWPARAM AS INTEGER, tnLPARAM AS INTEGER) AS Integer
		**** DEBUGOUT "HandleWinMsg1 - WM_ERASEBKGND WPARAM = " + TRANSFORM(m.tnWPARAM) + " | LPARAM = "+ TRANSFORM(m.tnLPARAM)
		*//
		*\\ 1st Windows Message handler (either bound to outer TLF window or
		*\\		to the 'one & only' window handle >>> thisform.hwnd)
		LOCAL nRetvalue
		*\\ This routine gets called on Windows "EraseBackground" messages. 
		*\\	Thus, first forward the message (which will wipe out the background)...
		nRetvalue = CallWindowProc(THIS.iWindowProc1, m.tnHWnd, m.tnMsg, m.tnWPARAM, m.tnLPARAM)
		*\\ ... and finally, render our image(s) again
		THIS.RenderImages()
		*//
	RETURN m.nRetvalue
	ENDFUNC

	FUNCTION HandleWinMsg2(tnHWnd AS INTEGER, tnMsg AS INTEGER, tnWPARAM AS INTEGER, tnLPARAM AS INTEGER) AS Integer
		*** DEBUGOUT "HandleWinMsg2 - WM_ERASEBKGND WPARAM = " + TRANSFORM(m.tnWPARAM) + " | LPARAM = "+ TRANSFORM(m.tnLPARAM)
		*//
		*\\ 2nd Windows Message handler (bound to any inner window, if such one exists)
		LOCAL nRetvalue
		nRetvalue = CallWindowProc(THIS.iWindowProc2, m.tnHWnd, m.tnMsg, m.tnWPARAM, m.tnLPARAM)
		THIS.RenderImages()
		*//
	RETURN m.nRetvalue
	ENDFUNC
	
	PROTECTED PROCEDURE RenderImages() AS VOID
			*\\ output loaded COM image (4 times to demonstrate FXs)
		WITH THIS
			*\\ errors may rise during INIT() and DESTROY()
			*\\	it makes not much sense to catch them separately.
			*\\ Thus, just wrap all rendering with TRY...CATCH here
			TRY
				*\\ render the loaded picture 4 times:
				*\\ 1st: upper left one >>> normal output
				.oIPic.Render(.nhDC, 0, 0, .nWidth, .nHeight, 0,;
					.oIPic.Height, .oIPic.Width, - .oIPic.Height, NULL)
				*//
				*\\ 2nd: upper right one >>> mirrored vertically
				.oIPic.Render(.nhDC, .nWidth+10, 0, .nWidth, .nHeight, .oIPic.Width,;
					.oIPic.Height, - .oIPic.Width, - .oIPic.Height, NULL)
				*//
				*\\ lower left one >>> mirrored horizontally
				.oIPic.Render(.nhDC, 0, .nHeight+10, .nWidth, .nHeight,;
					0, 0, .oIPic.Width, .oIPic.Height, NULL)
				*//
				*\\ lower right one >>> mirrored horizontally + vertically
				.oIPic.Render(.nhDC, .nWidth+10, .nHeight+10, .nWidth, .nHeight, .oIPic.Width, 0,;
					- .oIPic.Width, .oIPic.Height, NULL)
				*//
			CATCH
				*\\ eat all rendering errors
			ENDTRY
			*//
		ENDWITH
	ENDPROC	
			
	PROCEDURE ImageAttribs() AS VOID
		*\\ only for testing
		WITH THIS
			IF VARTYPE(.oIPic) == "O"
				*\\ Output some interesting(?) things
				WITH .oIPic
					?
					? "Eigenschaften des 'IPicture'-Interface:"
					? "Attributes",.Attributes
					TRY
						? "CurDC",.CurDC
					CATCH
						? "No CurDC" && .ICO file
					ENDTRY
					? "Handle",.Handle
					? "Height",.Height
					TRY
						? "hPal",.hPal
					CATCH
						? "No hPal"
					ENDTRY
					? "KeepOriginalFormat" ,.KeepOriginalFormat
					? "Type"			,.Type
					? "Width"			,.Width
					?
				ENDWITH
				*//
			ENDIF
		ENDWITH
	ENDPROC
		
	#DEFINE INCH2MILLIMETER 25.4 && 1 Inch (German: 'Zoll') = 25.4 millimeters
	#DEFINE INCH2HIMETRICS (INCH2MILLIMETER * 100) && 1 HIMETRIC = 0.01 
	
	FUNCTION PXL2HIME(tnPixel AS Integer, tcDimension AS Character ) AS Integer
		LOCAL lnPixelsOnOneHiMetricUnit AS Integer
		lnPixelsOnOneHiMetricUnit = INCH2HIMETRICS / IIF(m.tcDimension== "X", THIS.xDPI,THIS.yDPI)
		*\\
		RETURN ROUND(lnPixelsOnOneHiMetricUnit * m.tnPixel, 0)
		*//
	ENDFUNC
	
	FUNCTION HIME2PXL(tnHimetric AS Integer, tcDimension AS Character ) AS Integer
		LOCAL lnPixelsOnOneHiMetricUnit AS Integer
		lnPixelsOnOneHiMetricUnit = INCH2HIMETRICS / IIF(m.tcDimension== "X", THIS.xDPI,THIS.yDPI)
		*\\
		RETURN ROUND(m.tnHimetric / m.lnPixelsOnOneHiMetricUnit, 0)
		*//
	ENDFUNC
	
	FUNCTION buf2dword(m.tcBuffer AS String) AS Integer
	RETURN CTOBIN(m.tcBuffer, "4rs")
	ENDFUNC
	*//
ENDDEFINE

DEFINE CLASS MyDockableForm AS MyForm
	Dockable = 1
	MDIForm	= .F.
ENDDEFINE

DEFINE CLASS MyScrollableForm AS MyForm
	Scrollbars = 3
	MDIForm	= .F.
ENDDEFINE

DEFINE CLASS MyTopLevelForm AS MyForm
	ShowWindow = 2
	MDIForm	= .F.
ENDDEFINE

*\\ unused defines and other useful declarations
*** #define WM_USER		 0x0400
*** #define WM_KILLFOCUS 0x0008
*** #define WM_PAINT	 0x000F

*\\ Unused, but useful WIN32API DECLAEs
* DECLARE INTEGER IsWindowVisible	IN WIN32API INTEGER HWND
* DECLARE INTEGER DefWindowProc		IN WIN32API INTEGER HWND, INTEGER Msg,INTEGER wParam, INTEGER LPARAM
* DECLARE INTEGER FindWindowEx		IN WIN32API INTEGER hWndParent, INTEGER hwndChildAfter, STRING lpszClass, STRING lpszWindow
* DECLARE INTEGER GetClassName		IN WIN32API INTEGER HWND, STRING lpClassName, INTEGER nMaxCount
* DECLARE INTEGER GetDesktopWindow	IN WIN32API
* DECLARE INTEGER GetWindowRect		IN WIN32API INTEGER HWND, STRING @lpRect
* DECLARE INTEGER GetWindowInfo		IN WIN32API INTEGER HWND, STRING @ pwindowinfo
* DECLARE INTEGER GetWindowText		IN WIN32API INTEGER HWND, STRING @szText, INTEGER nLen

 


Previous EntryTips & Tricks Home (TOC)Next Entry

6 comments:

  1. HI.
    i am loading a picture using the code
    lPicture=LOADPICTURE("FILENAME")

    as soon as when code hits this line..its popping up an error
    OLE ERROR:Unspecified error 1426.

    So,my suspect is when the object is created its popping an error its may be due to .dll if its .dll what is that the LOADPICTURE() function use.
    am trying it since a long time but couldn't figure out :( ..plz help me its very urgent.

    ReplyDelete
  2. @Jack19: Your input is pretty vague!

    LOADPICTURE() is a regular VFP command. Thus, you should not get any errors (especially no unspecific OLE error) under the following pre-conditions:


    1st.) Read VFP help thoroughly first, so that you are able to apply the function successfully (use correct parametrization)!
    2nd.) Pass in a valid (fully qualified) picture file name expression: one that evaluates/points to an existing image file that can be successfully processed by VFP.
    3rd.) Note that VFP evaluates the image file type by looking at the file extension. See above what file types are supported.
    4th.) The code you posted above > lPicture=LOADPICTURE("FILENAME") < will never work! You must write at least:
    lPicture=LOADPICTURE("FILENAME.BMP") if there really *is* a bitmap file called FILENAME.BMP in your VFP's search path.
    5th.) If you, against expectation, still encounter any dubious OLE errors, your picture file itself seems to be broken! To check it out replace your LOADPICTURE() code with the following (only during testing/debugging): lPicture=LOADPICTURE(GETPIC()) - this allows you to randomly select other images from your hard drive at runtime (maybe you want to wrap that line with TRY CATCH ENDTRY, just to not raise any more errors during testing).
    6th.) If you are not able to load _a_single_image_ without generation an OLE error (BTW: this should also be reproducible right from your VFP's command window, then) *then* and only then(!), you have to look at your OLEPRO32.DLL file(s)... And, sorry to say that, this clearly will be beyond the extend of my support.


    Anyway, I'm looking forward to hear from you if you successfully troubleshot the bug, or created an interesting workaround - good luck!

    ReplyDelete
  3. Thanks for the reply.

    Yes am loading a .bmp file i.e.

    lpicture=LOADPICTURE("filename.bmp")

    so the image isn't broken and we can open it fine from its folder where it is been saved and i thought in a direction that whether user has a full access permissions(because sometimes restricted access can cause 1426 OLE error code 0x80004005: Unspecified error)..yes he has full access but even though its been popping up.

    So,will there be any problem as soon as when the object reference is created by LOADPICTURE() or as user is pulling an from database or there will be any problem in outgoing ports.

    And if there is a problem in OLEPRO32.DLL what is it and what need to be taken care off.

    Waiting for your reply :)

    Thanks.

    ReplyDelete
  4. @Jack19: Please be more specific/verbose :-)
    What do you mean with "we can open it fine..." with what kind of program? Maybe MS-Paint, or from VFP's command windo, or what?

    Try this:
    run VFP in interactive mode: Execute LOADP() from VFP's command window. Does this work?
    If not: run your VFP application (I suppose its an EXE) or even your VFP-development environment with ADMIN privileges, then try again.
    Did you try to open another (!)DIFFERENT(!) bmp file from within your source code (at the same place/source code line)?
    Did you try out my earlier suggestions 5.) and 6.)

    Sorry, I have to stop this here and now. This neither is the right place, nor am I the right guy to give any kind of free VFP support :-) Feel free to visit some of the many VFP community sites out there to ask a galore of smart VFP guys for further help!

    After all, if you cannot solve your problem, drop me another comment containing your email address (I will not publish it) - maybe I will find some time to have a closer peek on your desaster :-)
    Good luck! I keep my fingers crossed for you!

    ReplyDelete
  5. What's up, this weekend is good designed for me, as this
    point in time i am reading this enormous educational paragraph here at my home.

    ReplyDelete
  6. Thanks for ones marvelous posting! I genuinely enjoyed reading it,
    you happen to be a great author.I will make certain to bookmark your blog and will
    often come back in the future. I want to encourage you to ultimately continue your
    great job, have a nice weekend!

    ReplyDelete