/***********************************************************************/ /* Copyright (C) 2002 Definitive Solutions, Inc. All Rights Reserved. */ /* THIS COMPUTER PROGRAM IS PROPRIETARY AND CONFIDENTIAL TO DEFINITIVE */ /* SOLUTIONS, INC. AND ITS LICENSORS AND CONTAINS TRADE SECRETS OF */ /* DEFINITIVE SOLUTIONS, INC. THAT ARE PROVIDED PURSUANT TO A WRITTEN */ /* AGREEMENT CONTAINING RESTRICTIONS ON USE AND DISCLOSURE. ANY USE, */ /* REPRODUCTION, OR TRANSFER EXCEPT AS PROVIDED IN SUCH AGREEMENT */ /* IS STRICTLY PROHIBITED. */ /***********************************************************************/ ///////////////////////////////////////////////////////////////////////////// // How to add this class to your application. // // Add MyExporter.cpp and MyExporter.h to your project in the usual folders. // // This is a very simple implementation of writing to various file types, // using (mostly) ADO. The intention is to provide exporting support to // applications as simply as possible. // // Here is what is not included in this class. Reading is not supported, // as it is not needed for exporting, and excluding it makes the code much, // much simpler. Transactions are not supported; writing is "direct access", // and there's no rollback; again, for exporting use, this is acceptable. ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Example usage: // // If you don't need to refer to the Exporter object polymorphically, you can // just instantiate one of the subclasses and use it like this: // // CStringArray saHeaders; // saHeaders.Add("Animal"); // saHeaders.Add("Vegetable"); // saHeaders.Add("Mineral"); // // MyExcelExporter mdfe; // mdfe.OpenExportFile("c:\\temp\\MySpreadsheet.xls", saHeaders); // // CStringArray saValues; // // saValues.Add("Aardvark"); // saValues.Add("Apple"); // saValues.Add("Calcium"); // mdfe.AppendRow(saValues); // // saValues.RemoveAll(); // saValues.Add("Bear"); // saValues.Add("Bean"); // saValues.Add("Boron"); // mdfe.AppendRow(saValues); // // Otherwise, if you don't know until runtime which one you'll need (perhaps // based on user input), you can use this procedure: // // CStringArray saHeaders; // saHeaders.Add("Animal"); // saHeaders.Add("Vegetable"); // saHeaders.Add("Mineral"); // // CString sExt(GetExportTypeFromUserInput()); // IMyExporter* pMyExporter = IMyExporter::Create(sExt); // pMyExporter->OpenExportFile("c:\\temp\\MySpreadsheet.xls", saHeaders); // // CStringArray saValues; // // saValues.Add("Aardvark"); // saValues.Add("Apple"); // saValues.Add("Calcium"); // pMyExporter->AppendRow(saValues); // // saValues.RemoveAll(); // saValues.Add("Bear"); // saValues.Add("Bean"); // saValues.Add("Boron"); // pMyExporter->AppendRow(saValues); // // delete pMyExporter; // pMyExporter = NULL; // // This second method uses the "parameterized Factory Method" design pattern // (sort of - I didn't need to create a separate class, so I just used a // static method). This allows your client code to not know until runtime // which subclass will be created. For more info on design patterns, see // "Design Patterns", Gamma et al., 1995, Addison Wesley Longman, Inc. ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // How to add another file type // // This code has been written to make it easy to add a new file type. All you // have to do is derive a new class from IMyExporter, implement three trivial // pure virtual functions, add an entry to IMyExporter::Create(), and add an // entry to IMyExporter::GetExportFormats(). That's it - now you can use your // new class just as you would MyExcelExporter. Behold, the power of object- // oriented design. // // NOTE: If you need to add new functionality to a derived class, you should // consider whether it makes sense to add it as a pure virtual function in the // base class IMyExporter, and then implement it in all derived classes. That // is the preferred way (assuming the new functionality you are adding has // analogues in all the derived classes, which it may not). ///////////////////////////////////////////////////////////////////////////// #if !defined(AFX_MYEXPORTER_H__262D9531_4C8A_11D6_8AE5_00B0D0529ED2__INCLUDED_) #define AFX_MYEXPORTER_H__262D9531_4C8A_11D6_8AE5_00B0D0529ED2__INCLUDED_ #pragma once // "Unary minus operator applied to unsigned type, result still unsigned." #pragma warning (disable : 4146) // Microsoft ADO. Look in "C:\Program Files\Common Files\system\ado". #import "msado15.dll" rename("EOF", "adoEOF") using namespace ADODB; ///////////////////////////////////////////////////////////////////////////// // IMyExporter abstract base class (interface) class IMyExporter { // Construction. public: IMyExporter(); virtual ~IMyExporter() = 0; // Interface. The entire public interface is described here. The derived // classes DO NOT have any public methods or data; they're pure implementation. public: // Open the file. Requires the fully qualified pathname. The file MUST NOT // already exist. HRESULT OpenExportFile(IN const CString& sPath, IN const CStringArray& saHeaders); // Appends a row given the sent values. HRESULT AppendRow(IN const CStringArray& saValues); // This is what is referred to as a "parameterized Factory Method" , or // "virtual constructor". It instantiates a derived object based on the // three-letter extension passed in. If you add a new derived class, be // sure to update this method. The caller is responsible for deleting the // returned object. static IMyExporter* Create(IN const CString& sExt); // This returns a list of supported types; if you add a new derived class, // be sure to update this method. (You might use this to, say, populate // a combobox.) static void GetExportFormats(OUT CStringArray& saFormats); // Overrides. These methods must be overridden by derived classes. protected: // Create a new file from the sent path and headers. virtual HRESULT MakeNewFile(IN const CString& sPath, IN const CStringArray& saHeaders) const = 0; // Given the file name, return the connection string. virtual HRESULT GetConnectionString(IN const CString& sPath, OUT CString& sConn) const = 0; // Given the file name, return the select string for the recordset. virtual HRESULT GetSelectString(IN const CString& sPath, OUT CString& sSelect) const = 0; // Data. protected: _ConnectionPtr m_Connection; // ADO connection. _RecordsetPtr m_Recordset; // ADO recordset. CStringArray m_saHeaders; // Header values. }; ///////////////////////////////////////////////////////////////////////////// // MyExcelExporter - Excel spreadsheet writer class MyExcelExporter : public IMyExporter { // Construction. public: MyExcelExporter(); /* pure */ virtual ~MyExcelExporter(); // Overrides. protected: // Create a new file from the sent path and headers. /* pure */ virtual HRESULT MakeNewFile(IN const CString& sPath, IN const CStringArray& saHeaders) const; // Given the file name, return the connection string. /* pure */ virtual HRESULT GetConnectionString(IN const CString& sPath, OUT CString& sConn) const; // Given the file name, return the select string for the recordset. /* pure */ virtual HRESULT GetSelectString(IN const CString& sPath, OUT CString& sSelect) const; }; ///////////////////////////////////////////////////////////////////////////// // MyCsvExporter - CSV (Comma Separated Values) writer class MyCsvExporter : public IMyExporter { // Construction. public: MyCsvExporter(); /* pure */ virtual ~MyCsvExporter(); // Overrides. protected: // Create a new file from the sent path and headers. /* pure */ virtual HRESULT MakeNewFile(IN const CString& sPath, IN const CStringArray& saHeaders) const; // Given the file name, return the connection string. /* pure */ virtual HRESULT GetConnectionString(IN const CString& sPath, OUT CString& sConn) const; // Given the file name, return the select string for the recordset. /* pure */ virtual HRESULT GetSelectString(IN const CString& sPath, OUT CString& sSelect) const; }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MYEXPORTER_H__262D9531_4C8A_11D6_8AE5_00B0D0529ED2__INCLUDED_)