home *** CD-ROM | disk | FTP | other *** search
- //---------------------------------------------------------------------------
- // modblast.c
- //---------------------------------------------------------------------------
- // Contains control procedure for ModBlaster control
- //---------------------------------------------------------------------------
-
- #define NOCOMM
- #include <windows.h>
-
- #include <vbapi.h>
- #include <string.h>
- #define CTL_DATA
- #include "modblast.h"
-
- //---------------------------------------------------------------------------
- // Global Variables
- //---------------------------------------------------------------------------
- HANDLE hmodDLL;
- CONTROLSTUFF controls[MAX_MSGBLASTERS];
- HANDLE taskDevEnvironment = NULL;
-
-
- //---------------------------------------------------------------------------
- // Utility Functions - added by BJ 1/15/94
- //---------------------------------------------------------------------------
- WORD FAR PASCAL _export mbLoWord(DWORD dword)
- {
- return (WORD)dword;
- }
-
- WORD FAR PASCAL _export mbHiWord(DWORD dword)
- {
- return (WORD)(dword >> 16);
- }
-
- WORD FAR PASCAL _export mbGetControlIndex(HWND hwnd)
- {
- DWORD index;
- HCTL hCtl;
- if ((hCtl = VBGetHwndControl(hwnd)) &&
- (VBGetControlProperty(hCtl, IPROP_STD_INDEX, (LPVOID)&index) == 0))
- return (WORD)index;
- else
- return (WORD)-1;
- }
-
- ULONG FAR PASCAL _export mbSetControlFlags(HWND hwnd, ULONG mask, ULONG value)
- {
- return VBSetControlFlags(VBGetHwndControl(hwnd), mask, value);
- }
-
- //---------------------------------------------------------------------------
- // MsgBlaster Control Procedure
- //---------------------------------------------------------------------------
- LONG FAR PASCAL _export MsgBlasterCtlProc(HCTL hctl, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
- {
- switch (msg)
- {
-
- case WM_NCCREATE:
- {
- int i;
- // deref MsgBlaster control struct now - valid until we call VB procedure (BJ)
- PMSGBLASTER lpMsgBlaster = LpblastDEREF(hctl);
-
- // Look for an open slot in the array and save the hctl
- for(i = 0; i < MAX_MSGBLASTERS; i++)
- {
- if(controls[i].hctlMain == NULL)
- {
- controls[i].hctlMain = hctl;
- break;
- }
- }
-
- // If users are trying to use this many blasters, then they are
- // probably doing something wrong. Besides, using 25 blasters would
- // slow down the entire system
- if (i == MAX_MSGBLASTERS)
- {
- MessageBox(hwnd, "Too many message blasters", "Error!", MB_OK);
- return(0);
- }
-
- // make sure that the hWndTargets are zeroed out.
- lpMsgBlaster->hWndTarget = NULL;
-
- // initialize the passage var to pass msgs onto the origproc
- // after firing the event. This is the default behavior.
- // There was a bug here - replaced MAX_MSGBLASTERS with MAX_TRAPPABLEMSGS (BJ)
- for(i = 0; i < MAX_TRAPPABLEMSGS; i++)
- lpMsgBlaster->MsgPassage[i] = 1;
-
- VBSetControlProperty(hctl, IPROP_MSGBLASTER_ABOUTBOX,
- (LONG)(LPSTR)"Click on \"...\" for the About Box ---->");
-
- }
- break;
-
- case VBM_SETPROPERTY:
- switch(wp)
- {
- case IPROP_MSGBLASTER_HWNDTARGET:
- {
- int i, j;
-
- // we only process this message if we are in run mode
- if (VBGetMode() != MODE_DESIGN)
- {
- // deref MsgBlaster control struct now - valid until we call VB procedure (BJ)
- PMSGBLASTER lpMsgBlaster = LpblastDEREF(hctl);
-
- // find the next slot and save the hWndTarget
- for(i = 0; i < MAX_MSGBLASTERS; i++)
- {
- if(controls[i].hctlMain == hctl)
- {
- // Check to see if this blaster is already being
- // used to subclass a control
- // if it is, un-subclass it.
- // This could happen when the vb programmer changes
- // the target control at run time
- if(controls[i].hWndTarget) {
- UnSubClass(controls[i].hWndTarget,hctl);
- // initialize messages and passage when target changes (BJ)
- for(j = 0; j < MAX_TRAPPABLEMSGS; j++) {
- lpMsgBlaster->MsgList[j] = 0;
- lpMsgBlaster->MsgPassage[j] = 1;
- }
- }
-
- controls[i].hWndTarget = (HWND)lp;
- break;
- }
- }
-
- // sublcass the target control
- // only if target not == NULL (BJ)
- if ((HWND)lp != NULL && !FSubClass((HWND)lp))
- MessageBox(hwnd, "Unable to subclass control", "Error", MB_OK);
- }
- }
- return 0L;
-
- case IPROP_MSGBLASTER_MSGLIST:
- {
- // This is where we store the list of messages to trap
- // normally, the vb programmer will load this in the
- // form load event.
- LONG i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = lpDs->index[0].data;
-
- // I put an arbitrary limit on the number of messages
- // that could be trapped. My think is that they really shouldn't
- // be doing a lot of message processing in VB.
- if (i < 0 || i >= MAX_TRAPPABLEMSGS)
- return ERRBADINDEX;
-
- LpblastDEREF(hctl)->MsgList[i] = (UINT)lpDs->data;
- return 0L;
- }
-
- case IPROP_MSGBLASTER_MSGPASSAGE:
- {
- // This property determines how each message will be processed
- // There are 3 valid possibilities; -1, 0, 1.
- // -1 means preprocess the message. This means pass it on to the
- // VBDefControlProc first
- // 0 means eat the message. i.e. never pass it on
- // 1 means pass the message on after firing the event
- // This is the default.
- LONG i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = lpDs->index[0].data;
- if (i < 0 || i >= MAX_TRAPPABLEMSGS)
- return ERRBADINDEX;
-
- LpblastDEREF(hctl)->MsgPassage[i] = (SHORT)lpDs->data;
- return 0L;
- }
-
- }
- break;
-
-
- case VBM_GETPROPERTY:
- switch(wp)
- {
- case IPROP_MSGBLASTER_MSGLIST:
- {
- LONG i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = lpDs->index[0].data;
- if (i < 0 || i >= MAX_TRAPPABLEMSGS)
- return ERRBADINDEX;
-
- lpDs->data = (LONG)LpblastDEREF(hctl)->MsgList[i];
- return 0L;
- }
- case IPROP_MSGBLASTER_MSGPASSAGE:
- {
- LONG i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = lpDs->index[0].data;
- if (i < 0 || i >= MAX_TRAPPABLEMSGS)
- return ERRBADINDEX;
-
- lpDs->data = LpblastDEREF(hctl)->MsgPassage[i];
- return 0L;
- }
- case IPROP_MSGBLASTER_HWNDTARGET:
- {
- LONG i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = lpDs->index[0].data;
- if (i < 0 || i >= MAX_TRAPPABLEMSGS)
- return ERRBADINDEX;
-
- lpDs->data = LpblastDEREF(hctl)->hWndTarget;
- return 0L;
- }
-
- } // end of switch
- break;
-
- case VBM_INITPROPPOPUP:
- if(wp == IPROP_MSGBLASTER_ABOUTBOX)
- {
- HWND hwndList = (HWND)LOWORD(lp);
- return (LONG)HwndInitAboutBox();
- }
- break;
- case IPROP_MSGBLASTER_ABOUTBOX:
- // force a repaint
- InvalidateRect(hwnd, NULL, FALSE);
- break;
-
- case WM_NCDESTROY:
- if(LpblastDEREF(hctl)->hszAbout)
- VBDestroyHsz(LpblastDEREF(hctl)->hszAbout);
- break;
-
- case WM_DESTROY:
- {
- int i;
-
- // find which control we are dealing with
- for(i = 0; i < MAX_MSGBLASTERS; i++)
- if(controls[i].hctlMain == hctl)
- break;
-
- // ****>>> We *must* unsubclass the hwndTarget when
- // this hctl goes away!
- UnSubClass(controls[i].hWndTarget,hctl);
-
- controls[i].hWndTarget = NULL;
- controls[i].hctlMain = NULL;
- }
- break;
- }
- return VBDefControlProc(hctl, hwnd, msg, wp, lp);
- }
-
-
- //---------------------------------------------------------------------------
- // Sub class routine for target control window proc.
- //---------------------------------------------------------------------------
- LONG FAR PASCAL _export SubClassProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
- {
- LONG rc;
- int i, j;
- UINT m;
- HCTL hctlMain;
-
- // find the correct hctlMain
- // I could have called FindhctlMain, but I wanted to avoid the overhead
- // we need the most speed we can get in this routine.
- for(j = 0; j < MAX_MSGBLASTERS; j++)
- if(controls[j].hWndTarget == hwnd)
- break;
-
- // The first part of this if is a sanity check
- if(j == MAX_MSGBLASTERS)
- MessageBox(hwnd, "Big trouble. We're gonna die.", "TROUBLE", MB_OK);
- else
- hctlMain = controls[j].hctlMain;
-
- for (i=0; i < MAX_TRAPPABLEMSGS; i++)
- {
-
- // Get out of the loop if hctlMain is no longer valid
- // ****>>> Since you fire an event, it is possible for hctlMain to
- // disappear during that event, so you must check to see if hctlMain
- // is still non-NULL. This is also why I added the NULLing out of
- // this variable to the WM_DESTROY case.
- if (!hctlMain)
- break;
-
- // ****>>> Firing an event invalidates pMsgBlaster!!!!
- // You MUST deref it each time through this loop!!!
- m = LpblastDEREF(hctlMain)->MsgList[i];
-
- // Get out of the loop if no more messages
- if (!m)
- break;
-
- if (msg == m)
- {
- int eat;
-
- // now that we have a hit, determine if we should pass the
- // msg on to the orig proc first, last or
- // do we eat the msg entirely
- eat = LpblastDEREF(hctlMain)->MsgPassage[i];
- switch(eat)
- {
- case -1: // call the orig proc first
- rc = CallWindowProc(LpblastDEREF(hctlMain)->lpfnOrigProc,
- hwnd, msg, wp, lp);
- rc = FireMessage(hctlMain, msg, wp, lp, rc);
- if (msg == WM_DESTROY)
- {
- MessageBox(hwnd,
- "Can't call original proc with WM_DESTROY prior to firing event.",
- "Error", MB_OK);
- break;
- }
- return rc;
-
- case 0: // eat the message
- rc = FireMessage(hctlMain, msg, wp, lp, rc);
- if (msg == WM_DESTROY)
- {
- MessageBox(hwnd,
- "Can't eat WM_DESTROY message.",
- "Error", MB_OK);
- break;
- }
- return rc;
-
- case 1: // pass it on afterward
- rc = FireMessage(hctlMain, msg, wp, lp, rc);
- break;
-
- case 2: // pass it on afterward - MAYBE - BJ
- rc = FireMessage(hctlMain, msg, wp, lp, rc);
- // if the return code is 0 then the message has been handled - BJ
- if (rc == 0) return rc;
- break;
-
- default:
- MessageBox(hwnd,
- "Default case in passage test. Should never get.",
- "Error", MB_OK);
- break;
- }
- }
- }
-
- // Call the original Window Procedure
- rc = CallWindowProc(LpblastDEREF(hctlMain)->lpfnOrigProc, hwnd, msg, wp, lp);
-
- // ****>>> Strictly speaking, it is not necessary to unsubclass this window
- // since it is being destroyed, but UnSubClass() does *need* to reset the
- // necessary global variables, and modular programming says we shouldn't
- // do that from here, when UnSubClass() can do that for us...
- if (msg == WM_DESTROY)
- UnSubClass(hwnd, hctlMain);
-
- return rc;
- }
-
-
- //--------------------------------------------------------------------------
- // Fire the msg event
- //--------------------------------------------------------------------------
- LONG NEAR FireMessage(HCTL hctl, UINT m, WPARAM wp, LPARAM lp, LONG rc)
- {
- MSGPARAMS p;
- UINT mval = m;
-
- p.MsgVal = &mval;
- p.wParam = ℘
- p.lParam = &lp;
- p.lRetVal= &rc;
-
- VBFireEvent(hctl, IEVENT_MSGBLASTER_MSG, &p);
- return rc;
- }
-
-
- //---------------------------------------------------------------------------
- // Register custom control. This routine is called by VB when the custom
- // control DLL is loaded for use.
- //---------------------------------------------------------------------------
- BOOL FAR PASCAL _export VBINITCC(USHORT usVersion, BOOL fRuntime)
- {
- // Avoid warnings on unused (but required) formal parameters
- fRuntime = fRuntime;
-
- // Register control(s)
- if (usVersion < VB200_VERSION)
- return FALSE;
-
- // Register popup class if this is from the development environment.
- if (!fRuntime)
- {
- WNDCLASS class;
-
- class.style = 0;
- class.lpfnWndProc = AboutBoxProc;
- class.cbClsExtra = 0;
- class.cbWndExtra = 0;
- class.hInstance = hmodDLL;
- class.hIcon = NULL;
- class.hCursor = NULL;
- class.hbrBackground = NULL;
- class.lpszMenuName = NULL;
- class.lpszClassName = CLASS_ABOUTBOX;
-
- if (!RegisterClass(&class))
- return FALSE;
-
- // Remember the task associated with the development environment
- taskDevEnvironment = GetCurrentTask();
-
- }
-
-
- return VBRegisterModel(hmodDLL, &modelMsgBlaster);
- }
-
-
- //---------------------------------------------------------------------------
- // Provide custom control model information to host environment.
- //---------------------------------------------------------------------------
- LPMODELINFO FAR PASCAL _export VBGetModelInfo(USHORT usVersion)
- {
- if (usVersion < VB200_VERSION)
- return NULL;
- else
- return &modelinfoMsgBlaster;
- }
-
-
- //---------------------------------------------------------------------------
- // Initialize library. This routine is called when the first client loads
- // the DLL.
- //---------------------------------------------------------------------------
- int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
- {
- // Avoid warnings on unused (but required) formal parameters
- wDataSeg = wDataSeg;
- cbHeapSize = cbHeapSize;
- lpszCmdLine = lpszCmdLine;
-
- hmodDLL = hModule;
-
- return 1;
- }
-
- //---------------------------------------------------------------------------
- // Unregister the property popup , if this unload
- // is from the development environment.
- //---------------------------------------------------------------------------
-
- VOID FAR PASCAL _export VBTERMCC()
- {
- // Unregister popup class if this is from the development environment
- if (taskDevEnvironment == GetCurrentTask())
- {
- UnregisterClass(CLASS_ABOUTBOX, hmodDLL);
- taskDevEnvironment = NULL;
- }
- }
-
- //---------------------------------------------------------------------------
- // WEP
- //---------------------------------------------------------------------------
- // C7 and QCWIN provide default a WEP:
- //---------------------------------------------------------------------------
- #if (_MSC_VER < 610)
-
- int FAR PASCAL WEP(int fSystemExit);
-
- //---------------------------------------------------------------------------
- // For Windows 3.0 it is recommended that the WEP function reside in a
- // FIXED code segment and be exported as RESIDENTNAME. This is
- // accomplished using the alloc_text pragma below and the related EXPORTS
- // and SEGMENTS directives in the .DEF file.
- //
- // Read the comments section documenting the WEP function in the Windows
- // 3.1 SDK "Programmers Reference, Volume 2: Functions" before placing
- // any additional code in the WEP routine for a Windows 3.0 DLL.
- //---------------------------------------------------------------------------
- #pragma alloc_text(WEP_TEXT,WEP)
-
- //---------------------------------------------------------------------------
- // Performs cleanup tasks when the DLL is unloaded. WEP() is
- // called automatically by Windows when the DLL is unloaded (no
- // remaining tasks still have the DLL loaded). It is strongly
- // recommended that a DLL have a WEP() function, even if it does
- // nothing but returns success (1), as in this example.
- //---------------------------------------------------------------------------
- int FAR PASCAL WEP(int fSystemExit)
- {
- // Avoid warnings on unused (but required) formal parameters
- fSystemExit = fSystemExit;
-
- return 1;
- }
- #endif
-
- //---------------------------------------------------------------------------
- // ****>>> Aux fn to subclass only valid windows, and only when we're not
- // already subclassing a window. Takes care of setting up and maintaining
- // the two necessary globals. Returns TRUE if it actually subclassed, FALSE
- // otherwise.
- //---------------------------------------------------------------------------
- BOOL FSubClass(HWND hwnd)
- {
- int i;
- HCTL hctlMain;
-
- if (!IsWindow(hwnd))
- return(FALSE); // Invalid hwnd parameter
-
- hctlMain = FindhctlMain(hwnd);
- if(!hctlMain)
- return(FALSE);
-
-
- if(i < MAX_MSGBLASTERS)
- if (LpblastDEREF(hctlMain)->lpfnOrigProc)
- return FALSE; // Already are subclassing
-
- LpblastDEREF(hctlMain)->lpfnOrigProc =
- (FARPROC)SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)SubClassProc);
-
- return TRUE;
- }
-
-
- //---------------------------------------------------------------------------
- // ****>>> Undo what FSubClass() did. Takes car of clearing out the two
- // necessary globals.
- //---------------------------------------------------------------------------
- VOID UnSubClass(HWND hWndTarget, HCTL hctlMain)
- {
- PMSGBLASTER pMsgBlaster;
-
- pMsgBlaster = LpblastDEREF(hctlMain);
-
- // Make sure we're actually subclassing before we undo it. if (pMsgBlaster->lpfnOrigProc)
- {
- SetWindowLong(hWndTarget, GWL_WNDPROC, (LONG)pMsgBlaster->lpfnOrigProc);
- pMsgBlaster->lpfnOrigProc = 0L;
- pMsgBlaster->hWndTarget = NULL;
- }
- }
-
- HCTL FindhctlMain(HWND hWnd)
- {
- int j;
-
- // find the correct hctlMain
- for(j = 0; j < MAX_MSGBLASTERS; j++)
- {
- if(controls[j].hWndTarget == hWnd)
- break;
- }
-
- return(j == MAX_MSGBLASTERS ? NULL:controls[j].hctlMain);
- }
-
-
- //---------------------------------------------------------------------------
- // Create our property popup-window. Since we want to put up a dialog, this
- // window never becomes visible. Instead, when asked to become visible, it
- // will post a message to itself, remining it to put up our dialog.
- //
- // NOTE: May return NULL!
- //---------------------------------------------------------------------------
- HWND NEAR HwndInitAboutBox(VOID)
- {
- return(CreateWindow(CLASS_ABOUTBOX, NULL, WS_POPUP,
- 0, 0, 0, 0, NULL, NULL,
- hmodDLL, NULL));
- }
-
- //---------------------------------------------------------------------------
- // We asked to show ourself, remain invisible and post a CM_OPENABOUT to
- // ourself. When we receive this message, open the dialog box.
- //---------------------------------------------------------------------------
- LONG _export FAR PASCAL AboutBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
-
- switch (msg)
- {
- case WM_SHOWWINDOW:
- if (wParam)
- {
- PostMessage(hWnd, CM_OPENABOUTBOX, 0, 0L);
- return 0L;
- }
- break;
-
- case CM_OPENABOUTBOX:
- VBDialogBoxParam(hmodDLL, "AboutBox", (FARPROC)AboutBoxDlgProc, 0L);
- return 0L;
- }
-
- return DefWindowProc(hWnd, msg, wParam, lParam);
- }
-
-
- //---------------------------------------------------------------------------
- // The Dialog Procedure for the AboutBox dialog.
- //---------------------------------------------------------------------------
- BOOL FAR PASCAL _export AboutBoxDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch (msg)
- {
- case WM_INITDIALOG:
- {
- RECT rect;
- int nx, ny; // New x and y
- int width, height;
-
- // Position dialog so it looks nice:
- GetWindowRect(hDlg, &rect);
- width = rect.right - rect.left;
- height = rect.bottom - rect.top;
- nx = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
- ny = (GetSystemMetrics(SM_CYSCREEN) - height) / 3;
- MoveWindow(hDlg, nx, ny, width, height, FALSE);
- return TRUE;
- }
-
- case WM_COMMAND:
- if(wParam == IDOK)
- {
- EndDialog(hDlg, TRUE);
- return TRUE;
- }
- }
- return FALSE;
- }
-
- //-- EOF -------------------------------------------------------------------
-