Access Cookbook, 2nd Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Access Cookbook, 2nd Edition [Electronic resources] - نسخه متنی

Ken Getz; Paul Litwin; Andy Baron

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










Recipe 12.5 Add an Item to the Startup Group



12.5.1 Problem


As part of your application, you would like
to be able to allow users to add an application to the Startup menu
so that your application will start up when Windows does. You just
can't figure out how to put the information into the
Startup group. Is there a way to communicate between Access and the
Windows shell so you can do this?


12.5.2 Solution


This is a case where the old technology
called DDE comes in handy. The Windows shell accepts commands using
DDE that allow you to create and delete groups and items. You can
also retrieve lists of existing groups and items within those groups.
This solution explains most of the Windows shell's
DDE interface.

To test out the DDE interface, load and
run the form frmShell from

12-05.MDB . This form,
shown in Figure 12-7, allows you to view groups and
their items, create and delete groups and items, and display a
particular group. It will decide whether to use the group/item or the
folder/shortcut terminology after determining whether you are using
the Windows 9x shell or the Windows NT/Windows 2000 Program Manager,
respectively.


You'll find several references to Program Manager
and PROGMAN throughout this solution, as well as the use of the
group/item notation rather than folder/shortcut, but the effect is
the same either way: you can create groups and items in the Program
Manager or in the Windows shell, depending on your environment.


Figure 12-7. frmShell allows you to communicate with the Windows shell via DDE


Once you select a group from the list on
the left in Figure 12-7, the form will display the
group's items in the list on the right. If you
select the first item in the righthand listthe group
itselfthe form will display the information Windows stored
about that group. Once you've selected a group in
the righthand list box, you can click the Show button to have Windows
display that group. The code attached to the Show button requests
Windows to open the group window using style 3 (see Table 12-8 for a list of window styles). As described
later, in the sidebar Switching Focus," Windows may
grab the focus, depending on the previous state of the group window
you've selected.


The shell DDE interface does not support long filenames, and attempts
to enter long filenames will fail with an error. The example form
displays long filenames using the 8.3 short version of the
nameusually six characters, followed by a
"~1" (or a higher digit).

Select an item in the group (any row except the first in the
righthand list box), and the form will display all the information
that Windows stores about that item. Figure 12-8
shows frmShell with an item selected.


Figure 12-8. frmShell with a group selected and its information displayed


With either a group or an item selected, you can create or delete a
group or an item. If you've selected a group,
pressing the Delete button will instruct Windows to delete that
group; if you've selected an item, Windows will
delete that item. Regardless of what's selected,
pressing the Create button will pop up a dialog asking whether you
want to create a new item or a new group. Either choice will pop up
the appropriate dialog requesting the necessary information.

The following sections describe how to use the sample forms in your
own applications, and then explain most of the DDE interface to the
Windows shell. Although more DDE options are available, the most
useful tasks can be accomplished with the tools provided here.


12.5.2.1 Using the sample forms

To include the sample forms from

12-05.MDB in
your own applications, follow these steps:

  1. Import the objects shown in Table 12-3 into your
    application.


Table 12-3. Objects to import from 12-05.MDB

Object


Name


Purpose


Form


frmNew


Choose new group or new item.


Form


frmNewGroup


Enter new group information.


Form


frmNewItem


Enter new item information.


Form


frmShell


Main form.


Module


basShell


Perform DDE conversations with Windows shell.


Module


basSortArray


Sort arrays (list of program groups).


Module


basToken


Pull apart strings (item and group information on frmShell).

  1. Load and run frmShell.

    As described previously, you can use
    the form to manipulate shell groups and items from your Access
    application. If you want to use only some parts of frmShell in your
    application instead of the whole thing, that's fine
    too. If you use the group list (lstGroups), you'll
    also need to include the function that fills it,
    FillGroups. If you want the item list (lstItems),
    you'll also need FillItems. In addition, place code
    in lstGroup's AfterUpdate event
    that requeries lstItems once
    you've made a selection in
    lstGroups. You'll end up with an
    event procedure like this:

    Private Sub lstGroups_AfterUpdate ( )
    Me.lstItems.Requery
    End Sub

    To use other bits and pieces of the functionality of
    frmShell, you'll need to
    investigate its form module.



12.5.2.2 Using DDE with the Windows shell

If your main interest is simply to use DDE
to control the Windows shell, follow these steps:

  1. Import the module basShell from

    12-05.MDB into your own application. This module
    is completely self-contained and includes a number of functions that
    will set up the DDE conversation, do the work or retrieve the
    information you need, and then terminate the conversation. Because
    we've hidden all the details of the DDE, you
    needn't worry about getting all the syntax and
    parameters correct.

  2. Depending on your needs, call one or more of the wrapper procedures
    described in Table 12-4. All of these functions are
    covered in detail in Recipe 12.4.3 (see Table 12-9).


Table 12-4. Procedures in basShell to aid in using DDE between Access and Windows shell

Procedure


Purpose


acbPMCreateGroup


Create a group, given a group name and a pathname for the group file.


acbPMCreateItem


Create a new item, given the group name, the item name, the command
line, the default directory, and whether or not to run the
application minimized.


acbPMDeleteGroup


Delete a group, given the name of the group to delete.


acbPMDeleteItem


Delete an item from a group, given the name of the group and the name
of the item.


acbPMGetGroups


Fill a dynamic array with all the groups.


acbPMGetItems


Fill a dynamic array with all the items for a particular group.


acbPMShowGroup


Show a particular group, given the name of the group and the window
mode to use.


acbPMShowMessages


Allow callers outside this module to show or hide messages. Pass in
True to show messages, False to hide them (no DDE involved).


12.5.3 Discussion


The Windows shell supports two
operations: you can either request information using the DDERequest
function (Table 12-5 lists the DDERequest items) or
execute actions using the DDEExecute subroutine (Table 12-6 lists the most useful subset of the
shell's DDEExecute command-string interface). DDE
conversations between Access and the shell involve three steps:

  1. Initiate the conversation.

  2. Perform the necessary tasks.

  3. Terminate the conversation.



12.5.3.1 Retrieving information from the Windows shell

Table 12-5 describes the two groups of information
you can request from Windows. The sample form,
frmShell, uses both to fill its two list boxes.

Table 12-5. DDERequest topics for the Windows shell

To retrieve


Program


Topic


Item


Returns


List of groups


PROGMAN, or Folders


PROGMAN, or AppProperties


PROGMAN


List of existing groups, separated with CR/LF pair


List of items in a group


PROGMAN, or Folders


PROGMAN, or AppProperties


<Group Name>


List of items in the specified group, separated with CR/LF pair

To retrieve a list of groups from
Windows using the Access DDERequest function, you must first initiate
a conversation with the PROGMAN program on the
PROGMAN topic, requesting information on the
PROGMAN item; even if you use the undocumented
"Folders" program name and
"AppProperties" topic, it still
expects you to request information on the PROGMAN
item. The DDERequest call returns a carriage-return/line-feed (CR/LF)
delimited string of group names. It's up to your
code to pull apart the list of groups and place them into whatever
data structure is most convenient for you. To simplify this task, you
can use the acbPMGetGroups function in basShell.
It accepts, as a parameter, a dynamic array to fill in with the list
of groups. This function performs the DDERequest
for you and calls the private CopyToArray function to break apart the
returned stream of groups and fill the array you've
sent it. It returns the number of items in the array. Its source code
is:

Public Function acbPMGetGroups(avarGroups( ) As Variant)
' Fill a dynamic array with all the Program Manager groups.
Dim lngChannel As Long
Dim strGroups As String
Dim intCount As Integer
On Error GoTo HandleErr
' Most replacement shells will start PROGMAN for you if you attempt
' to start up a DDE conversation with it. That is, you won't need
' to Shell( ) PROGMAN if you're using a replacement shell.
lngChannel = DDEInitiate("PROGMAN", "PROGMAN")
strGroups = DDERequest(lngChannel, "PROGMAN")
intCount = CopyToArray(strGroups, avarGroups( ))
ExitHere:
acbPMGetGroups = intCount
On Error Resume Next
DDETerminate lngChannel
Err.Clear
Exit Function
HandleErr:
MsgBox Err.Number & ": " & Err.Description, , "acbGetProgmanItems"
Resume ExitHere
End Function

To call this function from your own code, use code like this:

Dim avarGroups( ) as Variant
Dim intCount as Integer
intCount = acbPMGetGroups(avarGroups( ))
' If you want the list sorted, call acbSortArray, in basSortArray.
acbSortArray avarGroups( )

To retrieve a list of items within a selected group, use the
acbPMGetItems function, which works almost exactly as
acbPMGetGroups does. This time, however, pass in a
group name along with the dynamic array to be filled in; the function
uses the group name as the topic, instead of
PROGMAN (see Table 12-5). It
calls the CopyToArray function to move the items into the dynamic
array. You generally won't sort the array, however,
unless you store the first item; this first item returns information
about the group window itself. The rest of the rows contain
information about the individual items. To use
acbPMGetItems, you might use code like this:

Dim avarGroups( ) as Variant
Dim avarItems( ) as Variant
Dim intCount as Integer
intCount = acbPMGetGroups(avarGroups( ))
intCount = acbPMGetItems(avarGroups(0), avarItems( ))
' List all the item information for the specified group.
For intI = 0 To intCount - 1
Debug.Print avarItems(intI)
Next intI


12.5.3.2 Executing tasks

The Windows shell includes a
command-string interface, which you can access via DDE, that allows
you to execute tasks involving groups and items within those groups.
Table 12-6 lists the functions addressed in this
solution. Other commands are available (they're
documented in the Windows SDK documentation), but
they're not as useful for Access programmers.

Table 12-6. DDEExecute commands for the Windows shell

Function


Parameters


Comments


AddItem


See Table 12-7


Uses

CreateGroup first to select the group.


CreateGroup


GroupName[, GroupPath]


Selects the group if it exists; otherwise, creates it.


DeleteGroup


GroupName


DeleteItem


ItemName 


Uses

CreateGroup first to select the group.


ShowGroup


GroupName, ShowCommand


See Table 12-8 for

ShowCommand
values.

In each
case, you use the Access DDEExecute procedure to communicate with the
shell. You must construct a string containing the function name,
parentheses, and any arguments for the function. For example, to
create a group from within Access, you can use code like this:

Dim intChannel as Integer
intChannel = DDEInitiate("PROGMAN", "PROGMAN")
DDEExecute intChannel, "[CreateGroup(My Group, MYGROUP.GRP)]"

The command string must be surrounded by
square bracket delimiters ([]). Luckily, the
Windows shell is far more relaxed about the use of embedded quotes
than almost any other DDE-enabled application. For example, WinFax
Pro's implementation of DDE requires quotes embedded
in command strings you send to it; the Windows shell accepts embedded
quotes but doesn't require them.

Some functions, such as
AddItem, allow quite a few parameters, almost all
of which can be left blank (see Table 12-7). To use
the AddItem command to add a new item, you must first select a group
in which to add the item. To do this, use the CreateGroup command,
which creates a group if necessary or selects it if it already
exists. The only required AddItem parameter is the command line. Note
that both X- and Y-coordinates are necessary if you choose to specify
coordinates for the icon. For example, to create a new icon to run
C:\EDIT\MYEDIT.EXE with the description My
Editor minimized in the My New Group group, use code like this
(you'd normally include error-handling code, too):

Dim intChan As Integer
intChan = DDEInitiate("PROGMAN", "PROGMAN")
' First select the group (or create it).
DDEExecute intChan, "[CreateGroup(My New Group)]"
' Use commas to delimit parameters (even missing ones).
DDEExecute intChan, "[AddItem(C:\EDIT\MYEDIT,My Editor,,,,,,1)]"

Table 12-7. Parameters for the AddItem function

Parameter


Required?


Used in sample?


Description


CmdLine


Yes


Yes


Command line to run the application. Must be at least the executable
filename, but can also include parameters as necessary.


Name


No


Yes


Name that appears below the icon in the group.


IconPath


No


No


Name and path of the icon file to use. If an executable file is
specified, use the first icon in that file. If left blank, use the
first icon in the executable file specified in the
CmdLine parameter.


IconIndex


No


No


Index of the icon in the specified
IconPath file (or the specified
executable). Otherwise, if missing, use the first icon specified.


Xpos


No


No


X-position of the icon within the group, as an integer. Both this and
Ypos are required to set the specific
position. If left blank, use the next available position.


Ypos


No


No


Y-position of the icon within the group, as an integer.


DefDir


No


Yes


Default (or working) directory for the application.


HotKey


No


No


Hot key for this application, stored as an integer.


fMinimize


No


Yes


Run Minimized (1 = True, 0 = False).


fSeparateMemSpace 


No


No


In Windows NT only, run the application in a separate memory space
(applies to 16-bit applications only).


Switching Focus


Using the ShowGroup command sometimes moves the focus to the shell
but usually does not. Whether the focus switches depends on the state
you request for the program group and on its current state. Though
you could make a matrix of options, comparing current states
(minimized, normal, or maximized) against the new window state (1-8,
as in Table 12-8), the rules are quite simple. If
you change the state of a group that's currently
minimized, the focus will switch to the shell. That means that if you
choose actions 1, 3, or 4 for a group that is currently minimized,
the shell will grab the focus. You can try this yourself, calling the
acbPMShowGroup function and passing it the name of a group and a new
window style.

Table 12-8. Window style command values for the ShowGroup function

Window style value


Action


1


Activate and display the group window. If it was minimized or
maximized, restore it to its original position (normalized).


2


Activate the group window and display it as an icon.


3


Activate the group window and display it maximized.


4


Display the group window normalized and leave the current group
selected.


5


Activate the group window and display it in its current placement.


6


Minimize the group window.


7


Minimize the group window and leave the current group selected.


8


Display the group window in its current placement and leave the
current group selected.


12.5.3.3 Using the wrapper procedures

To make your DDE programming simpler,
the module basShell includes wrapper procedures
that handle all the details for you. (Table 12-4
provides a description of each of the wrapper procedures; Table 12-9 lists the parameters.) The module also
provides functions that handle each of the commands described in
Table 12-6. In some cases
(AddItem, for example), the wrapper functions
don't allow you to specify all the possible
parameters for the command string. If you find these wrapper
functions too limiting, you can modify them so they allow you to pass
in whatever parameters you like.

All the wrapper procedures (except
acbPMShowMessages) in Table 12-9
perform the same set of steps to communicate with the Windows shell.
To simplify the code and centralize error handling, those steps have
been pulled into a single private procedure in
basShell, DDEExecutePM, which
is shown in the following code example:

Private Function DDEExecutePM(strCommand As String) As Boolean
' DDEExecute with the passed-in command. If it succeeds,
' return True. If it fails, return False.
' At this point, this function handles error messages itself.
' You could move this out of here to a higher level, if you
' want, by setting the SHOW_MESSAGES constant to False.
Dim lngChannel As Long
On Error GoTo HandleErr
lngChannel = DDEInitiate("PROGMAN", "PROGMAN")
DDEExecute lngChannel, strCommand
DDEExecutePM = True
ExitHere:
On Error Resume Next
DDETerminate lngChannel
Err.Clear
Exit Function
HandleErr:
If Not mfHideMessages Then
MsgBox Err.Number & ": " & Err.Description, , "DDEExecutePM"
End If
DDEExecutePM = False
Resume ExitHere
End Function

Given a string to execute,
this code initiates the DDE channel, uses
DDEExecute to execute the command, and then
terminates the connection. If all goes according to plan, the
procedure returns a True value. If an error
occurs, it displays a message box (unless you've
used the acbPMShowMessages procedure to disable warning messages) and
then returns False.

Table 12-9 lists the parameters for the wrapper
procedures in basShell. Each of these procedures
(except acbPMShowMessages) returns
True if the function succeeded, or
False if it failed. Unless you've
called the acbPMShowMessages subroutine to disable messages, a
message will appear before deleting a group or item or if any error
occurs.

Table 12-9. Parameters for the wrapper procedures in basShell

Procedure


Parameter


Data type


Parameter description


acbPMCreateGroup


varName


Variant


Name of the new group.


varGroupPath 


Variant


Name of the group file (can be Null, in which case Windows uses a
name of its own choosing).


acbPMCreateItem


varGroup 


Variant


Name of the group in which to create the new item.


varName 


Variant


Descriptive name for the new item; appears under the icon.


varCommandLine


Variant


Command line to execute when this icon is chosen. Cannot be Null.


varDirectory 


Variant


Default (working) directory when the application starts up.


varMinimized 


Variant


Logical value: run the app minimized?


acbPMDeleteGroup


varName 


Variant


Group to delete.


acbPMDeleteItem


varGroup 


Variant


Group from which to delete the item.


varName


Variant


Name of the item to delete.


acbPMShowGroup


varName


Variant


Name of the group to show.


intMode 


Integer


Window mode, as listed in Table 12-8.


acbPMShowMessages


fShow 


Integer


Logical value: display messages during DDE wrapper functions? If
True, functions use message box if errors occur and when deleting
items. This subroutine sets a module global variable, so you need to
call it only once per session.

For example, to use the wrapper functions to add an icon to the My
Group group that will run C:\EDIT\MYEDIT.EXE
minimized with the description My Editor (as in the example that
called AddItem directly), you could use code like
this:

Dim fSuccess As Boolean
' Disable error messages.
acbPMShowMessages False
fSuccess = acbPMCreateItem("My Group", "My Editor", _
"C:\EDIT\MYEDIT.EXE", Null, True)
If Not fSuccess Then MsgBox "Unable to create new item!"

This example also calls acbPMShowMessages to
disable error messages from within acbCreateItem,
so the code fragment itself can handle them.

For examples of each of the wrapper functions, check out the code in
frmShell's module.


12.5.4 Comments


Though this solution covers a great deal more than the original
question required, all the information here will be useful to Access
programmers working with the DDE interface to the Windows shell.

The sample form, frmShell, is not only a good example of using DDE to
converse with Windows, it's also a useful tool on
its own. Because it allows you to see what's in each
group without having to open and close each group's
window, it's a quick and easy way to clean out your
groups. Of course, some extra work would be required for it to be a
really useful tool, but it's a good start.

In
16-bit applications, DDEInitiate returns a short
integer (16-bit) handle. In Access 95 and later (and other 32-bit
applications), this function returns a long integer (32-bit) handle.
If you have existing code that uses DDE, you'll want
to convert the variables containing the return values into long
integers.

The Windows shell has an undocumented DDE application
topic pair that is not supported by the original Program Manager or
any of the major third-party shell substitutes: Folders
AppProperties. This syntax seems to be just an alias for the
regularly documented DDE interface, because the item name syntax and
all the operations are identical in both cases.

This undocumented syntax can be of some
benefit. If you are going to add the functionality to interact with
the shell, you can use code like the following to determine if your
user is running the Windows 9x shell:

Public Function acbNewShell ( ) as Boolean
Dim lngChannel as Long
On Error Resume Next
lngChannel = DDEInitiate("Folders","AppProperties")
acbNewShell = (lngChannel <> 0)
DDETerminate lngChannel
End Function

You'll notice that the example uses this function
(as well as a public flag) to decide whether to call the various
shell objects "groups" and
"items" (as in the Windows NT
Program Manager) or "folders" and
"shortcuts" (as in the Windows 9x
shell).

To
shield you from the details of the DDE conversation and to isolate
the DDE code in one routine, each of the command-string replacement
functions calls the DDEExecutePM function. This makes the code neat
and easy to understand, but it does have a potential disadvantage:
calling DDEInitiate and
DDETerminate every time you call a wrapper
function adds substantial time and overhead to your application. If
you make many calls to Window via DDE, you'll want
to reconsider this design. For most applications, though, this
shouldn't be a problem.


/ 232