The ModuleHook Interface

The ModuleHook Interface is really nothing more than a !bangcommand with a special 
syntax. And it is relatively easy to add to existing code, depending on how many of 
its features you want to use.

!CallMeWhatYouWant <Userdata[0..N]> <future options> <Path\to\BoxFile.box> <current Box HWND>

I suggest that you use <Modulename>LsBoxHook as BangCommand name, but that's up to you.

Everything but the userdata string is generated by lsbox.

The <Userdata> strings are optional - they are only needed if you want to pass additional 
options from the *ModuleHook line in the box file. Label needs this to decide what Label should 
be loaded/docked to the Box. 

The <Path\to\BoxFile.box> string contains the full expanded path to the .box file. You 
can use this together with LiteStep's LoadRC LSAPI to load options from the box file.
RabidVWM is currently the only Module to do this.

The <current Box HWND> argument is the Box's HWND converted to string

It is important that you evaluate the options that are created by LsBox END of the 
string!!!! 
I have <future options> planned that will break your module's ModuleHook support if
you evaluate from the front!
Don't evaluate the Userdata string from the end for the same reason.

Sample Code

Tasks

This is the code i used for hooking Tasks. Since Tasks already had a DockToWindow 
option patching it for LsBox was easy - I just had to look at TasksDockToWindow and 
add my own bang for the Hook interface.


void TasksBoxHook(HWND caller, LPCTSTR szArgs)
{
  UNREFERENCED_PARAMETER(caller);

  char *handle = strrchr(szArgs,' ');
  if (handle) 
  {
    HWND hWnd = (HWND)atoi(handle+1);
	if (hWnd) 
	{
      if (hWnd != ts.DockWindow){
	    for (int i=0;i<numTasks;i++){
		  SetWindowLong(tasks[i].hwnd, GWL_STYLE, (GetWindowLong(tasks[i].hwnd, GWL_STYLE) &~ WS_POPUP)|WS_CHILD);
		  SetParent(tasks[i].hwnd, hWnd);
		  //This is a Bad idea under Win2k SP2 - don't ask me why.....
		  //SetWindowLong(tasks[i].hwnd, GWL_STYLE, (GetWindowLong(tasks[i].hwnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
		}
	    ts.DockWindow = hWnd;
      }
	}
  }
  return;
}

Well and that's really everything that is needed here - the way Tasks is build so that 
it doesn't have to handle the WM_DESTROY case.....

LsXcommand

The Bang really isn't any different from the Task HookBang - it just handles a second 
hidden state so the LsXcommand window only shows up when it is docked to a Box.
void BangBoxHook(HWND caller, const char *args)
{
  char *handle = strrchr(args,' ');
  if (handle) 
  {
    HWND boxwnd = (HWND)atoi(handle+1);
    if (boxwnd) 
	{
      lsboxed = TRUE;
	  if (boxwnd != GetParent(hWnd))
	  {
	    SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_POPUP)|WS_CHILD);
        SetParent(hWnd, boxwnd);
		//This is a Bad idea under Win2k SP2 - don't ask me why.....
	    // SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
		if (cs->WaitForBox && visible)
	    {
		  ShowWindow(hWnd, SW_SHOWNORMAL);
		  cs->WaitForBox = FALSE;
		}
	  }
	}
  }
  return;
}
Since LsBox will send a WM_DESTROY message to it's Child Windows once a box 
is destroyed we have to handle the WM_DESTROY Message so LsXcommmand isn't 
actually destroyed.
  case WM_DESTROY:
    if (lsboxed)
    {
	  cs->WaitForBox = TRUE;
	  visible = TRUE;
	  SetWindowLong(hWnd, GWL_STYLE, (GetWindowLong(hWnd, GWL_STYLE) &~ WS_CHILD)|WS_POPUP);
	  SetParent(hWnd, 0);
	  SetWindowPos(hWnd,HWND_TOP,cs->x,cs->y,0,0,SWP_NOSIZE|SWP_HIDEWINDOW);
	  lsboxed = FALSE;
	  return 0;
    }

Label

Label was the most difficult of the three Modules to patch since it actually 
used more than one window. AND it is written useing OOP. But aside from that
the only difference between the Label and the LsXcommand code is that it actually
uses an Userdata string to select the right Label 
void LsBoxHookBangCommand(HWND caller, const char *arguments)
{
	char labelName[MAX_LINE_LENGTH];
	LPCTSTR nextToken[MAX_LINE_LENGTH];

	GetToken(arguments,labelName,nextToken,false);

	//check if the label is already running
	Label *label = lookupLabel(labelName);

    if (label == 0) 
	{
		label = new Label(labelName);
		label->load(hInstance);
		labelList.insert(labelList.end(), label);
	}

	char *handle = strrchr(arguments,' ');

	if ((label != 0)&&(handle))
		{
			HWND boxWnd = (HWND)atoi(handle+1);
			if (boxWnd) 
			{
				label->setBox(boxWnd);
				label->show();
				label->update();
			}
		}
}
The WM_DESTROY case has to be handld, too.
	case WM_DESTROY:
	{
		if(box)
		{
			//hide or destroy is the Question - i take hide - blkhawk
			this->hide();
			this->setBox(0);

			//Uncomment these to destroy the Label when the parent box gets killed
			/*hWnd = 0;
			labelList.remove(this);
			delete this;*/
		} 

		return false;
	}

Why?

Well, frankly neither the *Module nor the *WharfModule Mode of LsBox really
do everything THEY NEED to do. *WharfMode is good for all old Modules THAT
haven't been updated in *years* or for new modules that only run in one 
instance at a time.  *ModuleMode was added by me to allow modules to have 
more than one window on a given box.
(i did this to allow LsSlider to be loaded into a box)

One limitation of *WharfMode remains; since the Modules are loaded by lsbox 
and the init and quit functions are modeled after the way *WharfMode works 
multiple windows over several boxes from one module are impossible to do.
(at least not without causeing crashes)

Along came a Module that People *wanted* to be loadable into multiple boxes 
(Label). I had patched the Label to be loadeable into a single box, but that
wasn't enough so Maduin added a simple interface that identified a box a label 
should be docked to by it's class and it's windowtitle. And it worked 
well enough at least until I switched to WinXP and noticed how good 
Alphatransparency can look. To allow boxes to be made transparent i had to 
unparent them from the Desktop window that caused them to show up in the 
Windows Taskmanager. I fixed this by changing the windowtitle to null.

I think you can see what that caused with Label... since i neither wanted to give 
up on Alphatrans nor wanted the boxes show up in TaskMan all the time i added some 
options that set the Window title again. i also tried to get both the label 
compability and the TaskHideing by adding a timed "TasksFlash" function.

But i wasn't satisfied by the solution because i felt that LsBox had become somewhat 
bloated and unstable because of it's bloatness. I thought about rewriting some 
functions to streamline the code a bit.
The long planned LsSlider rewrite was around the corner too and i wanted to add 
Label-style freedocking of Sliders to boxes, but i didn't quite wanted to do it
exactly like Maduin did......

And that's why i did the !ModuleHook mode