contents   index   previous   next



blobDescriptor example

The Win32 API function GetOpenFileName is being used for this example. The syntax, in the Win32 API documentation, for this function is:

 

BOOL GetOpenFileName(LPOPENFILENAME lpofn);

 

The ScriptEase syntax for calling the Win32 API is:

 

SElib.dynamicLinkdynamicLink SElib.dynamicLink (library, procedure, convention

                  [, [desc,] param …])

 

The first three parameters in the ScriptEase syntax are standard for all calls to the Win32 API and are not discussed here. See SElib.dynamicLink() - for Win32 for a complete discussion. In the current section, we are only dealing a structure parameter since the lpofn parameter in the GetOpenFileName API function is a pointer to a structure. Other parameters, not discussed here, such as, integers and double words, are handled in a straightforward way.

 

An actual call to the GetOpenFileName function might look like the following:

 

var rtn;

rtn = SElib.dynamicLink("COMDLG32", "GetOpenFileNameA", STDCALL,

                        ofnDesc, ofn);

 

We are concerned with the parameters: ofnDesc and ofn. The original function only required one parameter, lpofn, but we are passing two parameters. (Remember that the first three parameters: library, procedure, and convention, are parameters for SElib.dynamicLink and that the parameters to API functions begin after the first three.) Why two parameters? Because ofn is a structure and ScriptEase requires a description of the structure. Hence, ofnDesc is a blobDescriptor object and ofn is a structure, and, in ScriptEase, a structure is considered a binary large object.

 

Lets look at the OpenFileName structure that is defined in the Win32 API and required by the GetOpenFileName function. The structure is defined as:

 

typedef struct tagOFN {// ofn  

    DWORD         lStructSize; 

    HWND          hwndOwner; 

    HINSTANCE     hInstance; 

    LPCTSTR       lpstrFilter; 

    LPTSTR        lpstrCustomFilter; 

    DWORD         nMaxCustFilter; 

    DWORD         nFilterIndex; 

    LPTSTR        lpstrFile; 

    DWORD         nMaxFile; 

    LPTSTR        lpstrFileTitle; 

    DWORD         nMaxFileTitle; 

    LPCTSTR       lpstrInitialDir; 

    LPCTSTR       lpstrTitle; 

    DWORD         Flags; 

    WORD          nFileOffset; 

    WORD          nFileExtension; 

    LPCTSTR       lpstrDefExt; 

    DWORD         lCustData; 

    LPOFNHOOKPROC lpfnHook; 

    LPCTSTR       lpTemplateName; 

} OPENFILENAME;

 

In ScriptEase, the blobDescriptor for the OpenFileName structure above could look like the following:

 

var ofnDesc = new blobDescriptor();

 

ofnDesc.lStructSize       = UWORD32;

ofnDesc.hwndOwner         = UWORD32;

ofnDesc.hInstance         = UWORD32;

ofnDesc.lpstrFilter       = UWORD32;

ofnDesc.lpstrCustomFilter = UWORD32;

ofnDesc.nMaxCustFilter    = UWORD32;

ofnDesc.nFilterIndex      = UWORD32;

ofnDesc.lpstrFile         = UWORD32;

ofnDesc.nMaxFile          = UWORD32;

ofnDesc.lpstrFileTitle    = UWORD32;

ofnDesc.nMaxFileTitle     = UWORD32;

ofnDesc.lpstrInitialDir   = UWORD32;

ofnDesc.lpstrTitle        = UWORD32;

ofnDesc.Flags             = UWORD32;

ofnDesc.nFileOffset       = UWORD16;

ofnDesc.nFileExtension    = UWORD16;

ofnDesc.lpstrDefExt       = UWORD32;

ofnDesc.lCustData         = UWORD32;

ofnDesc.lpfnHook          = UWORD32;

ofnDesc.lpTemplateName    = UWORD32;

 

As you can see, the ScriptEase blobDescriptor functions like a structure definition in another language and, specifically, like struct in C. The OpenFileName shown above is used with typedef for a struct, which might be a more useful comparison than just a structure definition. In any case, the similarity between structures and blobDescriptors is evident. Each property of the blobDescriptor object describes or determines how much memory is used by an element of a structure. For example, the first element of the Win32 API OpenFileName structure is lStructSize of type DWORD. In ScriptEase, the corresponding first property in ofnDesc is lStructSize and is defined as UWORD32. Both DWORD in the Win32 API and UWORD32 in ScriptEase designate 32 bits of memory to hold data. Thus, the memory requirements, for a structure, in the Win32 API and in ScriptEase are coordinated.

 

Notice that the original structure element name is lStructSize and the object property name lStructSize are the same. They did not need to be. The property names in a blobDescriptor object can be any names of your choosing. It is the size designations, such as, UWORD32, that are important. This blobDescriptor is the parameter desc in the syntax statement for SElib.dynamicLink().

 

Now we need to define the parameter param that is described. (Remember, desc is required only if the following param is a structure.) In our current example, ofn is the structure that is passed as param following the ofnDesc which is passed as desc. How might ofn be built since ScriptEase no longer has structure data types? Objects may be used as structures with object properties being equivalent to structure elements. So the following lines of code could be used:

 

#include "comdlg32.jsh"

#define MAXFILESIZE 65

 

var ofn = new Object();

   // Size of the ofn structure

ofn.lStructSize = Blob.size(ofnDesc);

 

   // Handle of owner, a ScriptEase screen in this example

ofn.hwndOwner = Screen.handle();

 

   // Set a buffer to pass and receive a filespec

var fileSpec;

fileSpec = new Buffer(MAXFILESIZE);

fileSpec.putString(`c:\bat\*.bat`);

fileSpec = fileSpec.toString();

   // Actually pass a pointer to this buffer

ofn.lpstrFile = SElib.pointer(fileSpec);

   // Set the maxsize for a filespec to pass and received

ofn.nMaxFile = MAXFILESIZE - 1;

 

   // Do the API call and get the function return

var rtn;

rtn =  SElib.dynamicLink("COMDLG32", "GetOpenFileNameA", STDCALL,

                         ofnDesc, ofn);

 

This code fragment would create a common open file dialog in a directory c:\bat and would show files with extensions of bat. The last statement is the SElib.dynamicLink() call. The object/structure ofn is passed, corresponding to the lpofn parameter in the original Win32 API syntax. The ofnDesc blobDescriptor is passed to describe ofn to ScriptEase so that ScriptEase may communicate properly with the Win32 API.

 

Notice two things about the ofn object/structure.

 

The property names match the properties in the blobDescriptor ofnDesc that describes the ofn object/structure.

Not all of the properties of the ofn object/structure needed to be initialized to values. We created a simple open dialog that did not need any data except the properties/elements that we defined. Often, it is not necessary to define data elements that are passed to an API function, if the data is not used. Be careful though. If you are not sure about whether or not to initialize all elements, it is a safe practice to initialize them to default values specified by API documentation.

 

Another thing of interest in this code fragment is how it handles string data. The lpstrFile property/element is used to pass a string to and receive a string from the GetOpenFileNameA API function. The method shown here is one way, among other techniques to handle string data. The API OpenFileName structure requires a point to a string buffer, not the string itself. Therefore, this fragment creates a buffer filespec of the proper size. It then puts the string with a file specification into the buffer and then converts the buffer to a string. ScriptEase strings may contain "\0" characters. The Buffer toString() method creates a string of the same length as the buffer and includes all of the "\0" characters after the string `c:\bat\*.bat`. Then the element lpstrFile is assigned a pointer to the string filespec, which started its existence as a Buffer object. The file name selected in the open dialog will be returned in the filespec string/buffer. We have been discussing the following lines:

 

var fileSpec;

fileSpec = new Buffer(MAXFILESIZE);

fileSpec.putString(`c:\bat\*.bat`);

fileSpec = fileSpec.toString();

   // Actually pass a pointer to this buffer

ofn.lpstrFile = SElib.pointer(fileSpec);

 

We could have accomplished the task of passing and receiving string data with the following lines (which are similar to the ones above):

 

var fileSpec;

fileSpec = new Buffer(MAXFILESIZE);

fileSpec.putString(`c:\bat\*.bat`);

   // Actually pass a pointer to this buffer

ofn.lpstrFile = SElib.pointer(fileSpec.data);

 

The main difference is that the string data is in a buffer when passed and returned. To work with the returned string data, the buffer must be converted to a string if you want to use string methods and functions with it.