Important alert: (current site time 4/17/2014 2:42:14 AM EDT)
 

winzip icon

Fastest, safest subclasser, no module!

Email
Submitted on: 7/20/2002 8:53:07 AM
By: Paul Caton 
Level: Advanced
User Rating: By 85 Users
Compatibility:
Views: 33645
 
     *** Update: See my new submission here... http://www.exhedra.com/vb/scripts/ShowCode.asp?txtCodeId=42918&lngWId=1 If you do want the original zip then email me at Paul_Caton@hotmail.com *** cSuperClass.cls is i believe the fastest, safest compiled in window subclasser around. Speed: The WndProc is executed entirely in run-time dynamically generated machine code. The class only calls back on messages that you choose. Safety: So far I've not been able to crash the IDE by pressing the end button or with the End statement. Flexible: The programmer can choose between filtered mode (fastest) and all messages mode. In filtered mode the user decides which windows messages they're interested in and can individually specify whether the message is to callback after default processing or before. Before mode additionally allows the programmer to specify whether or not default processing is to be performed subsequently. No module: AFAIK this is the only subclasser ever to eschew the use of a module. So how do I get the address of the WndProc routine? Simple, the dynamically generated machine code lives in a byte array; you can get its address with the undocumented VarPtr function. The real magic in cSuperClass.cls is getting from the WndProc to the callback interface routine using ObjPtr against the owning Form/UserControl, see the assembler .asm model file included in the zip. Speaking of which... it may well be the case that my assembler is sub-optimal. Any experts out there willing to take a look? I thought I had a nifty/dirty stack trick working for a while but it didn't pan out. Should work with VB5 if VarPtr & ObjPtr were in that release? Sample project included. Regards.
 
winzip iconDownload code

Note: Due to the size or complexity of this submission, the author has submitted it as a .zip file to shorten your download time. Afterdownloading it, you will need a program like Winzip to decompress it.Virus note:All files are scanned once-a-day by Planet Source Code for viruses, but new viruses come out every day, so no prevention program can catch 100% of them. For your own safety, please:
  1. Re-scan downloaded files using your personal virus checker before using it.
  2. NEVER, EVER run compiled files (.exe's, .ocx's, .dll's etc.)--only run source code.

If you don't have a virus scanner, you can get one at many places on the net including:McAfee.com

 
Terms of Agreement:   
By using this code, you agree to the following terms...   
  1. You may use this code in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this code (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this code from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the code or code's description.


Other 13 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this code (in the Advanced category)?
(The code with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments

7/20/2002 10:12:24 AMPaul Caton

I'm more interested in widespread distribution than globes, though obviously votes will help in that regard. So feel free to post the zip to the four winds, claim it as your own, whatever... So long as the innovative techniques become more widely known and exploited then we all should benefit.
(If this comment was disrespectful, please report it.)

 
7/20/2002 1:41:51 PMCoding Genius

Impressive. I've been programming for about 4 years now. But I still don't see...Whereabouts did the asm come into it?
(If this comment was disrespectful, please report it.)

 
7/20/2002 1:42:44 PMCoding Genius

5 globes by the way :)
(If this comment was disrespectful, please report it.)

 
7/20/2002 4:33:19 PMPaul Caton

Thanks :) - Not sure what you're asking, but i'll take a stab at... What are the two asm files doing in the zip? First I wrote the asm source of how, approx, the Filtered mode and All Message mode WndProc's would work; then I assembled and linked those sources into exe's. That done I loaded the exe's up into a hex editor so i could see the bytes for each asm instruction and then copied them into Const strings in hex notation. Look at Const WNDPROC_ALL and compare with the equivalent asm file, that one is the easiest to figure because it's short and linear, no jumps, just two Call's, the calls to WndProcPrev and iSubClass_After. So, what you see in that string is a hex representation of the op-code bytes that the CPU will execute, save for two 8 char sequences that are patched at run-time with the with the actual memory addresses. Hope this helps if not ask again.
(If this comment was disrespectful, please report it.)

 
7/20/2002 4:54:47 PMRobert Rayment

This is beyond anything that I would attempt, but you may be interested in some code on www.vbdotcom.com where the LoadLibray api is used to pick up the entry address of an api declared in VB. This can then be inserted into the asm binary after the point where the api parameters are pushed on the stack. This potentially can avoid the need for the WindProc.inc Masm32 library. I haven't worked all this out yet and apologise if this is all known by you. *****
(If this comment was disrespectful, please report it.)

 
7/21/2002 5:36:18 AMAndrea Batina

Thanks for this great submission!

5 globes
(If this comment was disrespectful, please report it.)

 
7/21/2002 6:02:54 AMPaul Caton

Thanks Robert for the feedback and globes. My original thought was that I'd use LoadLibrary/GetProcAddress to get the memory address of the CallWindowProc API routine so as to call the previous WndProc but then in a Damascean flash of light I thought $!&% I've got it's address anyway, I might as well call it directly without the overhead Duh! I must say though that if anyone's interested in calling arbitary assembler routines in a byte buffer CallWindowProc is the way to go... It takes an address as the first parameter and allows you to pass four data arguments to your code. Whoo-hoo. If anyone's interested I can submit an example.
(If this comment was disrespectful, please report it.)

 
7/21/2002 6:47:13 AMPaul Caton

Thanks Andrea, much appreciated. Tell you what folks... I'm seriously suprised, 11 x 5 globes in less than 24 hours! I would never have guessed that a submission this esoteric would attract that kind of support. If I'd known, I would've submitted at the start of a month. Still, should this make it up the table into prize land (unlikely at this late stage) I promise that i'll forward the prize to the contributor of the best feedback.
(If this comment was disrespectful, please report it.)

 
7/21/2002 7:17:28 AMMartin

Excellent, innovative, glad you uploaded this 'class'class here. A crash proof subclassing class should get more than 5/5. Keep up the good work and thanks for sharing.
(If this comment was disrespectful, please report it.)

 
7/21/2002 7:32:03 AMOzan Yasin Dogan

you did a well job Paul, excellent solution for subclassing.. many thanks
(If this comment was disrespectful, please report it.)

 
7/21/2002 8:53:04 AMGerco Dries

This is truly excellent. I had thought of using assembly to implement a wndProc, but I didn't really see the benefit, apart from my lack of experience with ASM in Win32.

I thought my latest submission was good, getting 9 "Excellent" ratings in 48 hours, but I was wrong, this is even better, WAY better.
(If this comment was disrespectful, please report it.)

 
7/21/2002 1:01:39 PMS.Y. Kim

Great excellent. Thank you.
I'll use your code when I develope
projects requiring subclassing.
(If this comment was disrespectful, please report it.)

 
7/21/2002 6:23:30 PMPaul Caton

Gerco, until six weeks ago I hadn't touched assembler since the eighties on an Atari ST (Motorola 68000k) - At that time I took a quick look at the X86 nightmare architecture and promptly decided to learn C. It's a lot easier now with the flat memory model and the extended registers. There's plenty of free assemblers out there, give it a go, suprise yourself, I know I did.

Thanks go out to you and the other recent voters. Now up to #4, can't quite believe it, just 36 hours!
(If this comment was disrespectful, please report it.)

 
7/21/2002 7:39:29 PMJohn Sugas

Excellent Paul.... Thanks for uploading. It is very rare to find something done with VB+Asm on PSC or the web that is this unique (and hardcore). The two that come to mind are Robert Rayment's CallWindowProc stuff and CompileController by John Chamberlain (Was in VBPJ a few years back). Thanks again....
(If this comment was disrespectful, please report it.)

 
7/22/2002 3:09:43 AMMichel Posseth

hey !!

i just thought $%#@$%$ i know this code !!

but i was glad to see that it was from the same person !!

i saw your code before on http://www.vb2themax.com/FileBank.asp?PageID=FileBank

( Francesco Rulessssss the vb world :-)

by the way you get five from me :-)

that code is superb !! great !! Amazing !! never seen something like it
(If this comment was disrespectful, please report it.)

 
7/22/2002 3:36:05 AMPaul Caton

Thanks Michael, yes it's been up on Francesco's site for a few weeks. I just wanted to see if any issues popped up from it's exposure there before laying it on the masses that trawl thru here. It's still worth downloading from PSC though as i've cleaned up the patching slightly, nothing functional has changed though.
(If this comment was disrespectful, please report it.)

 
7/22/2002 3:38:44 AMPaul Caton

Say gasha you've spoilt my 100% voting record. WHAAAAAAAA.... If you've got any complaints/criticisms/suggestions I'd much rather hear them than not.
(If this comment was disrespectful, please report it.)

 
7/22/2002 10:30:30 AMpolaris

Very uncredible
wonderful job how can u perform a so
complicated task, in add u use MASM32 asm code GREAT
ONE QUESTION IT IS POSIBLE TO MAKE ASMLIB with MASM32 to make Graphics routines for a Software3d engine with VB+MASM32
Or a lib for fast image processing with callBack
I want VB PSC people to think about the innovation of that code
Definitly GOOD JOB
Polaris
(If this comment was disrespectful, please report it.)

 
7/22/2002 11:31:34 AMElias Barbosa

Very cool! Way over my head, though! :)

I developed an ActiveX Control that I posted on PSC that uses subclassing. One of the worse problems that I encountered while developing this control was that I always crashed Visual Basic if I used the End statement before unloading the control.

If your submission works the way you claimed, it will resolve my problem. I will try to implement it into my control. However, I am not sure if I am skilled enough to do so!! :)

I will give you my best vote, anyway! :)

(If this comment was disrespectful, please report it.)

 
7/22/2002 12:11:18 PMPaul Caton

Polaris: thanks. If I understand you correctly, sure it's possible but i wouldn't want to attempt it myself.

I thought I saw an entry near the top of the all time list that was a graphics dll where the author was offering both VB and C++ source code if that helps.
(If this comment was disrespectful, please report it.)

 
7/22/2002 12:25:45 PMPaul Caton

Elias, I always avoid the end statement like the plague. There's almost always a better approach.

The code itself is a little out-there but the interface is straight-forward. Follow the code in frmMain, you don't need any kind of understanding about what's happening in cSuperClass.cls to be able to use it effectively.

Most times out of ten you'll probably be using after default processing mode.

If you want to let me know publicly or privately what windows messages it is that you're after I can probably point you in the right direction.

The subclasser has been up on vb2themax for a few weeks now and with 900+ downloads from here since saturday i'm getting reasonably comfortable re its resilience.

That's not to say it's impossible to crash. If someone did a CopyMemory for example across the op-code buffer or something mad in response to the wrong windows message then all bets are off!

Thanks for the vote -Paul
(If this comment was disrespectful, please report it.)

 
7/22/2002 12:54:25 PMPaul Caton

Elias, a further thought... some people get a little intimidated by the Implements statement. The MSDN help isn't much either (help that is). But really there's nothing much to think about. As soon as you add the Implements iSuperClass statement you'll see an entry in the left combo at the top of your code window for iSuperClass. Select that and it'll build you the iSuperClass_After implementation interface, then select the before version in the right hand combo. You must implement both, though most times the *before* interface is empty, contains no code.

Why use it rather than an event? Implemented interfaces are somewhere between 6 and 10 times faster! As in effect they are pretty much (in concept) like a method call. Whereas an event... well that's something else entirely. BUT! same result.
(If this comment was disrespectful, please report it.)

 
7/22/2002 1:32:47 PMPaul Caton

Just got this in my email... It wont hurt to repeat it one more time

Hi, Paul

I have one problem about yours SubClass Class which you uploaded on Planet Source Code.
I'm trying to implement iSuperClass in UserControl with

Implements iSuperClass

but I have got an error: "Object module needs to implement 'Before' for interface 'iSuperClass'. ". I have set cSuperClass to Private, and iSuperClass to PublicNotCreatable, but I still have problem.

Please help me!

Thanks in forward

(If this comment was disrespectful, please report it.)

 
7/22/2002 1:35:00 PMPaul Caton

Reply:
It'll cost you your vote, if you haven't already ;-)

What the implements statement means here is that you guarantee to implement ALL the methods in the iSuperClass.cls

Go to the drop-down combo box at the top left of your code Window
Select iSuperClass. It will take you to the iSuperClass_After routine.
Now in the right hand combo box select the before event It will create the routine.
Don't worry if there's no code to go in there, but it must exist.

This'll teach me to leave my Email address in the source code. A lifetime of consumer support.

Good luck, next time ask me at PSC then others can benefit.

-Paul
(If this comment was disrespectful, please report it.)

 
7/22/2002 3:16:53 PMVlad Vissoultchev

paul: do a general purpose class that implements iSuperClass, contains an instance of cSuperClass and exposes its methods but raises events instead. should be ~30 lines :-))

btw, do you know what superclassing usually refers to?

btw, do you know what term "thunk[ing]" is used for? :-))

final note, you know that "REP SCASW" is quit fast. i mean you are using code (couple of instruction) as data and vice versa. on AddMessage better fill a lookup table and "scas" it then use ECX as an index etc. etc.

HTH,

</wqw>
p.s. i like it -- a lot!
(If this comment was disrespectful, please report it.)

 
7/22/2002 4:32:01 PMPaul Caton

Oh no, it's Vlad the impaler, now i'm in trouble...

Cool idea, re general pupose class, would certainly help with the Implements challenged. As an update do you think?

But what do I call it ? ;-)

Ahem, a SuperClass *usually* refers to an aggregate class that errrrr agregates other classes into a single entity... Ok, I'll state the obvious - Just as you suggested above.

Thunk - originally I think to refer to a translation layer between 16 and 32bit, but I think more generally as a seemless translation from somefink to anotherfink. Like wot i fink ms will do with the dll's we know and love. Make em thunks into .NET

btw. Why do you ask? I'm just an 'umble self taught code-slinger (tugs at forelock)

Continued below...
(If this comment was disrespectful, please report it.)

 
7/22/2002 4:36:04 PMPaul Caton

When I said I picked up a copy of MASM32 six weeks ago (upstream) I wasn't joking. REP I recognise as part of a repeat instruction but my asm stuff is on another computer. Give me a day to look it up and i'll get back to you if i'm still in the dark.

Maybe I could discuss my dirty stack trick with you.

You may've noticed further up the page that stated that should I win a prize that I'd donate it to the best feedback as I was more interested in wide distribution than globes. Well you're clearly way ahead in that department. So you could get two!

You like it a lot but no cigar! - OK, me first.
(If this comment was disrespectful, please report it.)

 
7/22/2002 5:27:39 PMS.Y. Kim

Yesterday, I replaced my previous subclassing codes with yours.
All of them works fine!
I also like the Implements method.
When I used your code with a usercontrol, it seems that your codes
give more redability and easier control.

Thanks! Great Code!
(If this comment was disrespectful, please report it.)

 
7/22/2002 6:21:11 PMVlad Vissoultchev

"Maybe I could discuss my dirty stack trick with you." -- i like it too, at least saves instructions. the problem with it is that *usually* in the before method i would prefer the arguments to be ByRef as to be able to modify current message and w/lparams (!) but this can easily be achieved by consuming the message a subsequent call to CallWindowProc(orig_wnd_procm, etc)

well, people are obviously afraid of "Implementing" anything, that's why i thought of late-bounding but alas, the slicky stack trick would not work. so we need a kind of proxy, kind of the events proxy i spoke before.

my experience: yes it seems immune to "End" in the IDE but breakpointing in the before/after [implemented] methods still crashes poor VB :-)) maybe you should put a reentrancy check in the asm and spare the debugger another function entry while in break mode, instead procede normal processing

just my $.02

</wqw>
(If this comment was disrespectful, please report it.)

 
7/22/2002 7:44:45 PMPaul Caton

Vlad,

I've responded in detail off line as it's getting cumbersome in this text box.

Has anybody else, and i'm suprised that I haven't heard, had any issues with breakpoints in the implemented subs?
(If this comment was disrespectful, please report it.)

 
7/22/2002 7:58:02 PMPaul Caton

S.Y. Glad to hear... probably because it is faster than a regular subclasser. Plus Implements can be up to 10 times quicker than an event.

And finally, IIRC new mouse messages, for example, will eat older mouse messages that haven't yet been pulled out of the message queue and dispatched to the WndProc - For what is the point in an application being told that mouse at x,y when the data is already out of date. IE the faster they are processed the more you'll receive. This is why I chose to focus on mouse messages in the example.

If anyone knows better i'm sure we'll be informed.
(If this comment was disrespectful, please report it.)

 
7/24/2002 5:38:19 AMPaul Caton

Vlad, took a look at REP SCASW, i'd need 2 tables (before/after), or possibly 1 if you analyze the users requests and construct accordingly. Might be worth it if the user was adding a significant number of msgs, but that wont be the majority situation. Also considered a 228byte 2bit/entry lookup covering msgs up to WM_PENLAST or a straight byte/entry lookup - with fallback processing for msgs outside the range. So many options, so little time.
Wrote asm for re-entry, but first I need to be sure that the VB runtime WndProc isn't calling DispatchMessage for its own devious purposes, otherwise msgs could be masked from the user in after mode. Perhaps you could tell me if this is a silly^ notion?
Wrote the cSuperClass event proxy, will update this weekend.

-Paul

^At this point i used the word st*pid, input rejected, inapropriate language, had to re-type from scratch. BAH!
(If this comment was disrespectful, please report it.)

 
7/27/2002 10:01:12 AMWalter Brebels

Great code, 5 from me
(If this comment was disrespectful, please report it.)

 
7/27/2002 11:44:49 PMMark Hunter

Oustanding.

I've been looking at this code for hours, and this is the best thing I've seen here, bar none. A definite fiver.

Paul, any idea how hard it would be to add a "RemoveMsg" call to complete the class? I assume that it would have to remove bytes from the ASM to unfilter that message.

Right now the only way to remove a message is to call .Unsubclass, followed by .AddMsg calls to all of the WM_ messages *except* for the one that was to be removed.

Trust me, if I could add that in, I would, and I would never be without this in any of my projects.

Thanks for a great job!
(If this comment was disrespectful, please report it.)

 
7/28/2002 10:16:16 AMPaul Caton

Mark, thanks, that request would be pretty easy to implement. Either a little jump to the next test or just overwrite with nop's (no operation) but if you don't mind i'll leave it till version 2 which I hope to get out within the next month or so (very, very, busy) I want to leave it til then because the job will be even easier at that time as I'll be deploying the SCASW op to scan a table rather than the series of 'if then's' that I'm using at the moment.

I guess my thought at the time for leaving that functionality out was that users would just ignore the message in the implemented interfaces. User wants, user gets (if it's reasonable)

regards -Paul
(If this comment was disrespectful, please report it.)

 
7/29/2002 8:54:19 AMDaniel Pramel

Wow, i don't understand any assembler but your code motivated me to search for the old asm-books in my fathers house :-)
Excellent code and i have to be afraid that you could be placed higher in the all time hall of fame than me *gg* (place 8 remotecontrolcode). Anyways... i HAVE to vote with ***** and you got my HIGH respect ...
greetings from germany -Daniel-
(If this comment was disrespectful, please report it.)

 
7/29/2002 9:00:40 AMPaul Caton

Thanks Daniel, very selfless of you.

(If this comment was disrespectful, please report it.)

 
7/30/2002 7:37:51 PMFred.Cpp

Excellent, It's the Smartest solution for Subclassing I've seen ;)
*****
(If this comment was disrespectful, please report it.)

 
7/31/2002 8:54:43 AMTanerax

Excellent Way to do subclassing...
(If this comment was disrespectful, please report it.)

 
9/27/2002 5:48:32 PM

very good. Excellent.
(If this comment was disrespectful, please report it.)

 
10/9/2002 4:11:33 PMmindopening

Awesome. Implementing in a DLL to be used in other dlls. Will tell you how it wworks
(If this comment was disrespectful, please report it.)

 
10/14/2002 8:00:41 AM

no comments for a while.. =/
any updates?
i wish to see more ideas from you.

*bored with currant stuff on psc* =Pp
(If this comment was disrespectful, please report it.)

 
10/21/2002 7:28:17 AMEdwin Vermeer

Hi, I just wanted to inform you that I used your great SuperClass for handeling a winsock connection (client and server) I published it here:
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=39939&lngWI d=1

(If this comment was disrespectful, please report it.)

 
11/21/2002 12:34:50 AM

i love this thing, i'd like to know when you plan on releasing version 2? =D cant wait!
(If this comment was disrespectful, please report it.)

 
12/4/2002 5:42:14 AMCoding Genius

Hey, was digging around for a subclasser and I remembered this one again. I have a problem this time though. I tried it on a Win 98 machine and I got an overflow error in the PatchOffset of cSuperClass:

PCode = 6454196
nOffset = 62
WndProcPrev = -2144912908 (I suspect this)

I really need to get this working. Any help would be greatly appreciated bud.


(If this comment was disrespectful, please report it.)

 
12/13/2002 3:13:14 PM

Can't seem to download, there seems to be a problem!
(If this comment was disrespectful, please report it.)

 
12/16/2002 1:01:15 AMAdam

machine code hey? Why don't you just program it using binary?
(If this comment was disrespectful, please report it.)

 
1/15/2003 11:15:04 AM

There's a problem to download the code..
(If this comment was disrespectful, please report it.)

 
1/20/2003 11:25:02 AM

Unable to download this code from the download link!
(If this comment was disrespectful, please report it.)

 
5/24/2003 12:24:52 AMNick B

Good work, nice to see this kind of work in this 'forum'
(If this comment was disrespectful, please report it.)

 
10/1/2003 12:30:30 PM

Excellent piece of work, got my top mark.

Thick as I am, how does one subclass more than one window (e.g. main form AND, say a richtextbox for mouse messages .. seem to miss the plot .. the crashes give the game away!!

Thanks
(If this comment was disrespectful, please report it.)

 
10/17/2004 1:09:19 PMMassimo Conti

Super Mega Great Work!
You are the number one!

Best Regards.
(If this comment was disrespectful, please report it.)

 
1/4/2005 5:47:14 PMSimon Moss

Advanced? No way, I think you have redefined eliteVB. Rock'n'Roll!

(If this comment was disrespectful, please report it.)

 
3/31/2005 8:19:44 AM

Crashes when the following code is used

Private Sub iSubclass_Proc(ByVal bBefore As Boolean, ByRef bHandled As Boolean, ByRef lReturn As Long, ByRef hWnd As Long, ByRef uMsg As WinSubHook2.eMsg, ByRef wParam As Long, ByRef lParam As Long)
If bBefore Then
lReturn = sc.CallOrigWndProc(uMsg, wParam, lParam)
bHandled = True
End If
End Sub

..and you unload the subclassed form from a menu

I think the asm might need to (cSubclass.Class_Terminate is getting called inside the iSubclass_Proc)
(If this comment was disrespectful, please report it.)

 
6/5/2005 9:11:20 PM

I viewed your code and incorporated it into a user control on my form - MCI with events - in a matter of a half hour or so. I really appreciate your hard work - 5 globes from Uncle Dan
(If this comment was disrespectful, please report it.)

 
7/9/2005 4:32:22 AMRiccardo Cohen

I was wondering if you got my email about Class Module support?

Riccardo
(If this comment was disrespectful, please report it.)

 
1/22/2006 9:08:04 AMStewart

Very nice implimentation. I had to redo the subclassing for my scintilla wrapper due to some issues with speed and yours seems to have worked beautifully. I really appreciate this great work. I know it's been out for a long time but 5 from me :)
(If this comment was disrespectful, please report it.)

 
12/10/2006 1:53:10 PMTomás

i dont understand what is this for...

aniway....:P congrats on writing on asm

a long and now forgotten bussiness
(If this comment was disrespectful, please report it.)

 
2/22/2007 11:11:20 PMSSJ

it seems as if a lot of good coders have moved out of PSC since 2003..
(If this comment was disrespectful, please report it.)

 
11/27/2007 11:45:35 PMLala

Hello there,
i've downloaded ur subclassing code.
it works well when its in IDE but the compiled version generates a Memory cannot be written error.
The line which causes this is at cSuperClass::SubClass()

Call SetWindowLong(hWnd, GWL_WNDPROC, pCode)

Can you think of a reason why this happens?
Im just starting with subclassing and dont know much yet, but i find ur work very good!
Thanks so much!
(If this comment was disrespectful, please report it.)

 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular code, please click here instead.)
 

To post feedback, first please login.