Programming tools

Refactor

I commonly find that a body of code gets littered with cut-and-paste after awhile. So I developed a tool that I thought would help in identifying the sections that need to be refactored since duplicated code can be reduced. Refactor finds duplicated segments of text that are at least four lines long and where the duplication does not start with an empty line, a solo {, or a solo }. (My roots are in C/C++, don't you know.)

Refactor is a .NET binary and requires the 1.0 framework. It runs on the command line and sends its findings to stdout. The only command line arguments are file names or the name of a file that contains a list of files to operate on.

Sample usage:

refactor *.cs

Or:

dir /S /B *.cpp > list
refactor @list > result

Get refactor.zip here!

Referring links:


ObjectCreator

If you have to use VB5 (or earlier) and you have to create objects remotely without using DCOMCNFG, then you might be interested in this ATL/C++ code to do precisely this.

Sample usage:

Option Explicit

Dim obj
Set obj = CreateObject ("ObjectCreator.Creator.1")
MsgBox "Got the creator object"

Dim RemoteObject
Set RemoteObject = obj.NewObject ("ARBSimulationEngine_54", "WINDOK")
MsgBox "Got the target object"

Set RemoteObject = Nothing
Set obj = Nothing

MsgBox "Done"

Get the source!


CoWhereIs

One of the major irritations of COM development is that you frequently have multiple copies of your servers around but they do not match the one you think you are using. CoWhereIs provides answers to the questions:

  • Where is the component?
  • Is the DLL/EXE actually there?
  • CoWhereIs is a command line program that takes CLSIDs, either as GUIDs or as ProgIDs, as arguments. This script:

    CoWhereIs ArbReport.Engine
    CoWhereIs ArbAggregator.Aggregator
    CoWhereIs ArbStart.Factory
    CoWhereIs CurveBookServer
    CoWhereIs ARBReportOcx.ARBReport
    CoWhereIs ARBReportOcx.ReportEngineInterface
    CoWhereIs ArbEngine
    CoWhereIs ARBBlob.BlobObject
    

    Produces this output:

    LocalServer32 ArbReport.Engine is at D:\AskariRiskBook53a\bin\ARBReportEngine.EXE
    LocalServer32 ArbAggregator.Aggregator is at C:\TEMP\ARBAggregator.exe
    InprocServer32 ArbStart.Factory is at D:\AskariRiskBook53a\bin\ARBStart.dll
    LocalServer32 CurveBookServer is at D:\AskariRiskBook53aa\bin\CurveBookServer.EXE
    INFO: File D:\AskariRiskBook53aa\bin\CurveBookServer.EXE does not exist
    InprocServer32 ARBReportOcx.ARBReport is at D:\AskariRiskBook53aa\bin\ARBReport.OCX
    INFO: File D:\AskariRiskBook53aa\bin\ARBReport.OCX does not exist
    LocalServer32 ArbEngine is at D:\AskariRiskBook53a\bin\Simulation.EXE
    InprocServer32 ARBBlob.BlobObject is at C:\ASKARI~1\src\Blob\Debug\ARBBlob.dll
    INFO: File C:\ASKARI~1\src\Blob\Debug\ARBBlob.dll does not exist
    

    Notice that it says that some of the components are not physically present, even though CoWhereIs indicates they are the components that COM will use. These will cause errors at runtime.

    Disclaimer: tested in NT 4.0 up to SP4. No promises for NT 5.0.

    Get CoWhereIs.EXE here!


    ADO recordsets

    Source code for using ADO recordsets

    People in the DCOM mailing list have asked me for the source code I offered for using ADO disconnected recordsets from the client. Well, here it is. There are several disclaimers that apply, including:

  • I was interested in connectionless ADO recordsets where there never was a relational database connection on the server. I wanted to return recordsets from a server and was trying out a large number of methods. This may not describe your circumstances.
  • All methods make one call per row returned. This may not suit your purposes.
  • The ADO recordsets use no caching and are not generated asynchronously. In general, they make no use of optimizations that might speed them up.
  • On the plus side, I don't know of any published code that shows how to do this at all (i.e. without any OLEDB data source), so there may still be some value to you.

    If you make changes to the source code or otherwise make worthwhile discoveries, please let me know. I would be interested. I have heard that rs.CacheSize would help performance, but I have not tested this.

    RetData.zip contains the server code.

    VCText.zip contains the VC++ 6.0 client code.

    Here are some related links on ADO that you may find useful:


    Reference counting template

    Occasionally, it is really useful to be able to create an object and add reference counting semantics to it apart from its identity as an object. I find this particularly useful with COM when a parent object owns some functionality but still has to pass it on to its child objects. I don't like having children with references to their parents, so I give the parent and the child a reference to the object wrapped in a reference counting template.

    RefTemplate.h contains the C++ code.

    Here is sample code to demonstrate its use:

    #include "stdafx.h"
    #include "RefTemplate.h"
    
    class Foo
    {
    public:
    	Foo ()
    	{
    		printf ("Foo\n");
    	}
    	~Foo ()
    	{
    		printf ("~Foo\n");
    	}
    
    	char *Hello ()
    	{
    		printf ("Foo::Hello! (%08lx)\n", (long) this);
    		return "Hello";
    	}
    };
    
    class Bar
    {
    public:
    	RefTemplate<Foo> x;
    	long z;
    public:
    	Bar ()
    		:	z(42)
    	{
    		printf ("Bar\n");
    	}
    	void Init (Foo *ptr)
    	{
    		x = RefTemplate<Foo>(ptr);
    	}
    	~Bar ()
    	{
    		printf ("~Bar\n");
    	}
    };
    
    int main(int argc, char* argv[])
    {
    	Bar bar_x, bar_y, bar_z;
    
    	printf ("\nMade x and z\n\n");
    
    	Foo *y = new Foo;
    	printf ("\nMade Foo\n\n");
    
    	bar_x.Init (y);
    	printf ("\nx.Init done\n\n");
    
    	bar_z = bar_x;
    	bar_y = bar_z;
    	bar_x = bar_y;
    	bar_z = bar_x;
    	bar_y = bar_z;
    	bar_x = bar_y;
    
    	printf ("\nassignments Done\n\n");
    
    	Foo *tmp = (Foo *) bar_x.x; //bar_x.x;
    	tmp->Hello ();
    	bar_z.x->Hello ();
    
    	Bar *b = &bar_z;
    	printf ("Bar::z = %ld\n", b->z);
    	printf ("Bar::Hello = %s\n", b->x->Hello());
    
    	printf ("\nx.x->Hello() done\n\n");
    
    	return 0;
    }
    

    © 2001-3 Hugh Brown. All rights reserved.