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 Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

need to link a file outside of a project created in foxpro

Status
Not open for further replies.

tanveerhabib

Programmer
Dec 8, 2015
27
PK
Hello all,

I need to link a file suppose client.dll which should be outside of the installed drive suppose my project is in E: drive and in folder newproject and want a file to be present suppose in C:/folder/ so how will i code it in foxpro?
 
I don't see a problem here. If a DLL is in another drive, you can still add it to a project and it'll be stored with its full path. It doesn't move with the project, so you have to manually care for it.

As a VFP developer you know how to work with data. If you need a flexible way, what hinders you to store the path to the DLL in some records of a config dbf?

DECLARE DLL can take a full path or work in current directory.

For the final deployment, you'll put the DLL side to side in the same folder as the EXEcutable, let an installer install it to whatever target directory you specify or let the user define it in the installation interview. It won't matter in what folder you are, you can always determine "here" with SYS(16). If the DLL is more complex and has some extra files for config or helper DLLs, you perhaps will redistribute it with a separate setup, then you need to determine or know the target folder.

Did I address your problem with any of this? If not, what other detail problem do you have? Do you think about linking the DLL, embedding it into the EXE? That's nothing VFP offers. DLLs are dynamically linked anyway, they are linked at runtime, not at design time or build. In a C compiler you may choose to link dynamically to a DLL or link a lib, but while VFP itself is a C application, it is not a C compiler nor has it a linker.

Bye, Olaf.
 
Maybe the core question you have is not about how to manage a file location outside of the project directory, but how to use a DLL at all.

Well, I already mentioned DECLARE, you have to know the functions defined in a DLL and the "function signature" the number and types of parameters it needs (the naming of parameters can differ, just the name of the function has to be exact including the case of the name).

DECLARE has a special clause WINAPI, where it will look for a certain function name in a set of OS core DLLs like kernel32.dll, but in general any DLL with functions can be dynamically linked to VFP via DECLARE definitions.

Let's see the principle for some DLL not part of the OS. Let's take a simple example only needing few declarations to start making use of the DLL: Visit and download the zlib compiled DLL from the section in the middle of this page starting with "The current release is publicly available here:". I don't copy the link here, as it's subject to change for future readers.

The download contains the main DLL zlib1.dll besides other things. The definition of the functions, zlib.h, can be found in the /include/ folder. I'm confident this will also be valid for future versions.

The three functions I'd like to demonstrate from the zlib1.dll are:
1. ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
2. ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int level));
3. ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));

The first is used to determine how much memory is needed to compress N bytes. You may assume the same number of bytes as the initial size would always be sufficient, but there will be a minimum and during compression maybe more bytes are needed, so you better determine that via this DLL function to not risc any undersized buffers. Sorry, that's more on the topic of the compression functionality than about how to DECLARE functions, but we now get straight to this:

The function definitions show what data types are needed and you need a little C knowledge to translate that to the data types usable for DECLARE. The first function is needing an unsigend long, well, we don't have that in VFP, but an INTEGER is good for any positive number up to 2^31. An unsigned long is needed both as output (return value type) and input parameter. So that declaration is quite simple:

Code:
CD C:\Downloads\zlib\ && change as needed
DECLARE INTEGER compressBound in zlib1.dll

The second function signature is harder to understand: An asterisk (*) always denotes a pointer to some memory block, in VFPs DECLARE you can either define that as INTEGER, which stands for a memory address, but it's easier to define that as a STRING@, a string passed by reference, which does nothing else but passing the strings memory address (in principle, I won't go into details). So note @ can be used for * parameters or pointers. The @ here is needed for the dest and destLen parameters. In the source parameter the @ is optional, as passing the uncompressed string to a DLL the VFP callhandler of DLL calls moves the input string to the DLL memory space anyway. As rule of thumb @ parameters are only needed, if you also get output, and in case of the dest that is the main output, the compressed block.

The third function is almost the same, just without a compression level parameter.

The final declaration and a sample usage here is:
Code:
CD C:\Downloads\zlib\ && change as needed
DECLARE INTEGER compressBound in zlib1.dll INTEGER sourceLen

DECLARE INTEGER compress2 in zlib1.dll ;
   STRING@ dest, INTEGER@ destLen, STRING@ source, INTEGER sourceLen, INTEGER level

DECLARE INTEGER uncompress in zlib1.dll ;
   STRING@ dest, INTEGER@ destLen, STRING@ source, INTEGER sourceLen

? 0,compressBound(0), compressBound(0)-0
? 1,compressBound(1), compressBound(1)-1
? 256,compressBound(256), compressBound(256)-256
? 1024,compressBound(1024), compressBound(1024)-1024 
? 1024*1024,compressBound(1024*1024), compressBound(1024*1024)-1024*1024
  
Local lcOriginal, lcUncompressed, lcCompressed, lnDestLen
lcOriginal = Replicate("a",1024*1024)
lcUncompressed = lcOriginal
lcCompressed = Space(compressBound(Len(lcUncompressed)))
lnDestLen = Len(lcCompressed)

lnError = compress2(@lcCompressed, @lnDestLen, lcUncompressed, Len(lcUncompressed),9)
? "Error (0=OK):",lnError
 lcCompressed = Left(lcCompressed,lnDestLen)

? "Compressed", Len(lcUncompressed), "bytes to", Len(lcCompressed),"bytes"

lnDestLen = Len(lcUncompressed)
lnError = uncompress(@lcUnCompressed, @lnDestLen, lcCompressed, Len(lcCompressed))
? "Error (0=OK):",lnError
? lnDestLen
? "Is uncomressed data equal to original data?",Iif(lcUncompressed==lcOriginal,"Yes","No")

A final word on the second DECLARE: What needs to be passed in as dest memory block address is the address of a string of that size, so you can't just pass in some address, VFP also has to have a variable of the given length to own this memory. You pass in a variable initialized to SPACE(len) for example, you could also use REPLICATE(chr(0),len), but it doesn't matter if that memory block is initialized with 0 bytes or spaces (byte value 32), the compress2 function overwrites this. The second immportant thing is, that the destLen parameter is both in/out. With the initial value you specify the length available to zlib1 for usage, when there is no error (lnError=0), the lnDestLen VFP variable becomes the size of the block really used to store the compressed data. We "truncate" the memory block in lcCompressed to that size via LEFT().

You are not needing to do low level memory management this way, but I mention and explain it in that detail, as it is a very common part of DLL function declarations and their usage, to pass in some memory address to empty memory or a structure of data. That is the part of this in regard of explaining DECLARE. There is more to say on this, but it isn't simple to get all DECLAREs for a DLL, you have to know function names and parameterizsations. There is no single SET DLL TO dllfile command, which does all declarations needed for you.

Without knowledge about the DLL, some reference like the zlib.h header file, which explains the DLL structure, functions, parameters and their meanings, you are lost anyway, because how would you use a DLL not knowing its functions? There is no automatic intellisense extension to tell you about the functions, their parameters and meanings, as the is no object like an OLE class would give you.

Aside of that the first part of the sample code shows zlib needs 13 bytes more than original data size with small blocks. When it comes to the MB size range it's 333 more bytes, so the compressBound() function really is useful to determine the initial buffer size for lcCompressed, my initial assumtion could have failed in case of data not compressible. The compression rate is very impressive in the test case, but a string of a MB of "a" is very redundant.

Bye, Olaf.
 
Yes you explained it correctly and when i changed the file location to suppose c:/windows/file.xxx

it worked as you said. Now one more question what if I want this file to be on a website location suppose abc.com/file.xxx

how can we add it to our project how can we set it in foxpro????
 
If you do a web application in VFP you'll create a webservice DLL and deploy it to the web, you won't use this from a client side with DECLARE, you'll use a soap client class and use the webservice via soap protocol via http requests. And such a solution has nothing to do with function library DLLs at all.

A sample walkthrough of that is Walkthrough: Creating XML Web Services with Visual FoxPro
I'd not recommend creating such type of webservice any more, this is outdated not only because the version of the soap toolkit coming with VFP is outdated.

This wold involve creating a COM server DLL and that would do the major work in an IIS webserver, but clients using it won't DECLARE that DLL or create an object of a class inside it, this will run on the webserver onoly and for a good reason: The output this DLL sends back via the webserver would for sure come from queries of data also server side. Even if you could create an object from the DLL local, you won't be able to use this, as it would be running on your client and won't have access to the server side DBFs.

If you use some webservice, you use it via web technology.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top