• Calling DLL routines from LotusScript. Part I: Windows API


    Domino/Notes Version: 4.x and higher
    Platform: Windows 95, 98, NT 4

    Like me, you probably find LotusScript just cannot do everything you want at times. After seeing the article titled "Changing Drivers on the Road" in the February 1998 Lotus Notes & Domino Advisor a whole new world became obvious to me. The article described how to call the Windows API functions from within LotusScript. I have found countless uses for this including:

    · Modifying the default printer (as described in the above mentioned article)
    · Getting a list of Windows printers to present to the user before modifying the default printer
    · Using the Windows Common Dialogs
    · Accessing the Windows clipboard
    · Getting Windows configuration settings (temp directory, computer name, etc.)
    · and quite a few others...

    A natural and quite possibly even more interesting extension to this is using the same method to call the Notes API. Again, I must given credit where credit is due. An article in The View sparked this idea. It appeared in the July/August 1998 issue and was called "Manipulating Rich Text Fields with LotusScript and the HiTest C API - Without C Programming". When I have done this I have chosen to use the C API over the HiTest C API and I will tell you why later. Part I of this document will describe writing declares and using the Windows API DLLs. Part II will cover using the Lotus Notes C API.

    Part I: The Windows API
    My intent here is not to cover programming the Windows API as there are many good books on the subject but to cover integrating it into your Lotus Notes/Domino applications. I have included several good references on more information that I found useful as I was getting started doing this and I also have a couple of examples to show you what can be done through the API.

    Declaring the DLL Functions
    Often, the trickiest part of using the WIndows API is writing the counterpart of the API routine in Notes; the declare statement for the function in the DLL. It takes some practice to get things right. Without the right declare statement get prepared for lots of memory exceptions and crashes within the Notes client. VB programmers do this all of the time so there are a few good references that you will find handy:

    First and foremost if you have Visual Basic, it contains a Text API Viewer which allows you to browse the Windows API functions and their associated declares. You can copy them to the clipboard and paste then into your (Declarations). The declares are also stored in a plain text file, WIN32API.TXT, that you can open with any text editor. Personally, I find this more effective for finding what I want.

    If you don’t have VB then there is another alternative. First, find the Windows DLL (e.g. kernel32.dll) you would like to investigate functions for in the Windows System directory using Windows Explorer. Right click it and select Quick View. This will bring up, among other things, an Export Table that will list the names of all of the functions in the DLL. Knowing what function you want to call, you just need the syntax for each function. The Microsoft Developers Network comes in handy here. On it, you’ll want to go to the MSDN Library Online but first you will have to register and tell MS about yourself. I think it is well worth it. Once on the site, a search on WIN32API.TXT turns up several good articles some of which are listed below. (The URLs are included here but I imagine they might change and that is why I told you how I found the documents.)

    Declaring a DLL procedure
    This article introduces you Declaring DLL routines for Word Basic but it applies equally to VB and LotusScript. Most importantly, it also covers how to convert C Language declarations to Word Basic/LotusScript equivalents.

    Calling Routine in DLLs
    An introduction to calling DLL procedures from VB. Listed here are important Windows DLL files and what types of routines they contain.

    I have provided a couple of examples here to discuss the main points in writing these solutions. The examples cover using the Windows Common Dialogs and using the Windows clipboard.

    Example 1 - Windows Common Dialogs
    The Lotus macro language has @Prompt([LocalBrowse]) but LotusScript programmers aren’t so lucky. In trying to solve this problem I could not help but think about using the Windows Common Dialogs. Here I’ll show you how to use the Open File dialog and this method can be extended to other common dialogs as well.

    To demonstrate this I wrote an Agent that had the settings "Manually from the Actions menu" and "Run Once (@Commands may be used)"


    (Declarations)

    Type OPENFILENAME
    lStructSize As Long
    hwndOwner As Long
    hInstance As Long
    lpstrFilter As String
    lpstrCustomFilter As String
    nMaxCustFilter As Long
    nFilterIndex As Long
    lpstrFile As String
    nMaxFile As Long
    lpstrFileTitle As String
    nMaxFileTitle As Long
    lpstrInitialDir As String
    lpstrTitle As String
    flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    lpstrDefExt As String
    lCustData As Long
    lpfnHook As Long
    lpTemplateName As String
    End Type

    Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long


    Sub Initialize
    Dim OpenFile As OPENFILENAME
    Dim Returnl As Long
    Dim Filterstr As String

    OpenFile.lStructSize = Len(OpenFile)
    Filterstr = "Word Documents (*.doc)" & Chr(0) & "*.doc" & Chr(0) & "All Files (*.*)" & Chr(0) & "*.*" & Chr(0)
    OpenFile.lpstrFilter = Filterstr
    OpenFile.nFilterIndex = 1
    OpenFile.lpstrFile = String(257, 0)
    OpenFile.nMaxFile = Len(OpenFile.lpstrFile) - 1
    OpenFile.lpstrFileTitle = OpenFile.lpstrFile
    OpenFile.nMaxFileTitle = OpenFile.nMaxFile
    OpenFile.lpstrInitialDir = "C:\My Documents"
    OpenFile.lpstrTitle = "Open File"
    OpenFile.flags = 0
    Returnl = GetOpenFileName(OpenFile)

    If Returnl = 0 Then
    Msgbox "The user pressed the Cancel Button"
    Else
    Msgbox "The user chose " & Trim(OpenFile.lpstrFile)
    End If
    End Sub


    This example demonstrates several important things about declaring and calling DLL routines.

    Often structures are used to pass data to and from these routines. Not only do you need to declare the routine but you must also define the structures to LotusScript. I have done that here with the OPENFILENAME structure in the (Declarations) section of my Agent. I just copied the declarations straight from the WIN32API.TXT file. In my call to the routine I have chosen to default the folder to "My Documents" and to display only Word (.doc) documents by default and also giving the user the option to change the Files of Type selection to "All Files (*.*)". For more information on the syntax of the options for GetOpenFileName see the developer's network and search of GetOpenFileName. My program simply calls the dialog box and returns, via a message box, the path and filename that the user has selected. This information can then be used for a file operation such as a NotesEmbeddedObject.ExtractFile

    Example 2 - Accessing the Windows clipboard
    I originally wrote this when I was using OLE Automation from LotusScript to work in another application (MS Word) and needed to bring back text from the other application into a Notes backend document. This routine accomplishes that although it just brings back plain text. I am sure there are lots of other uses for and extensions of it.


    (Declarations)

    'Clipboard Manager Functions
    Declare Function GetClipboardData Lib "User32" (Byval wFormat As Long) As Long 'Note: GetClipboardDataA as aliased in Win32api.txt did not work!
    Declare Function OpenClipboard Lib "User32" Alias "OpenClipboard" (Byval hwnd As Long) As Long
    Declare Function CloseClipboard Lib "User32" Alias "CloseClipboard" () As Long

    'Predefined Clipboard Formats
    Public Const CF_TEXT = 1

    'Memory management functions
    Declare Function GlobalLock Lib "kernel32" Alias "GlobalLock" (Byval hMem As Long) As Long
    Declare Function GlobalUnlock Lib "kernel32" Alias "GlobalUnlock" (Byval hMem As Long) As Long

    'String Copy function for each of its various parameter configurations lstrcpy(to_string, from_string)
    Declare Function lstrcpyLP2Str Lib "kernel32" Alias "lstrcpyA" (Byval lpString1 As String, Byval lpString2 As Long) As Long
    Declare Function lstrcpyStr2Str Lib "kernel32" Alias "lstrcpyA" (Byval lpString1 As String, Byval lpString2 As String) As Long
    Declare Function lstrcpyStr2LP Lib "kernel32" Alias "lstrcpyA" (Byval lpString1 As Long, Byval lpString2 As String) As Long

    'String Length function for each of its various parameter configurations
    Declare Function lstrlenLP Lib "kernel32" Alias "lstrlenA" (Byval lpString As Long) As Long
    Declare Function lstrlenStr Lib "kernel32" Alias "lstrlenA" (Byval lpString As String) As Long

    'Keyboard input functions
    Declare Function GetFocus Lib "User32" Alias "GetFocus" () As Long


    Function GetClipboardContents() As String

    Dim ClipboardHandlel As Long
    Dim LpStrl As Long
    Dim HWndl As Long
    Dim Resultl As Long
    Dim Clipboardstr As String

    'Get a handle for the current window that has keyboard focus
    HWndl = GetFocus()

    'Open the clipboard, specify this window as the owner so no one else modifies it while we use it
    If (OpenClipboard(HWndl) <> 0) Then

    'Get the data off of the clipboard in text format
    ClipboardHandlel = GetClipboardData(CF_TEXT)

    'Get the text out of Windows memory into a string we can work with here
    If (ClipboardHandlel <> 0) Then
    'Lock the memory we will work on and get a handle to it
    LpStrl = GlobalLock(ClipboardHandlel)
    'Pre-allocate some space for our String
    Clipboardstr = Space$(lstrlenLP(LpStrl))
    'Copy it in
    Resultl = lstrcpyLP2Str(Clipboardstr, LpStrl)
    'Release the lock
    GlobalUnlock(ClipboardHandlel)
    Else
    Clipboardstr = "NULL"
    End If
    'Close the clipboard so other applications may use it
    Resultl = CloseClipboard
    Else
    Print "Could not open Clipboard"
    End If

    GetClipboardContents = Clipboardstr
    End Function


    There are some important points about this code worth mentioning. There are sometimes more that one way to alias a DLL routine depending on the types of parameters that will be passed to it. In Example 2 I have done this for the lstrlenA routine which computes the length of a string.

    Often the result of a call to a DLL routine will be a pointer to a block of memory that contains a result; in our case a string. This is a little different from a block of memory that has been allocated via LotusScript for a string variable. When using lstrlenA providing it pointers to each of these blocks of memory is done differently. In the first case, the pointer is passed as a Long. Is the second case the pointer is passed for the String. Each of these two difference interactions with the single routine require a different declaration in LotusScript as I have done for lstrlenA. I have named them so it is easy to tell them apart when using them. For the version that is used when the pointer is a long pointer obtained from another routine I have appended "LP" to its name and declared the parameter as ByVal Long. For the version that is used when a LotusScript string variable is used I have appended "Str" to its name and declared the parameter as ByVal String..

    Conclusion
    I think it goes without saying that careful planning must be done when using these types of solutions since you are tying your application to not only the Lotus Notes platform but the Operating System version. These types of calls would not result in cross platform solutions that would work on other Operating Systems. But, if you work primarily in the Windows enviroment as many people do the power here is very appealing. And, although Windows versions are usually backward compatible it is not always the case that things behave exactly the same from one version to another.

    Hopefully this document arms you with enough information and inspiration to incorporate this type of functionality into your solutions.

  • 相关阅读:
    句柄实现SMARTFORMS
    SMARTFORMS错误整理:全局定义
    SAP Web IDE Local Trial Version的安装
    SAP 讲解史上最牛smartforms
    关于针对SMARTFORMS模板不能修改的解决办法
    特朗普赢了大选,中国赢了世界
    com.opensymphony.xwork2.ognl.OgnlValueStack]
    ognl.OgnlException: target is null for setProperty(null, "emailTypeNo", [Ljava.lang.String;@1513fd0)
    ASE Code Search
    ASE "黄金点游戏"
  • 原文地址:https://www.cnblogs.com/hannover/p/2130348.html
Copyright © 2020-2023  润新知