Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Visual Foxpro 9.0 OLE problems in Window 7

Status
Not open for further replies.

drmitchellkahn

Programmer
Jan 24, 2016
3
US
We have a complex data and document management system using VFP 9.0 tables where we embed documents (pdf, doc, tiff, etc) in general data fields using APPEND GENERAL and then to view the document

WITH THISFORM.oleboundcontrol1
.REFRESH()
.DOVERB(-2)
ENDWITH

This worked perfectly well for 10 years with Windows XP but as the old computers died we are forced to use Window 7 (I know we are up to Windows 10 but...) and now when we call that routine we get a popup window which with a Title "Create Package" and says "type the name of the file you want to package. If you prefer to search for the file, click "Browse". There is already a file embedded in the general field that is not linked. If I cancel I get "OLE error code 0x0004081: Verb number is valid but verb cannot be done now"

Any ideas on how to deal with this?
 
If you put data into a general field, you're bound to that computer. Not that literal, but you're bound to the OLE server used when storing the OLE object into the gen field, no matter how you use a gen field, also when appending into it from a file, what's embedded is an OLE object as usable by a certain OLE server. And OSes differ in what OLE classes/servers are preinstalled. There even are known problems with simple picture files because of MSPaint having changed from OS to OS.

You can only hope extracting the gen field portions of the fpt file will give you a usable file.

Bye, Olaf.
 
As a general rule, it is not a good idea to put the contents of pdf, doc, tiff, etc files into general data fields.

It is much better to put the files themselves (in their original format) into a Windows directory and then put the fully pathed filename into a data table field so that the VFP program can 'find' them and use them accordingly.

Good Luck,
JRB-Bldr



 
to OlafDoschke:

Any suggestion on how to programatically extract the documents from gen field? I have at least 100,000 documents embeded in gen fields.

Thanks

 
I fear you have no real chance without the old computers. You need to dig deep into the file structure of DBF and FPT, eg the memo, blob and gen fields all have a 4 byte pointer to an offset in the fpt file after it's header section and there you find a size. What the DBF offset means depends on how Blocksize was set when the dbf was created.

I can't knock out such code just like that.

dbf header explained here
memo file structure here:

Bye, Olaf.
 
Besides it should have been clear from the outset of general field usage you can't get your files back as they were, there is APPEND GENERAL {FROM FILE] command, but no opposite command like COPY GENERAL, so you don't have a pair of in/out operations as you have with APPEND MEMO and COPY MEMO. It's not forseen you get to the ole objects in other ways than via the olebound control using the OLE servers you have at the old XP machines.

Your best bet is to put up a virtual XP machine and try to get at the files from there, as you then at least have the ole servers, again.

Bye, Olaf.
 
Hi drmitchellkahn,

Your problem is difficult, but not unsolvable :)

Try this function to export a general data field into an external file:


Code:
FUNCTION fieldExport( tableAlias, fieldName, fileName )
	LOCAL dbfFileName
	LOCAL fptFileName
	LOCAL hfptFile
	LOCAL hFile
	LOCAL fileSize
	LOCAL fileBuffer
	LOCAL lenVal
	
	dbfFileName = ALLTRIM( FORCEEXT( fileName, "dbf" ) )
	fptFileName = ALLTRIM( FORCEEXT( fileName, "fpt" ) )
	
	IF FILE( dbfFileName )
		DELETE FILE( dbfFileName )
	ENDIF
	
	IF FILE( fptFileName )
		DELETE FILE( fptFileName )
	ENDIF
	
	IF FILE( fileName )
		DELETE FILE( fileName )
	ENDIF
	
	SELECT( tableAlias )
	
	IF EMPTY( &fieldName )
		RETURN .F.
	ENDIF
	
	COPY TO &dbfFileName FIELDS &fieldName NEXT 1
	
	SET COMPATIBLE DB4
	
	fileSize = FSIZE( fptFileName )
		
	SET COMPATIBLE FOXPLUS
	
	hFile = FCREATE( fileName )
	
	IF hFile = -1
		RETURN .F.
	ENDIF
	
	hFptFile = FOPEN( fptFileName )
	
	IF hFptFile = -1
		FCLOSE( hFile )
		
		RETURN .F.
	ENDIF
	
	fileBuffer = FREAD( hFptFile, fileSize )
	
	lenVal = LEN( fileBuffer )
	lenVal = lenVal - 599
	
	IF lenVal > 0
		fileBuffer = RIGHT( fileBuffer, lenVal )
		
		FWRITE( hFile, fileBuffer )
	ENDIF
	
	FCLOSE( hFptFile )
	FCLOSE( hFile )
	
	DELETE FILE( dbfFileName )
	DELETE FILE( fptFileName )
	
	RETURN .T.
ENDFUNC


This code works for me for years (with the default BLOCKSIZE of 64 Byte - but no idea if the BLOCKSIZE matters at all).

Parameters:

- tableAlias: alias of Your table (means: table already opened !!!), for example: "customers"
- fieldName: name of the general data field in Your table
- fileName: name of the created output file, for example: "C:\MyFolder\Test.doc" or "MyFolder\Test.doc" or only "Test.doc"

Regards, Stefan
 
Fine idea. You should perhaps explain the parameterisation a bit, eg the third parameter fileName is for a temp file you create to export a gen field, it should by all means not be the original dbf name, as your code deletes this file. Why do you let the user specify that name, you could simply take a random or constant name for this, eg SYS(2015) should not collide with any file name already existing.

You export one gen field to a new dbf, you cut off the fpt header by always reducing it by 599 bytes. The memo structure explains a header size of 512 plus 8 bytes after the header for a memo block header, so you cut off additional 79 bytes of the memo/gen field itself. For images that might relfect a thumbnail stored as start, but I don't see that working for pdf or other, I'd start with only cutting off 520 bytes.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top