Automatically add ‘Search As You Type’ to every SharePoint page using Infuser

Posted at: 17:10 on 30 July 2009 by Muhimbi

Inject some goodies into your site It’s only been a day since we launched our free Infuser tool  and we already have an excellent application for it; Add Search as you Type support to SharePoint’s standard search box.

As many of you will be aware, Jan Tielens created a proof of concept some time ago to demonstrate how you could add this functionality to a custom web part. Very innovative, but unfortunately it has a couple of problems, most notably:

  • The script has to be added manually to every page on the site, which is very laborious and not always possible.
  • It doesn’t integrate with the standard MOSS search box, leaving the end user with two search boxes to choose from.
  • If the user doesn’t have access to the root site of the portal then search doesn’t work.
  • Resizing the window with the search results causes undesired effects.
  • The search button is present, but doesn’t work.
  • It is not clear how to make the search results window disappear.
  • It relies on the MOSS Search web service and doesn’t work with WSS.  

    Although Jan’s script works without modification in Infuser, we asked Jan’s permission and spent a couple of hours to address the points listed above with the exception of WSS compatibility, feel free to add this yourself. The full source code is listed at the end of this article.  


  Follow the steps outlined below to add Search as you Type to your site collection:

  1. Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
  2. Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
  3. From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
  4. Download the code and paste it into the Infuser window. If copying from the window below and you are using IE then you may want to paste it in WordPad first , otherwise all line breaks are stripped out.
  5. Click the Save button and navigate to any page that contains a search box and start typing.

<style type="text/css">
    /* Hide the search scope fields as we don't take their input */
    .ms-sbscopes          {display:none}   /* MOSS */
    #idSearchScope        {display:none}   /* WSS */
        background: white;
        border: 1px solid white;
        margin-left: 2px;
        overflow: hidden;
        text-overflow: ellipsis;
        background: #EEEEEE;
        border: 1px solid Gray;
        margin-left: 2px;
        overflow: hidden;
        text-overflow: ellipsis;
<!-- Load the JQuery Libraries that ship with Infuser -->
<script type="text/javascript" src="/_layouts/Muhimbi.Infuser/JQuery/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
    // QuickSearch v0.2
    // Created by Jan Tielens,
    // Modified to integrate with standard Seachbox by
    // This sample code is provided on an “as is” basis and without warranty of any kind.
    // *** Customizable parameters ***
    var quickSearchConfig = {
        delay: 500,             // time to wait before executing the query (in ms)
        minCharacters: 3,       // minimum nr of characters to enter before search
        scope: "All Sites",     // search scope to use 'All Sites'
        numberOfResults: 15,    // number of results to show
        resultsAnimation: 200// animation time (in ms) of the search results
        resultAnimation: 0      // animation time (in ms) of individual result (when selected)
    var quickSearchTimer;
    var quickSearchSelectedDivIndex = -1;
    var searchBox = null;
    // ** Hook up the various events 
    jQuery.event.add(window, "resize", resizeWindow);
    jQuery.event.add(document, "click", hideResultsDiv);
    $(document).ready(function() {
        // ** The searchbox uses a dynamic ID so select it by class     
        searchBox = $('.ms-sbplain');
        // Muhimbi, insert the results box after te search area
        searchBox.after("<div id=\"quickSearchResults\" style=\"display: none; z-index:1000\"></div>");
        searchBox.keyup(function(event) {
            var previousSelected = quickSearchSelectedDivIndex;
            // catch some keys
            switch(event.keyCode) {
                case 13:    // enter
                    var selectedDiv = $("#quickSearchResults>div:eq(" + quickSearchSelectedDivIndex + ") a");
                    if(selectedDiv.length == 1)
                        window.location = selectedDiv.attr("href");
                case 38:    // key up
                case 40:    // key down
                    quickSearchSelectedDivIndex ++;
            // check bounds
            if(quickSearchSelectedDivIndex != previousSelected) {
                if(quickSearchSelectedDivIndex < 0)
                    quickSearchSelectedDivIndex = 0;
                if(quickSearchSelectedDivIndex >= $("#quickSearchResults>div").length -1)
                    quickSearchSelectedDivIndex = $("#quickSearchResults>div").length - 2;               
            // select new div, unselect the previous selected
            if(quickSearchSelectedDivIndex > -1) {
                if(quickSearchSelectedDivIndex != previousSelected) {
                    unSelectDiv( $("#quickSearchResults>div:eq(" + previousSelected + ")"));
                    selectDiv($("#quickSearchResults>div:eq(" + quickSearchSelectedDivIndex + ")"));
            // if the query is different from the previous one, search again
            if($(searchBox).data("query") != $(searchBox).val()) {
                if (quickSearchTimer != null) // cancel the delayed event
                quickSearchTimer = setTimeout(function() { // delay the searching
                        $("#quickSearchResults").fadeOut(200, initSearch);
                    } , quickSearchConfig.delay);
    function showResultsDiv(text) {
        var div = $("#quickSearchResults");
    function hideResultsDiv() {
        var div = $("#quickSearchResults");
    function resizeWindow()
        var div = $("#quickSearchResults");
        var searchParent = $(searchBox).parent();
        var divCss = {
            "left": searchParent.offset().left,
            "padding": 0,
            "position": "absolute",
            "top": searchParent.offset().top + searchParent.height() + 1,
            "border": "1px solid #7f9db9",
            "width": searchParent.width(),
            "background": "white",
            "max-width": searchParent.width()
    function unSelectDiv(div) {
        // first stop all animations still in progress
        $("#details", div).hide();
    function selectDiv(div) {
        $("#details", div).slideDown(quickSearchConfig.resultAnimation);
    function initSearch() {
        // first store query in data
        $(searchBox).data("query", $(searchBox).val());
        // clear the results
        // start the search
        var query = $(searchBox).val();
        if(query.length >= quickSearchConfig.minCharacters) {
            showResultsDiv("Searching ..."); // display status
    function search(query) {
        quickSearchSelectedDivIndex = -1;
        var queryXML =
            "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'> \
            <Query domain='QDomain'> \
             <SupportedFormats> \
                <Format>urn:Microsoft.Search.Response.Document.Document</Format> \
             </SupportedFormats> \
             <Context> \
              <QueryText language='en-US' type='STRING' >SCOPE:\"" +
                 quickSearchConfig.scope + "\"" + query + "</QueryText> \
             </Context> \
             <SortByProperties> \
               <SortByProperty name='Rank' direction='Descending' order='1'/> \
             </SortByProperties> \
             <Range><StartAt>1</StartAt><Count>" + quickSearchConfig.numberOfResults + "</Count></Range> \
             <EnableStemming>false</EnableStemming> \
             <TrimDuplicates>true</TrimDuplicates> \
             <IgnoreAllNoiseQuery>true</IgnoreAllNoiseQuery> \
             <ImplicitAndBehavior>true</ImplicitAndBehavior> \
             <IncludeRelevanceResults>true</IncludeRelevanceResults> \
             <IncludeSpecialTermResults>true</IncludeSpecialTermResults> \
             <IncludeHighConfidenceResults>true</IncludeHighConfidenceResults> \
        var soapEnv =
            "<soap:Envelope xmlns:xsi=''" +
            " xmlns:xsd='' \
              xmlns:soap=''> \
              <soap:Body> \
                <Query xmlns='urn:Microsoft.Search'> \
                  <queryXml>" + escapeHTML(queryXML) + "</queryXml> \
                </Query> \
              </soap:Body> \
            url: L_Menu_BaseUrl + "/_vti_bin/search.asmx",
            type: "POST",
            dataType: "xml",
            data: soapEnv,
            complete: processResult,
            contentType: "text/xml; charset=\"utf-8\""
        function processResult(xData, status) {
            var html = "";
            $(xData.responseXML).find("QueryResult").each(function() {
                var divWidth = $(searchBox).parent().width() + 20;
                var x = $("<xml>" + $(this).text() + "</xml>");
                x.find("Document").each(function() {
                    var title = $("Title", $(this)).text();
                    var url = $("Action>LinkUrl", $(this)).text();
                    var description = $("Description", $(this)).text()
                    html +=
                        "<div class='quickSearchResultDivUnselected' style='width:" + divWidth +
                              "px;max-width:" + divWidth +"px'> \
                            <a href=\"" + url + "\">" + $("Title", $(this)).text() + "</a> \
                            <div style='display:none' id='details' style='margin-left:10px'>"
                                + description +
                                "<br/>" + url + " \
                            </div> \
                if(x.find("TotalAvailable").text() != "")
                    html += "<div style='text-align:center; width:" + divWidth +
                            "px'>Total results: " + x.find("TotalAvailable").text() + "</div>";
                    html += "<div style='text-align:center; width:" + divWidth +
                            "px'>Total results: 0</div>";
                function() { selectDiv($(this).parent()); },
                function() { unSelectDiv($(this).parent());  }
    function escapeHTML (str) {
       return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');


Labels: , ,

‘Massage’ SharePoint into submission using Muhimbi’s SharePoint Infuser

Posted at: 17:33 on 29 July 2009 by Muhimbi


They say Great things come in small packages and Simple solutions are often the best. In case of our new, and completely free product, we humbly agree.

SharePoint Infuser’s concept is simple. It allows custom content, any content, to be inserted automatically on every page in a site collection. Big deal you may think, I can do that easily via SharePoint Designer / Customer Master Page / Content Editor Web Part, Delegate Controls etc. All I need to do is spec it out, develop it, put it through testing, put it past infrastructure, sweet talk the change control guy and my manager…. Yes, easy indeed.

And indeed, some people may prefer to roll their own solution, which is not necessarily always a bad idea. Meanwhile the rest of us may want to make changes that can be measured in minutes rather than days, or more likely, weeks.

In essence Infuser is used in a similar manner to the many existing Content Editor Web Part (CEWP) ‘hacks’ such as Jan Tielens’ cool hacks, End User SharePoint’s many articles and The main difference is that the CEWP must be added manually to every page in the site - which is a pain and doesn’t scale – whereas Infuser inserts the code automatically on every page in the Site Collection.

The best way to show the power of Infuser is by example. In addition to the examples listed below we will publish many more over the next few weeks, so subscribe to our RSS feed, Twitter Stream or Newsletter.


Example 1 – Hide unnecessary user interface elements

Sometimes less is better, which is why it may be a good idea to hide user interface elements that your users have no need for, or quite frankly would confuse them. In the following example we will hide the ‘View all Site Content’ and ‘Search Scope Picker’ from every page in the site collection as visualised in the following ‘before & after’ screenshots.


Follow the steps outlined below to implement the changes:

  1. Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
  2. Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
  3. From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
  4. Insert the following style sheets:

       .ms-quicklaunchheader {display:none}
       .ms-sbscopes          {display:none}   /* MOSS */
       #idSearchScope        {display:none}   /* WSS */

  5. Click the Save button and navigate to any page that was previously displaying the Search Scope Picker.



Example 2 – Collapse the Quick Launch menu

Let’s continue with a slightly more complex example that inserts a small section of JavaScript in every page in order to collapse the individual items in the Quick Launch Menu.


Follow the steps outlined below to implement the changes:

  1. Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
  2. Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
  3. From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
  4. Copy and paste the code from this End User SharePoint posting.
  5. Click the Save button and navigate to any page that displays the Quick Launch Menu.


Example 3 – Let it snow

Finally, and most importantly, a real Enterprise Ready example: Snow!…. Yes snow on every page of your SharePoint site, why not.

Follow the steps outlined below to add this marvellous winter wonderland.

  1. Download and install Muhimbi’s SharePoint Infuser on one of your Web Front End Servers.
  2. Ensure you have Designer privileges, more specifically the Add and Customize Pages right.
  3. From the Site Actions / Site Settings screen, select Infuse custom content in the Look and Feel column.
  4. Manually insert “<script></script>” in the Infuser window and paste the code in snowstorm.js in between.
  5. Update line 75 (see how cool the line numbers in our editor are) to:
    var imagePath = '';
  6. Click the Save button and navigate to any page in the site collection.


Bonus Examples

We created a couple of follow up articles:


In closing

The possibilities are endless. If it can be done in the Content Editor WebPart then it can most likely be done more efficiently using SharePoint Infuser.

So, if  your IT team doesn’t allow you to make changes, is too busy, your changes are not a priority or if you are hosting your SharePoint site externally and you are not allowed to install your own modifications then SharePoint Infuser is most likely the best option you have to modify the look and feel of your SharePoint site.

We are currently working with a number of hosting providers to ensure Infuser is installed by default on all systems, allowing all their customers to benefit from it.

Note that we ship with JQuery (1.3.2-min) out of the box. It can be found at “/_layouts/Muhimbi.Infuser/JQuery/jquery-1.3.2.min.js”

For more information check out the:

As always, feel free to contact us using Twitter, our Blog or regular email or subscribe to our newsletter.


Download your complete free, no strings attached, copy here (1MB).

You don’t even have to register, but we would appreciate it if you did.

Labels: , , ,

Visio, Word, and Access Services in SharePoint 2010

Posted at: 17:06 on 20 July 2009 by Muhimbi

SharePoint2010 We are not in the habit of reposting external content on this blog, but with the limited amount of public SharePoint 2010 information available, this is too tempting to pass on.

The videos listed below were recorded by a member of the audience at the recent WPC and refer to MS-Access, MS-Word and the previously announced Visio Services for SharePoint, after which these services are demonstrated.

Just ignore the introduction music.


New release of MuSH, ‘TinyURL’ for SharePoint v1.1.0.1

Posted at: 15:46 on by Muhimbi

MushBox We are proud to announce the availability of MuSH version This version is largely a maintenance release that fixes a number of bugs that only appeared in certain SharePoint environments. In addition to a number of bugfixes, support for the French language has been added as well.

For those not familiar with the product we recommend reading the original announcement. In summary, the Muhimbi URL Shortener for SharePoint, aka MuSH, can be used to shorten URLs for typical web applications and SharePoint in particular. It integrates tightly with both WSS and MOSS and allows short URLs to be created directly from a list item’s context menu.

The changes and improvements are as follows:

576 Error creating list when Central Administration uses a language other than English.
Contact us if you have previously tried to install MuSH on a non English system and you encountered problems. A few extra steps are needed before the new version can be installed.
564 Add support for French
567 Short URL is not passed back by the webservice for some systems
568 Event log shows ‘Index out of range in HTTP Module’ messages


For more information check out the:

As always, feel free to contact us using Twitter, our Blog or regular email or subscribe to our newsletter.

Download your free trial here (1MB). You don’t even have to register, but we would appreciate it if you did.

Labels: , ,

A solution for SharePoint’s common DISP_E_EXCEPTION COM error

Posted at: 17:28 on 14 July 2009 by Muhimbi

SherlockAnother post from our ‘customer support archives’. We’ll call this one ‘The case where code executed by workflows behaves differently from code executed by Application pages and why it actually was our own fault’.

We were contacted by a SharePoint developer who is using our PDF Converter to convert files to PDF format from a SharePoint Designer workflow, a common requirement. This developer clearly knew what he was doing and decided to test the system under stress by activating the workflow on a number of files simultaneously, which resulted in a number of horrible SharePoint errors in the Event log, most notably the following ones:

Message: Exception occurred. (Exception from HRESULT: 0x80020009 (DISP_E_EXCEPTION))
- Exception: System.Runtime.InteropServices.COMException
- StackTrace: at System.Runtime.InteropServices.ComTypes.IStream.Seek(Int64 dlibMove, Int32 dwOrigin, IntPtr plibNewPosition)
at Microsoft.SharePoint.SPFileStream.get_Position() …. etc


Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
- Exception: System.AccessViolationException
- StackTrace: at System.Runtime.InteropServices.ComTypes.IStream.Seek(Int64 dlibMove, Int32 dwOrigin, IntPtr plibNewPosition)
at Microsoft.SharePoint.SPFileStream.Seek(Int64 offset, SeekOrigin origin)
at Microsoft.SharePoint.SPFileCollection.AddInternal(String urlOfFile, Object file, PutFileOpt fileOpt, String createdBy, String modifiedBy, Int32 createdByID, Int32 modifiedByID, DateTime timeCreated, DateTime timeLastModified, Object varProperties, String checkInComment, SPVirusCheckStatus& virusCheckStatus, String& virusCheckMessage)
at Microsoft.SharePoint.SPFileCollection.Add(String urlOfFile, Stream stream, Hashtable properties, Boolean overwrite)

and the SharePoint trace log (in verbose mode) showed the following, all too familiar, messages

ERROR: request not found in the TrackedRequests. We might be creating and closing webs on different threads. ThreadId = 10, Free call stack =    at Microsoft.SharePoint.SPRequestManager.Release(SPRequest request)     at Microsoft.SharePoint.SPSite.Close()     at Microsoft.SharePoint.SPSite.Dispose()     at Microsoft.SharePoint.Workflow.SPWorkflowAutostartEventReceiver.AutoStartWorkflow(SPItemEventProperties properties, Boolean bCreate, Boolean bChange, AssocType atyp)     at Microsoft.SharePoint.Workflow.SPWorkflowAutostartEventReceiver.AutoStartWorkflow(SPItemEventProperties properties, Boolean bCreate, Boolean bChange)     at Microsoft.SharePoint.Workflow.SPWorkflowAutostartEventReceiver.ItemUpdated(SPItemEventProperties properties)     at Microsoft.SharePoint.SPEventManager.RunItemEvent...


An SPRequest object was not disposed before the end of this thread.  To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it.  This object will now be disposed.  Allocation Id: {1BA98355-FDFB-4757-92E6-644DD7CED638}  To determine where this object was allocated, create a registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings.  Then create a new DWORD named SPRequestStackTrace with the value 1 under this key.    


36 heaps created, above warning threshold of 32. Check for excessive SPWeb or SPSite usage.

Anyone who has done any SharePoint development, including us, will immediately draw the conclusion that somewhere we are not disposing an SPWeb or SPSite object and if it wasn’t for the following we would agree.

  1. When invoking exactly the same code through a SharePoint Application Page, which is how our end-user - non workflow - interface works, everything works great. No errors, no warnings and no memory leaks.
  2. As part of our development process we thoroughly check our code for typical SharePoint dispose leaks using SPDisposeCheck. The PDF Converter comes out completely clean.
  3. When using an out-of-the-box Workflow Activity such as Copy List Item, you get the same ‘errors’ in the SharePoint trace log.
  4. A Google search for DISP_E_EXCEPTION SharePoint returns 1420 results, all from people tearing their hair out in despair. This problem appears to have many different causes and few common solutions.


So, with a nice problem that only occurs under stress at hand we fired up our debuggers. Naturally it all works great when stepping through the code. We tried all kinds of common temporary workarounds such as a big mutex around the entire Workflow Activity, a couple of Sleeps in the code to let the system ‘recover’ and even acts of desperation such as manually calling the Garbage Collector (!)….. nada.

After stripping the code down to its bare minimum, removing all calls to anything remotely complex such as the actual PDF Conversion, we noticed that we were not disposing the stream that comes of our SPFile Object. After adding a Dispose() for that stream all problems went away.

using(Stream stream = someSPFileObject.OpenBinaryStream())
   … do your stuff

Why this is only a problem when invoked via workflows and why this has not turned up during our own stress tests is anyone's guess. We just hope that this solution will help anyone else with the same problem.

On a separate note, I would really like to thank our customers. They are extremely cooperative when it comes to troubleshooting these kinds of errors. They happily send log files, install interim versions while staying friendly and helpful. Thanks for making our lives a lot easier.


Labels: ,

New release of Workflow enabled PDF Converter for SharePoint – v1.3.0.2

Posted at: 15:29 on 09 July 2009 by Muhimbi


We are excited to announce the new version of the Muhimbi PDF Converter. No major changes in functionality this time, just a vastly improved conversion engine.

For those not familiar with the product, the PDF Converter for SharePoint is a light weight solution (4MB download) that allows end-users to convert common document types, such as doc, docx, rtf, InfoPath, txt etc, to PDF format from within SharePoint. It integrates at a deep level with SharePoint and leverages facilities such as the Audit log, localisation, security and tracing. It runs on both WSS 3 as well as MOSS and is available in English, German, Dutch and Japanese. For detailed information check out the product page as well as this blog posting describing how to use the PDF Converter from A SharePoint Designer Workflow.

The number of improvements is significant. The main ones are as follows:

570 Removed a minor SharePoint ‘Dispose’ leak
566 Fixed a bug where sometimes table background colours were not converted
338 Page footers in RTF files are now rendered correctly
503 SharePoint designer Workflow Action translated to German and Dutch.
526 Improved conversion engine, most notably:
- General stability improvements when opening documents.
- Improved memory handling.
- Improved recognition and support for converting ODT (Open Office) files.
- Improved support for converting RTF files.
572 DISP_E_EXCEPTION when converting many documents using a workflow
573 Occasional "Value cannot be null" exception in Workflow activity


For more information check out the:

As always, feel free to contact us using Twitter, our Blog, regular email or subscribe to our newsletter.


Download your free trial here (4MB). You don’t even have to register, but we would appreciate it if you did.

Labels: , ,

Solution for displaying the Office 2007 Project templates in VS2008

Posted at: 10:45 on 06 July 2009 by Muhimbi


A quick tip to spare everyone else a desperate and lengthy Visual Studio 2008 + SP1 reinstall.

Earlier today we started a project that required an Office 2007 client side add-in to be developed. However, for some reason none of our developer workstations showed any templates in the Office 2007 category when choosing ‘New Project’ in Visual Studio 2008.

So we checked that Office 2007 support had been installed with Visual Studio, we removed and added it back, ran several repairs, reinstalled SP1 etc….nothing!

Then we read the MSDN site and re-read it a couple of times after which the quarter dropped. As it turns out, the VS Tools for Office 2007 that ship with VS2008 require the .net 3.5 framework (Great, yet another massive dependency). Simply switching the .net Framework version in the top right corner of the ‘New Project’ dialog to 3.5 solved the problem.

Office 2007 templates invisible

Office 2007 templates after selecting .net 3.5


Reselling Muhimbi’s products

Posted at: 18:49 on 03 July 2009 by Muhimbi

ResellerWe are frequently approached by companies who wish to become a reseller of our products. At this moment in time Muhimbi’s reseller program is closed and we will not accept any applications.

However, if you represent an organisation that wishes to purchase a product on behalf of one of your customers then we are happy to take your order. Please use the e-commerce facilities on our website to place the order, but do not download the license key when prompted. Instead email the following customer details to, together with your order reference, so we can create a license key for your customer.

  • Company Name:
  • Address:
  • Town:
  • ZipCode:
  • Country:
  • State:
  • Main Contact Person First Name:
  • Main Contact Person Last Name :
  • Main Contact Person Telephone:
  • Main Contact Person Email:

You are free to set your own price point and charge your customer for your services.


Labels: ,

Subscribe to News feed