Excel - Windows 7 Taskbar Progress - winapi

Running Excel 2010, I can assuredly always be running these sheets on this version, as it will only be accessed locally exclusively on my work's terminal computers.
I run a number of import process and large folder filtering/printing batch functions via excel. I am wanting to utilize the Windows 7 taskbar progress bar visual while my functions process, giving an idea of how far they are along. Considered going with other visual effects for showing the progress, but this(if possible) seems the most obvious and professional style to do so.
I've been looking thoroughly into trying to make this work, to no avail. My understanding thus far is that I need to impliment the ITaskbarList3 interface, commonly found within the Windows API. From the code I have found showing how to make it work, once implimented the rest seems fairly easy and self-explanatory.
I am completely restricted to using Excel as the basis for the code, no installation permission on the work computers. I can install at home to get any files necessary, and then transfer them. Happy to use any extensive or really backwards ways to get to the end, as the ends justify whatever means it takes.

It would be much easier to use the Excel Status Bar:
Application.StatusBar = "Show progress to user...";
For the Windows & Taskbar progress bar you need to download the
Windows 7 taskbar: Developer Resources.
You'll need to open the sample solution, right click on the Windows7.DesktopIntegration project > properties > Build > Tick Register for COM.
By checking the "Register for COM interop" option in the IDE during development, the IDE will call regasm on the target assembly together with the /codebase option.
This will cause regasm.exe to add the following registry entry for a COM-visible class exported from your assembly :
HKEY_CLASSES_ROOT\CLSID{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\InprocServer32\CodeBase=
This will enable the CLR to locate your assembly by following the path to your assembly.
Without the codebase path, the CLR will have to locate your assembly (and its dependencies) using the standard search algorithm.
Next Build the solution > goto the bin folder the Windows7.DesktopIntegration project and copy the Windows7.DesktopIntegration.DLL and Windows7.DesktopIntegration.TLB to the System32 folder or better yet Register to the GAC.
One related technique that helps the CLR to locate required assemblies is to copy all assemblies (and their dependencies) to the same folder as the client application itself. However, the client application in your case will be Excel. This means that you must copy the assemblies into the same folder as the Excel application (not a good idea).
Once you are able to instantiate the Windows7.DesktopIntegration DLL, you should be able to call the Windows7Taskbar.SetProgressValue method, eg VBA code:
Set Windows7Taskbar = CreateObject("Windows7.DesktopIntegration")
Windows7Taskbar.SetProgressState(form.Handle, Windows7Taskbar.ThumbnailProgressState.Normal)
Windows7Taskbar.SetProgressValue(form.Handle, progress, maximum)

Related

How do I include an SDK routine in VB6?

I am modifying some old VB6 code and there are a number of calls to a subroutine called SDKPress(Index as integer, PressStatus as Integer, PressX as double, PressY as double, PressDataX as double, PressDataY as double).
(This routine returns the position of the mouse click and Index returns which graph on a form the mouse is in.)
Since there is no code for this in the project, I assume it is from some Windows software development kit. However, there is no trace of it on the development PC. just an SDK directory in the VisualBasic directory containing winsdk_web.exe.
I cannot call that subroutine from another project. Where does the subroutine live? Where can I find documentation on it? How can I get it in a form where I can use it on another project?
To find out where it lives. Put the cursor in one of the routine calls in the IDE, right-click on it, and choose go to definition. See where it takes you.
It may be an ordinary routine in a code file in your project.
It may be a routine in a DLL which is imported into your project via a Declare statement.
It may be a routine in a COM/ActiveX DLL or OCX control or even ActiveX EXE. In which case the IDE will show you the "object browser" window and you should be able to figure out where the routine lives, and go from there. I.e. figure out how to add a reference to it into another VB project, and how to install/register the relevant DLL/OCX/EXE on another PC.
OR, and I'm sure you tried this already, but just in case, search the source code for the routine name. Use Ctr-F or menu item Edit-Find in the VB IDE.
DLL files contains the API functions, vb6 code will load the DLL (Declare Function SDKPress Lib "DLLName" ....) and call the functions, use a tool like DllExpView: https://www.nirsoft.net/utils/dll_export_viewer.html and list DLLs and their functions. Or it also might be an internal subroutine/function.
If the original program which uses the SDK runs, you can gather some information using Process Monitor and Process Explorer. These can help you locate dependencies of many types.
I'd start with the second - when you run your program, ProcExp will show you all the files, including DLLs, that are loaded into the process. This alone might give you some insight.
If that is insufficient then use ProcMon to actively monitor the activities of your program. While ProcExp is basically a snapshot in time, ProcMon will dynamically record many of the actions of your program, including how it searches for and ultimately loads DLLs.
https://learn.microsoft.com/en-us/sysinternals/downloads/procmon
https://learn.microsoft.com/en-us/sysinternals/downloads/process-explorer
I have found these tools to be invaluable on many occasions. They help to break down the "black box" around a running process which appears in many programmers minds.

How to handle legacy OCX files in a Visual Basic Project

I have inherited an old VBP project that is ostensibly usable in Visual Basic 6.
It has two .ocx files which, research seems to indicate, need to be registered with regsvr32. Loading VB6 onto a Windows XP installation seems to allow me to successfully register them both.
However, VB6 still chokes on them. When I load the project, two errors are logged:
Line 228: Class CvsInSightDisplayOcx.CvsInSightDisplay of control Camera1 was not a loaded control class.
Line 5841: Class Xtimer01.Xtimer of control Xtimer1 was not a loaded control class.
And, naturally, the project will not compile. What steps can I take to get these .ocx files to play well?
#Bob77's comment led me to a two part resolution.
1) One of the components needed to be formally installed. (Thankfully it was still available.)
2) Both needed to be manually removed from the .vdp file using Notepad, and added via the VB6 UI, through Project -> Components... and 'Browse...'

How to share VB project with another programmer overcoming the vbp "reference" issue?

I have this old VB6 project that is composed of a few DLLs, OCXs, and GUIs.
There is a GUI component that includes this in it's VBP file:
Type=Exe
Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\SysWOW64\stdole2.tlb#OLE Automation
Object={EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.1#0; ieframe.dll
Object={3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}#4.0#0; mshtml.tlb
Reference=*\G{64E54C86-D847-48F7-9AE5-D6C9B8E6A3A2}#3.0#0#..\..\bin\Crypt.dll#Crypt
Reference=*\G{B3E7F95C-B6D9-458E-B4D4-5272759B139A}#4.0#0#..\..\bin\SpeechMike.dll#SpeechMike_DLL
Object={831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.1#0; MSCOMCTL.OCX
Object={AB4F6C60-4898-11D2-9692-204C4F4F5020}#29.0#0; Ccrpsld.ocx
Object={48E59290-9880-11CF-9754-00AA00C00908}#1.0#0; msinet.ocx
Object={9C526969-AA6E-4D61-BAFA-117FD20C2B38}#3.0#0; SpeechMike.ocx
The Reference settings are a pain since they always change from one machine to the other. I mean, the GUID '9C526969-AA6E-4D61-BAFA-117FD20C2B38', for the last one as an example, will be something on my system, but something else on somebody else's machine.
For now, to make it work, I erase References to Crypt.dll and SpeechMike.dll. Also Object SpeechMike.ocx. Otherwise, Visual studio looks for something that does not exists. Then in "project > references" I check both Crypt and SpeechMike and the Reference goes back to the VBP with the proper GUID and version. Finally, in 'project > components' I add the OCX and I'm good to go.
Am I wrong about that? How can I share the project with some else without going through hoops and loops to start the project?
I'm using MS Visual Basic 6 (part of VS 6 enterprise).
This sounds like "failure to maintain binary compatibility." Normally you only do this to yourself, but of course it can be a bigger headache if multiple people are compiling your libraries from the source Project files.
When you create ActiveX EXEs, DLLs and OCXs you need to create a "base" version where type and class ID values (GUIDs) get assigned. The documentation even suggests that you do this leaving the procedures empty: just a comment line or something so the IDE does not remove the empty declarations.
You don't have to use an "empty" base reference library, it can be one with full code in it.
Once you have compiled this baseline library, you'd exit and save your Project. Then rename this "empty" library as something else and from there keep it along with your Project source files.
After this you re-open the Project and go into Project Properties and on the Component tab change the Compatibility setting to Binary Compatibility and in the box there enter the full path and name of your compiled baseline library. Save the Project. Now you can add code and compile the "real" library to be used by other programs.
When you distribute these libraries (DLLs, OCXs) to somebody else in source code form so that they can compile them you must provide this renamed compiled baseline library along with the source code files, VBP file, resource files, etc.
From there your GUIDs will be stable until you make a change to something that breaks binary compatibility (changing a method's argument list, etc.).
There is more detail on this in the online Help (MSDN Library). See:
Using Visual Basic|Component Tools Guide|Creating ActiveX Components|Debugging, Testing, and Deploying Components|Version Compatibility in ActiveX Components

Developing Reg-Free COM application with VB6

I'm maintaining a VB6 application with many COM components (DLLs and OCXs). In order to streamline development and deployment I'd like to use reg-free com. The problem with development is that the application runs within the VB6.EXE instance. How can I trick VB6 to use my (unregistered) components? It is very important for me to not have to go through registering/unregistering components when switching between branches. Generating a .manifest file for VB6 is not out of the question but is there some other, more optimal way, to specify a .manifest file when launching VB6.EXE?
Note: The Activation Context API doesn't seem to help, even if used from within the development environment.
Solutions I've thought:
A utility application that activates a context from a manifest and launches VB6 as a child process (doesn't work; processes don't inherit activation context)
Injecting context activation into the VB6 process at startup (too complicated; must hack the executable to do this)
Hosting VB6 in my own process after activating the right context (can't even find out if this is possible)
Using a VB6 Add-In or other utility that runs within VB6 to activate a context (tried that but it doesn't seem to work)
Update Jan. 16
As suggested by wqw, I did some testing with a VB.exe.manifest. The VB6.exe.manifest worked, with some caveats:
The SxS dll specified in the manifest would not appear in the references window on projects that didn't actually reference the component
On projects that did reference the component it would be shown to reside in the directory according to the following order:
The pathname recorded in the project file (if the file was still present)
A pathname as if it resided in the same folder as the project (vbp)
If the file was not in any of these folders, the project would not compile (just running the code causes an internal compile in VB6) with the message "Can't find project or library".
Obviously, VB6 actualy scans the registry to find COM components and verifies, during compilation, that they exist where they say they exist. I'm not sure what that might mean if I actually want to use VB6.exe.manifest to redirect COM component instantiation. Perhaps having dummy component files at some predefined location might trick VB6 into believing that everything is as it should be, although an entirely different set of components got loaded for use.
Further update:
I did a test on that last assumption and it proved to be false. The component has to actually be there in order for the project to compile. It must even properly load (no dummy, zero-length files accepted!). Now I'm not even sure if the manifest works. That's a more time-consuming test (requires a component with two versions that produce different results, one with the project, and one for the manifest).
Our approach to this problem was to write a build assist program that registered and unregistered components, run the VB6 compiler, and would even rewrite project files with updated GUIDs when interfaces changed. You would hand it a VBG project group and it would do the rest.
I suppose we could also have added a mode that unregistered components when you switched branches.
Are you following the practice of using "compatibility" binaries? You shouldn't use the binary at your build location for compatibility references - you should commit a separate copy to version control and configure your project to consider that the "compatible" version - only change this file when you break interfaces.

what is the diff between dependencies and manually add a dll/ocx in vs installer 6?

i'm using vs installer to build a setup package for my vb6 app.
and the problem is i can see that under the project explorer there's a list of dependencies attached to my exe file.
alt text http://img505.imageshack.us/img505/9696/croppercapture259lr8.png
and under the file system on target machine treeview, i can actually store the dll/ocx on a folder or in the windows system folder itself[the left window].
alt text http://img101.imageshack.us/img101/9224/croppercapture251qm1.png
so what i don't understand is .. is there actually a difference?
if i just set the dependencies and didn't add the dll or ocx to the folder or win sys folder, does the dll automatically get copied over too?
It is not guaranteed that all those dlls will be present on the system that the software is being installed on. So they need to be included in your installer. From there you have two choices.
You can install them in your windows system folders or in your application folder. The difference is that if you install them in your application folder you can set things up on XP and Vista so that the different version of the software with different version of the components can be fired up and run side by side. Installing them into the system folder will break any older version that depend on older version of the components.
Installing in the application folder rarely doesn't work if a component depends on other components that can't be updated. When this occurs it is usually with with Microsoft libraries. They have gotten better over the years on this issue.
You can read more about the issues involving side by side execution here
Finally the dependencies need to be in your installer so that they are registered in the Windows Registry. Unlike most .NET assemblies any ActiveX/COM application needs to have the component registered in order to use it even if you are using CreateObject and Variant types to access it.
I will admit the whole process is idiosyncratic and is one of the sources for the stories about DLL Hell. Start with the MSDN article, use wikipedia, and of course ask further questions here.
You should usually not have a "dlls" folder under the app folder for a normal Installer package but there are many factors involved (private standard DLLs, Reg-Free COM, etc.). Yes, the dependencies get included (unless you exclude them). They should each have a property that determines where they install on the target systems.
You also have a number of components in that list that are either not redistributable this way because they are OS-dependent system components, MDAC components, or not licensed for redist (fm20.dll for example).
Sadly this is an example of the type of package that can lead directly to DLL Hell for your users' systems. Fixing this can mean researching every MS component in MS KB articles to determine what can or should be redistributed and how.
Deployment can be a messy business to get right.

Resources