Login / Register  search  syndication

          CRM Developer

Ryan Farley on CRM Development for SalesLogix, SageCRM, MSCRM, .NET - and all things geek

Embedding windows in SalesLogix

Something that I do quite often, and have done since early versions of SalesLogix is embed my own applications into the running Sales Client. I recently posted to my main blog about some tips to get started doing this from C#. It really is easy to do.

I recently built an application for SalesLogix that monitors for exceptions on opportunities (An exception being something defined by an administrator for something such as no activities on an opportunity that has a status of open). Anyway, I needed the app to be able to notify users when they move to an opportunity (or it's associated contact or account) that had an exception. Some kind of visual alert. However, I wanted to be able to install this without the need to modify any existing screens like the Account, Contact, or Opportunity detail screens (Reason being that it makes it difficult for upgrades and also then you have to build it into the existing customizations on those screens). So, I decided to take the approach to embed something in the top black strip in the Sales Client. For this app I too a button and embedded that - then the user could also click that to bring up a window that detailed the exceptions present on the current record. Here's a sample:


Click for larger picture


What you're seeing there is a .NET Button object embedded into an uncustomizable area in SalesLogix. Pretty cool. So, how do I do that? Easy. First of all, read the post from my main blog I mentioned before. That will get you a little up to speed on some of it. The remaining part not mentioned in my other post is the use of the SetParent Win32API. SetParent allows you to to the handle of a windowed object and assign the handle of a new parent window. It is my favorite API - but that is another blog entry.

First, you need to discover the running Sales Client and then find the handle of the TPanel object that we'll be embedding the button into. As outlined in my other post, you have two ways to do that. However, since we need to be able to also find a child handle for the TPanel object we'll use the FindWindow approach along with the FindWindowEx Win32API to drill down from the main SalesLogix window handle, to the child to the MDI client container handle, then to the main view window, and finally to the TPanel where we'll embed the button. Let's get started into the code. I've omitted the DllImports for the API calls for brevity - you can download the full code at the end of this post.

//Find SalesLogix app main window handle
IntPtr hwnd = FindWindow("TmdiMain", null);
if (!hwnd.Equals(IntPtr.Zero))
{
    //Find MDI client container handle
    hwnd = FindWindowEx(hwnd, IntPtr.Zero, "MDIClient", null);

    //Find main view handle
    if (!hwnd.Equals(IntPtr.Zero)) hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TfrmNewMainView", null);

    //find TPanel handle
    if (!hwnd.Equals(IntPtr.Zero)) hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TPanel", null);

    //Now we'll embed the button
    if (!hwnd.Equals(IntPtr.Zero))
    {
        SetParent(button1.Handle, hwnd);
        //Now we need to reposition the button in the TPanel otherwise 
        //we won't see it because it is to low at the moment.
        //To do this we need to get the RECT of the TPanel object and 
        //then reposition the button according to those coordinates

        Rect rect = new Rect();
        GetWindowRect(hwnd, ref rect);
        button1.Location = new Point((int)(rect.Width/2)-(int)(button1.Size.Width/2), 3);
    }
}

So the end result looks like this:


Not bad. Now to remove the button, or unembed it, all we have to do is set the parent back to the original handle. When you can SetParent, it returns an IntPtr which is the original handle. You can use that, or set it back to the handle of the form it came from.

Update: By request, I've added the sample code in VB.NET also - which was painful for me since I am not a fan of VB ;-)  -Enjoy.


Download a sample project containing the code here (C#)
Download a sample project containing the code here (VB.NET)

Edit: A change in SalesLogix 6.2 was that the MainView container window (inside MDIClient) is now named "TfrmNewMainView" insetad of it's previous object "TwndMainView2". I updated the code in this post, but you'll need to change the download to match.

What's This?

About Ryan Farley

   Ryan Farley is the Director of Development for Customer FX Corporation and the creator of slxdeveloper.com.


Related Content
   Programmatically building a datagrid in SalesLogix LAN
I recently had a project where I had to configure an account-level datagrid which displayed a list of rel
Posted on Nov 14, 2008 by Jason Buss to The Customization Blog
 
   Public SalesLogix Developer Classes Revamped
I announced a while ago that we will be offering some public developer training classes for SalesLogix We
Posted on Oct 27, 2008 by Ryan Farley to CRM Developer
 
   SalesLogix Group Explorer Added to Labs
I added a new utility to the Customer FX Labs tonight, the SalesLogix Group Explorer. This utility allows
Posted on Sep 13, 2008 by Ryan Farley to CRM Developer
 
   Public SalesLogix Web Developer Classes On The Way
Ever since the new SalesLogix 7.2 Web client and platform was released, I've had numerous requests fo
Posted on Sep 02, 2008 by Ryan Farley to CRM Developer
 
   SalesLogix 7.5 Beta Testing Has Begun!
The beta tesing for SalesLogix 7.5 has begun! Completely exciting. This is THE release for SalesLogix web
Posted on Jul 11, 2008 by Ryan Farley to CRM Developer
 
Comments

 

Jeremy Brayton said:

It's been a while since you've written this but I guess I want to understand the implications.

How would you go about running this say when SalesLogix runs or say when the Opportunity Detail screen is open? Would you place some script that calls your program and keeps it open while the Opportunity Detail screen is opened and close the program as it closes? Instead of it being like the demo with radio buttons, it would simply inject itself any time it's run.

I guess to understand this I would need to understand how you're using it. From what it looks like, you run your application after SalesLogix and use it to go through Opportunities only. I assume you have to leave your application up for it to work. It also appears that from the FindWindow calls that it is attaching to a child form. Meaning that if you were to chose any form in SalesLogix, you would see this button would you not? I'm interested in keeping things near their relations such as attaching only a button to Opportunity, or only the Activity screen. You probably can do that with this sample but I've yet to play with it. I just wanted to see how you're making it work so that I know how I'll have to make it work when/if I choose to use it.

Thanks
April 21, 2004 4:26 PM
 

Ryan Farley said:

I've used this approach (or a similar approach) many times to embed objects in non-standard places in SLX.

For something like what I describe in this post, I will use a monitoring application - a process that runs in the background. This monitor app will run in the background and wait for SLX to open. When it detects that SLX is running it will attach itself to the running client and embed where needed. When it detects that the sales client closes, it removes detaches itself and destroys the button.

As far as knowing when the user is on the opportunity screen (or account, contact, or anywhere else) what I do is use the GetClientWindowText Win32API to read the title bar of the SLX window. From there you can parse out what the current "entity" is that the user is on (ie: Opportunity, Contact, Account, etc). If you only want to embed when the user is on the opp screen, then you'd just read the title bar and go for it.

There have been times that I have also loaded the object, or started the EXE or DLL process running when the object is needed. More of an on demand type thing. So for example, if it is a window in SLX, such as a account, contact, managed screen or something, then I'll launch the process that embeds the object on the form when the form opens.
April 21, 2004 11:38 PM
 

Jame Ripper said:

I am fairly new to SLX and I am trying to understand how you knew what the ClassName (third Parameter) in the FindWindowEX call is? Is this posted somewhere? Many thanks for the help
April 29, 2004 1:06 PM
 

Ryan Farley said:

In order to find out the names of Windowed objects, you need to use a "Spy" utility that can discover details about running Windows, such as HWNDs, Class names, etc.

There is a utility named Spy++ that comes with Visual Studio. I use one that I built myself, but a great one (also free) I've used in the past is called "Spy & Capture". It can be downloaded here: http://kobik.videodot.net/spy_capture.asp
April 29, 2004 1:26 PM
 

Jiho Han said:

Ryan,

I have tried similar approach but in VB6 before. I've kind of not pursued it after a while - too many issues.
But the real issue whenever I try to employ these "tricks" has been deployment issues. For example, in your case, you'd have to make sure the client workstation has .NET Framework installed. Anytime you think you can incorporate a custom ActiveX control, the same issues abound.

How have you handled these in the past?
June 16, 2004 2:32 PM
 

Ryan Farley said:

Jiho Han,

Never had any issues with deployment. Just about *everything* I do for SalesLogix contains outside code/dll/exe. I just build my own install to contain all of my stuff and that just becomes part of the SLX installation process.
June 16, 2004 3:41 PM
 

Jiho Han said:

Wow, and you've never had your clients complain that they had to run the install on say, 100 desktops? One time installation may be overlooked but for every update to the locally installed apps/dlls, the local IT guy will have to visit those 100 desktops again and again. Of course, I'm sure there's a way to manage this using SMS or something like that(I actually don't know much about SMS).
June 17, 2004 7:43 AM
 

Ryan Farley said:

That is just an expectation that is set up front. Really no different than the fact that SLX must be installed on all workstations and updates as well. And actually, my own installations are much easier - and can be more easily automated than the SLX installation.

To be honest, I've never had any complaints from any IT staff and I develop externally on about every project. It is all how you sell it. The added benefit gained by what could be done since you are developing externally makes it worth it.
June 17, 2004 8:08 AM
 

Jiho Han said:

Hmm.. what is this, new concept, Expectation Management, you speak of? :) I would like to hear more of this...
June 17, 2004 12:20 PM
 

David Purnell said:

Ryan, any chance you can post some sample code for vb.net, i can't get it to work in vb.net at all, c# using your code it works fine though.
August 27, 2004 8:41 AM
 

Ryan Farley said:

I've had that request before, so I threw together the same code in VB.NET. I don't ever use VB so I hope it works OK ;-)

Take a look at the links at the bottom to download the sample code in VB.NET.

Have fun.
August 27, 2004 9:42 AM
 

David Purnell said:

Cheers Ryan, works a treat.
September 28, 2004 5:31 AM

Leave a Comment

(required)  
(optional)
(required)  
Add
All contents Copyright © 2008 Customer FX Corporation
Customer FX Corporation
2324 University Avenue West, Suite 115
Saint Paul, Minnesota 55114
Tel: 800.728.5783
 Follow us on Twitter @CustomerFX






Login / Register