VirtualBox

Changeset 4264 in vbox


Ignore:
Timestamp:
Aug 21, 2007 3:23:28 PM (17 years ago)
Author:
vboxsync
Message:

Backed out 23773 until it works

Location:
trunk/src/VBox/Additions/WINNT/VBoxService
Files:
3 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/VBoxService/Makefile.kmk

    r4263 r4264  
    3030        VBoxSeamless.cpp \
    3131        VBoxClipboard.cpp \
    32         VBoxDisplay.cpp \
    3332        helpers.cpp \
    3433        VBoxService.rc
  • trunk/src/VBox/Additions/WINNT/VBoxService/VBoxService.cpp

    r4263 r4264  
    1717#include "VBoxService.h"
    1818#include "VBoxSeamless.h"
    19 #include "VBoxClipboard.h"
    20 #include "VBoxDisplay.h"
    2119#include <VBoxHook.h>
    2220#include "resource.h"
     
    7068
    7169
     70/* The shared clipboard service prototypes. */
     71int                VBoxClipboardInit    (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
     72unsigned __stdcall VBoxClipboardThread  (void *pInstance);
     73void               VBoxClipboardDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
     74
    7275/* The service table. */
    7376static VBOXSERVICEINFO vboxServiceTable[] =
    7477{
    75     {
    76         "Display",
    77         VBoxDisplayInit,
    78         VBoxDisplayThread,
    79         VBoxDisplayDestroy,
    80     },
    8178    {
    8279        "Shared Clipboard",
     
    299296    }
    300297
     298    /* create display change thread */
     299    HANDLE hDisplayChangeThread;
     300    if (status == NO_ERROR)
     301    {
     302        hDisplayChangeThread = (HANDLE)_beginthread(DisplayChangeThread, 0, NULL);
     303        if ((int)hDisplayChangeThread == -1L)
     304            status = ERROR_GEN_FAILURE;
     305    }
     306
     307    dprintf(("VBoxService: hDisplayChangeThread h %p, st %p\n", hDisplayChangeThread, status));
     308
    301309    /* terminate service if something went wrong */
    302310    if (status != NO_ERROR)
     
    372380    dprintf(("VBoxService: waiting for display change thread...\n"));
    373381
     382    /* wait for the display change thread to terminate */
     383    WaitForSingleObject(hDisplayChangeThread, INFINITE);
     384
    374385    vboxStopServices (&svcEnv, vboxServiceTable);
    375386
     
    401412}
    402413
     414static bool isVBoxDisplayDriverActive (void)
     415{
     416    bool result = false;
     417
     418    DISPLAY_DEVICE dispDevice;
     419
     420    FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
     421
     422    dispDevice.cb = sizeof(DISPLAY_DEVICE);
     423
     424    INT devNum = 0;
     425
     426    while (EnumDisplayDevices(NULL,
     427                              devNum,
     428                              &dispDevice,
     429                              0))
     430    {
     431        DDCLOG(("DevNum:%d\nName:%s\nString:%s\nID:%s\nKey:%s\nFlags=%08X\n\n",
     432                      devNum,
     433                      &dispDevice.DeviceName[0],
     434                      &dispDevice.DeviceString[0],
     435                      &dispDevice.DeviceID[0],
     436                      &dispDevice.DeviceKey[0],
     437                      dispDevice.StateFlags));
     438
     439        if (dispDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
     440        {
     441            DDCLOG(("Primary device.\n"));
     442
     443            if (strcmp(&dispDevice.DeviceString[0], "VirtualBox Graphics Adapter") == 0)
     444            {
     445                DDCLOG(("VBox display driver is active.\n"));
     446                result = true;
     447            }
     448
     449            break;
     450        }
     451
     452        FillMemory(&dispDevice, sizeof(DISPLAY_DEVICE), 0);
     453
     454        dispDevice.cb = sizeof(DISPLAY_DEVICE);
     455
     456        devNum++;
     457    }
     458
     459    return result;
     460}
     461
     462/* ChangeDisplaySettingsEx does not exist in NT. ResizeDisplayDevice uses the function. */
     463typedef LONG WINAPI defChangeDisplaySettingsEx(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
     464static defChangeDisplaySettingsEx *pChangeDisplaySettingsEx = NULL;
     465
     466/* Returns TRUE to try again. */
     467static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
     468{
     469    BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
     470   
     471    DISPLAY_DEVICE DisplayDevice;
     472
     473    ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
     474    DisplayDevice.cb = sizeof(DisplayDevice);
     475   
     476    /* Find out how many display devices the system has */
     477    DWORD NumDevices = 0;
     478    DWORD i = 0;
     479    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
     480    {
     481        DDCLOG(("[%d] %s\n", i, DisplayDevice.DeviceName));
     482
     483        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
     484        {
     485            DDCLOG(("Found primary device. err %d\n", GetLastError ()));
     486            NumDevices++;
     487        }
     488        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
     489        {
     490           
     491            DDCLOG(("Found secondary device. err %d\n", GetLastError ()));
     492            NumDevices++;
     493        }
     494       
     495        ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
     496        DisplayDevice.cb = sizeof(DisplayDevice);
     497        i++;
     498    }
     499   
     500    DDCLOG(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
     501   
     502    if (NumDevices == 0 || Id >= NumDevices)
     503    {
     504        DDCLOG(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
     505        return FALSE;
     506    }
     507   
     508    DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
     509    DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
     510    RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
     511   
     512    /* Fetch information about current devices and modes. */
     513    DWORD DevNum = 0;
     514    DWORD DevPrimaryNum = 0;
     515   
     516    ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
     517    DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
     518   
     519    i = 0;
     520    while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
     521    {
     522        DDCLOG(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
     523       
     524        BOOL bFetchDevice = FALSE;
     525
     526        if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
     527        {
     528            DDCLOG(("Found primary device. err %d\n", GetLastError ()));
     529            DevPrimaryNum = DevNum;
     530            bFetchDevice = TRUE;
     531        }
     532        else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
     533        {
     534           
     535            DDCLOG(("Found secondary device. err %d\n", GetLastError ()));
     536            bFetchDevice = TRUE;
     537        }
     538       
     539        if (bFetchDevice)
     540        {
     541            if (DevNum >= NumDevices)
     542            {
     543                DDCLOG(("%d >= %d\n", NumDevices, DevNum));
     544                return FALSE;
     545            }
     546       
     547            paDisplayDevices[DevNum] = DisplayDevice;
     548           
     549            ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
     550            paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
     551            if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
     552                 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
     553            {
     554                DDCLOG(("EnumDisplaySettings err %d\n", GetLastError ()));
     555                return FALSE;
     556            }
     557           
     558            DDCLOG(("%dx%d at %d,%d\n",
     559                    paDeviceModes[DevNum].dmPelsWidth,
     560                    paDeviceModes[DevNum].dmPelsHeight,
     561                    paDeviceModes[DevNum].dmPosition.x,
     562                    paDeviceModes[DevNum].dmPosition.y));
     563                   
     564            paRects[DevNum].left   = paDeviceModes[DevNum].dmPosition.x;
     565            paRects[DevNum].top    = paDeviceModes[DevNum].dmPosition.y;
     566            paRects[DevNum].right  = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
     567            paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
     568            DevNum++;
     569        }
     570       
     571        ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
     572        DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
     573        i++;
     574    }
     575   
     576    if (Width == 0)
     577    {
     578        Width = paRects[Id].right - paRects[Id].left;
     579    }
     580
     581    if (Height == 0)
     582    {
     583        Height = paRects[Id].bottom - paRects[Id].top;
     584    }
     585
     586    /* Check whether a mode reset or a change is requested. */
     587    if (   !fModeReset
     588        && paRects[Id].right - paRects[Id].left == Width
     589        && paRects[Id].bottom - paRects[Id].top == Height
     590        && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
     591    {
     592        DDCLOG(("VBoxService: already at desired resolution.\n"));
     593        return FALSE;
     594    }
     595
     596    resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
     597#ifdef DDCLOG
     598    for (i = 0; i < NumDevices; i++)
     599    {
     600        DDCLOG(("[%d]: %d,%d %dx%d\n",
     601                i, paRects[i].left, paRects[i].top,
     602                paRects[i].right - paRects[i].left,
     603                paRects[i].bottom - paRects[i].top));
     604    }
     605#endif /* DDCLOG */
     606   
     607    /* Without this, Windows will not ask the miniport for its
     608     * mode table but uses an internal cache instead.
     609     */
     610    DEVMODE tempDevMode;
     611    ZeroMemory (&tempDevMode, sizeof (tempDevMode));
     612    tempDevMode.dmSize = sizeof(DEVMODE);
     613    EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
     614
     615    /* Assign the new rectangles to displays. */
     616    for (i = 0; i < NumDevices; i++)
     617    {
     618        paDeviceModes[i].dmPosition.x = paRects[i].left;
     619        paDeviceModes[i].dmPosition.y = paRects[i].top;
     620        paDeviceModes[i].dmPelsWidth  = paRects[i].right - paRects[i].left;
     621        paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
     622       
     623        paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
     624       
     625        if (   i == Id
     626            && BitsPerPixel != 0)
     627        {
     628            paDeviceModes[i].dmFields |= DM_BITSPERPEL;
     629            paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
     630        }
     631       
     632        pChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
     633                 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
     634        DDCLOG(("ChangeDisplaySettings position err %d\n", GetLastError ()));
     635    }
     636   
     637    /* A second call to ChangeDisplaySettings updates the monitor. */
     638    LONG status = ChangeDisplaySettings(NULL, 0);
     639    DDCLOG(("ChangeDisplaySettings update status %d\n", status));
     640    if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
     641    {
     642        /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
     643        return FALSE;
     644    }
     645
     646    /* Retry the request. */
     647    return TRUE;
     648}
     649
     650/**
     651 * Thread function to wait for and process display change
     652 * requests
     653 */
     654VOID DisplayChangeThread(void *dummy)
     655{
     656    bool fTerminate = false;
     657    VBoxGuestFilterMaskInfo maskInfo;
     658    DWORD cbReturned;
     659   
     660    HMODULE hUser = GetModuleHandle("USER32");
     661
     662    if (hUser)
     663    {
     664        pChangeDisplaySettingsEx = (defChangeDisplaySettingsEx *)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
     665        DDCLOG(("VBoxService: pChangeDisplaySettingsEx = %p\n", pChangeDisplaySettingsEx));
     666    }
     667
     668    maskInfo.u32OrMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     669    maskInfo.u32NotMask = 0;
     670    if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
     671    {
     672        DDCLOG(("VBoxService: DeviceIOControl(CtlMask - or) succeeded\n"));
     673    }
     674    else
     675    {
     676        dprintf(("VBoxService: DeviceIOControl(CtlMask) failed, DisplayChangeThread exited\n"));
     677        return;
     678    }
     679
     680    do
     681    {
     682        /* wait for a display change event */
     683        VBoxGuestWaitEventInfo waitEvent;
     684        waitEvent.u32TimeoutIn = 100;
     685        waitEvent.u32EventMaskIn = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     686        if (DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
     687        {
     688            DDCLOG(("VBoxService: DeviceIOControl succeded\n"));
     689
     690            /* are we supposed to stop? */
     691            if (WaitForSingleObject(gStopSem, 0) == WAIT_OBJECT_0)
     692                break;
     693
     694            DDCLOG(("VBoxService: checking event\n"));
     695
     696            /* did we get the right event? */
     697            if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
     698            {
     699                DDCLOG(("VBoxService: going to get display change information.\n"));
     700
     701                /* We got at least one event. Read the requested resolution
     702                 * and try to set it until success. New events will not be seen
     703                 * but a new resolution will be read in this poll loop.
     704                 */
     705                for (;;)
     706                {
     707                    /* get the display change request */
     708                    VMMDevDisplayChangeRequest2 displayChangeRequest = {0};
     709                    displayChangeRequest.header.size        = sizeof(VMMDevDisplayChangeRequest2);
     710                    displayChangeRequest.header.version     = VMMDEV_REQUEST_HEADER_VERSION;
     711                    displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest2;
     712                    displayChangeRequest.eventAck           = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     713                    BOOL fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_VMMREQUEST, &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2),
     714                                                                 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest2), &cbReturned, NULL);
     715                    if (!fDisplayChangeQueried)
     716                    {
     717                        /* Try the old version of the request for old VBox hosts. */
     718                        displayChangeRequest.header.size        = sizeof(VMMDevDisplayChangeRequest);
     719                        displayChangeRequest.header.version     = VMMDEV_REQUEST_HEADER_VERSION;
     720                        displayChangeRequest.header.requestType = VMMDevReq_GetDisplayChangeRequest;
     721                        displayChangeRequest.eventAck           = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     722                        fDisplayChangeQueried = DeviceIoControl(gVBoxDriver, IOCTL_VBOXGUEST_VMMREQUEST, &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest),
     723                                                                 &displayChangeRequest, sizeof(VMMDevDisplayChangeRequest), &cbReturned, NULL);
     724                        displayChangeRequest.display = 0;
     725                    }
     726
     727                    if (fDisplayChangeQueried)
     728                    {
     729                        DDCLOG(("VBoxService: VMMDevReq_GetDisplayChangeRequest2: %dx%dx%d at %d\n", displayChangeRequest.xres, displayChangeRequest.yres, displayChangeRequest.bpp, displayChangeRequest.display));
     730
     731                        /* Horizontal resolution must be a multiple of 8, round down. */
     732                        displayChangeRequest.xres &= 0xfff8;
     733
     734                        /*
     735                         * Only try to change video mode if the active display driver is VBox additions.
     736                         */
     737                        if (isVBoxDisplayDriverActive ())
     738                        {
     739                            if (pChangeDisplaySettingsEx != 0)
     740                            {
     741                                /* W2K or later. */
     742                                if (!ResizeDisplayDevice(displayChangeRequest.display,
     743                                                         displayChangeRequest.xres,
     744                                                         displayChangeRequest.yres,
     745                                                         displayChangeRequest.bpp))
     746                                {
     747                                    break;
     748                                }
     749                            }
     750                            else
     751                            {
     752                                /* Single monitor NT. */
     753                                DEVMODE devMode;
     754                                memset (&devMode, 0, sizeof (devMode));
     755                                devMode.dmSize = sizeof(DEVMODE);
     756
     757                                /* get the current screen setup */
     758                                if (EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &devMode))
     759                                {
     760                                    dprintf(("VBoxService: Current mode: %dx%dx%d at %d,%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmPosition.x, devMode.dmPosition.y));
     761
     762                                    /* Check whether a mode reset or a change is requested. */
     763                                    if (displayChangeRequest.xres || displayChangeRequest.yres || displayChangeRequest.bpp)
     764                                    {
     765                                        /* A change is requested.
     766                                         * Set values which are not to be changed to the current values.
     767                                         */
     768                                        if (!displayChangeRequest.xres)
     769                                            displayChangeRequest.xres = devMode.dmPelsWidth;
     770                                        if (!displayChangeRequest.yres)
     771                                            displayChangeRequest.yres = devMode.dmPelsHeight;
     772                                        if (!displayChangeRequest.bpp)
     773                                            displayChangeRequest.bpp = devMode.dmBitsPerPel;
     774                                    }
     775                                    else
     776                                    {
     777                                        /* All zero values means a forced mode reset. Do nothing. */
     778                                    }
     779
     780                                    /* Verify that the mode is indeed changed. */
     781                                    if (   devMode.dmPelsWidth  == displayChangeRequest.xres
     782                                        && devMode.dmPelsHeight == displayChangeRequest.yres
     783                                        && devMode.dmBitsPerPel == displayChangeRequest.bpp)
     784                                    {
     785                                        dprintf(("VBoxService: already at desired resolution.\n"));
     786                                        break;
     787                                    }
     788
     789                                    // without this, Windows will not ask the miniport for its
     790                                    // mode table but uses an internal cache instead
     791                                    DEVMODE tempDevMode = {0};
     792                                    tempDevMode.dmSize = sizeof(DEVMODE);
     793                                    EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
     794
     795                                    /* adjust the values that are supposed to change */
     796                                    if (displayChangeRequest.xres)
     797                                        devMode.dmPelsWidth  = displayChangeRequest.xres;
     798                                    if (displayChangeRequest.yres)
     799                                        devMode.dmPelsHeight = displayChangeRequest.yres;
     800                                    if (displayChangeRequest.bpp)
     801                                        devMode.dmBitsPerPel = displayChangeRequest.bpp;
     802
     803                                    DDCLOG(("VBoxService: setting the new mode %dx%dx%d\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel));
     804
     805                                    /* set the new mode */
     806                                    LONG status = ChangeDisplaySettings(&devMode, CDS_UPDATEREGISTRY);
     807                                    if (status != DISP_CHANGE_SUCCESSFUL)
     808                                    {
     809                                        dprintf(("VBoxService: error from ChangeDisplaySettings: %d\n", status));
     810
     811                                        if (status == DISP_CHANGE_BADMODE)
     812                                        {
     813                                            /* Our driver can not set the requested mode. Stop trying. */
     814                                            break;
     815                                        }
     816                                    }
     817                                    else
     818                                    {
     819                                        /* Successfully set new video mode. */
     820                                        break;
     821                                    }
     822                                }
     823                                else
     824                                {
     825                                    dprintf(("VBoxService: error from EnumDisplaySettings: %d\n", GetLastError ()));
     826                                    break;
     827                                }
     828                            }
     829                        }
     830                        else
     831                        {
     832                            dprintf(("VBoxService: vboxDisplayDriver is not active.\n"));
     833                        }
     834
     835                        /* Retry the change a bit later. */
     836                        /* are we supposed to stop? */
     837                        if (WaitForSingleObject(gStopSem, 1000) == WAIT_OBJECT_0)
     838                        {
     839                            fTerminate = true;
     840                            break;
     841                        }
     842                    }
     843                    else
     844                    {
     845                        dprintf(("VBoxService: error from DeviceIoControl IOCTL_VBOXGUEST_VMMREQUEST\n"));
     846                        /* sleep a bit to not eat too much CPU while retrying */
     847                        /* are we supposed to stop? */
     848                        if (WaitForSingleObject(gStopSem, 50) == WAIT_OBJECT_0)
     849                        {
     850                            fTerminate = true;
     851                            break;
     852                        }
     853                    }
     854                }
     855            }
     856        } else
     857        {
     858            dprintf(("VBoxService: error 0 from DeviceIoControl IOCTL_VBOXGUEST_WAITEVENT\n"));
     859            /* sleep a bit to not eat too much CPU in case the above call always fails */
     860            if (WaitForSingleObject(gStopSem, 10) == WAIT_OBJECT_0)
     861            {
     862                fTerminate = true;
     863                break;
     864            }
     865        }
     866    } while (!fTerminate);
     867
     868    maskInfo.u32OrMask = 0;
     869    maskInfo.u32NotMask = VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST;
     870    if (DeviceIoControl (gVBoxDriver, IOCTL_VBOXGUEST_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
     871    {
     872        DDCLOG(("VBoxService: DeviceIOControl(CtlMask - not) succeeded\n"));
     873    }
     874    else
     875    {
     876        dprintf(("VBoxService: DeviceIOControl(CtlMask) failed\n"));
     877    }
     878
     879    dprintf(("VBoxService: finished display change request thread\n"));
     880}
     881
    403882/**
    404883 * Window procedure for our tool window
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette