home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 32 / IOPROG_32.ISO / SOFT / SqlEval7 / devtools / samples / BACKUP / simple.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-30  |  9.0 KB  |  335 lines

  1. //
  2. // This file is part of Microsoft SQL Server online documentation.
  3. // Copyright (C) 1992-1997 Microsoft Corporation. All rights reserved.
  4. //
  5. // This source code is an intended supplement to the Microsoft SQL
  6. // Server online references and related electronic documentation.
  7. //
  8. // This sample is for instructional purposes only.
  9. // Code contained herein is not intended to be used "as is" in real applications.
  10. // 
  11. // simple.cpp
  12. //
  13. // This is a sample program used to demonstrate the Virtual Device Interface
  14. // feature of Microsoft SQL Server.
  15. //
  16. // The program will backup or restore the 'pubs' sample database.
  17. //
  18. // The program accepts a single command line parameter.  
  19. // One of:
  20. //  b   perform a backup
  21. //  r   perform a restore
  22. //  
  23.  
  24.  
  25. // To gain access to free threaded COM, you'll need to define _WIN32_DCOM
  26. // before the system headers, either in the source (as in this example),
  27. // or when invoking the compiler (by using /D "_WIN32_DCOM")
  28. //
  29. #define _WIN32_DCOM
  30.  
  31. #include <objbase.h>    // for 'CoInitialize()'
  32. #include <stdio.h>      // for file operations
  33. #include <ctype.h>      // for toupper ()
  34. #include <process.h>    // for spawn ()
  35.  
  36. #include "vdi.h"        // interface declaration
  37. #include "vdierror.h"   // error constants
  38.  
  39. #include "vdiguid.h"    // define the interface identifiers.
  40.             // IMPORTANT: vdiguid.h can only be included in one source file.
  41.             // 
  42.  
  43.  
  44. void performTransfer (
  45.     IClientVirtualDevice*   vd,
  46.     int                     backup );
  47.  
  48. int execSQL (int doBackup);
  49.  
  50.  
  51.  
  52. //
  53. // main function
  54. //
  55. int main(int argc, char *argv[])
  56. {
  57.     HRESULT                     hr;
  58.     IClientVirtualDeviceSet*    vds = NULL ; 
  59.     IClientVirtualDevice*       vd=NULL;
  60.  
  61.     VDConfig                    config;
  62.     int                         badParm=TRUE;
  63.     int                         doBackup;
  64.     int                         hProcess;
  65.     int                         termCode;
  66.  
  67.     // Check the input parm
  68.     //
  69.     if (argc == 2)
  70.     {
  71.         if (toupper(argv[1][0]) == 'B')
  72.         {
  73.             doBackup = TRUE;
  74.             badParm = FALSE;
  75.         }
  76.         else if (toupper(argv[1][0]) == 'R')
  77.         {
  78.             doBackup = FALSE;
  79.             badParm = FALSE;
  80.         }
  81.     }
  82.  
  83.     if (badParm)
  84.     {
  85.         printf ("useage: simple {B|R}\n"
  86.             "Demonstrate a Backup or Restore using the Virtual Device Interface\n");
  87.         exit (1);
  88.     }
  89.  
  90.     printf ("Performing a %s using a virtual device.\n", 
  91.         (doBackup) ? "BACKUP" : "RESTORE");
  92.  
  93.     // Initialize COM Library
  94.     // Note: _WIN32_DCOM must be defined during the compile.
  95.     //
  96.     hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  97.  
  98.     if (!SUCCEEDED (hr))
  99.     {
  100.         printf ("Coinit fails: x%X\n", hr);
  101.         exit (1);
  102.     }
  103.  
  104.     // Get an interface to the device set.
  105.     // Notice how we use a single IID for both the class and interface
  106.     // identifiers.
  107.     //
  108.     hr = CoCreateInstance ( 
  109.         IID_IClientVirtualDeviceSet,
  110.         NULL, 
  111.         CLSCTX_INPROC_SERVER,
  112.         IID_IClientVirtualDeviceSet,
  113.         (void**)&vds);
  114.  
  115.     if (!SUCCEEDED (hr))
  116.     {
  117.         // This failure might happen if the DLL was not registered,
  118.     // or if the application is using the wrong interface id (IID).
  119.         //
  120.         printf ("Could not create component: x%X\n", hr);
  121.         printf ("Check registration of SQLVDI.DLL and value of IID\n");
  122.         goto exit;
  123.     }
  124.  
  125.     // Setup the VDI configuration we want to use.
  126.     // This program doesn't use any fancy features, so the
  127.     // only field to setup is the deviceCount.
  128.     //
  129.     // The server will treat the virtual device just like a pipe:
  130.     // I/O will be strictly sequential with only the basic commands.
  131.     //
  132.     memset (&config, 0, sizeof(config));
  133.     config.deviceCount = 1;
  134.  
  135.     // Create the virtual device set
  136.     //
  137.     hr = vds->Create (L"SUPERBAK", &config);
  138.     if (!SUCCEEDED (hr))
  139.     {
  140.         printf ("VDS::Create fails: x%X", hr);
  141.         goto exit;
  142.     }
  143.  
  144.     // Send the SQL command, by starting 'isql' in a subprocess.
  145.     //
  146.     printf("\nSending the SQL...\n");
  147.  
  148.     hProcess = execSQL (doBackup);
  149.     if (hProcess == -1)
  150.     {
  151.         printf ("execSQL failed.\n");
  152.         goto shutdown;
  153.     }
  154.  
  155.     // Wait for the server to connect, completing the configuration.
  156.     //
  157.     hr = vds->GetConfiguration (10000, &config);
  158.     if (!SUCCEEDED (hr))
  159.     {
  160.         printf ("VDS::Getconfig fails: x%X\n", hr);
  161.         if (hr == VD_E_TIMEOUT)
  162.         {
  163.             printf ("Timed out. Was Microsoft SQLServer running?\n");
  164.         }
  165.         goto shutdown;
  166.     }
  167.  
  168.     // Open the single device in the set.
  169.     //
  170.     hr = vds->OpenDevice (L"SUPERBAK", &vd);
  171.     if (!SUCCEEDED(hr))
  172.     {
  173.         printf ("VDS::OpenDevice fails: x%X\n", hr);
  174.         goto shutdown;
  175.     }
  176.  
  177.     printf ("\nPerforming data transfer...\n");
  178.     
  179.     performTransfer (vd, doBackup);
  180.     
  181.     
  182. shutdown:
  183.  
  184.     // Close the set
  185.     //
  186.     vds->Close ();
  187.  
  188.     // Obtain the SQL completion information, by waiting for isql to exit.
  189.     //
  190.     if (hProcess == _cwait( &termCode, hProcess, NULL))
  191.     {
  192.         if (termCode == 0)
  193.             printf("\nThe SQL command executed successfully.\n");
  194.         else
  195.             printf("\nThe SQL command failed.\n");
  196.     }
  197.     else
  198.     {
  199.         printf ("cwait failed: %d\n", errno);
  200.     }
  201.  
  202.     // COM reference counting: Release the interface.
  203.     //
  204.     // Rather than releasing it, the application has the
  205.     // option to 'Create' another set, reusing the interface
  206.     // that it currently has.  Of course that applies to 
  207.     // a real application, not this simple sample!
  208.     //
  209.     vds->Release () ;
  210.  
  211. exit:
  212.  
  213.     // Uninitialize COM Library
  214.     //
  215.     CoUninitialize () ;
  216.  
  217.     return 0 ;
  218. }
  219.  
  220. //
  221. // Execute a basic backup/restore, by spawning a process to execute 'isql'.
  222. //
  223. // Returns:
  224. //  -1      : failed to spawn
  225. //  else    : a "process handle" 
  226. //
  227. int execSQL (int doBackup)
  228. {
  229.     const char *const bCmd = "-Q\"BACKUP DATABASE PUBS TO VIRTUAL_DEVICE='SUPERBAK'\"";
  230.  
  231.     const char *const rCmd = "-Q\"RESTORE DATABASE PUBS FROM VIRTUAL_DEVICE='SUPERBAK'\"";
  232.     int rc;
  233.  
  234.     // Spawn off the isql utility to execute the SQL.
  235.     // Notice the '-b' which causes an error to set a non-zero
  236.     // exit code on error.
  237.     //
  238.     rc = _spawnlp( _P_NOWAIT, "isql", "isql", "-Usa", "-P", "-b",
  239.         (doBackup) ? bCmd : rCmd, NULL);
  240.  
  241.     if (rc == -1)
  242.     {
  243.         printf ("Spawn failed with error: %d\n", errno);
  244.     }
  245.     
  246.     return (rc);
  247. }
  248.  
  249. // This routine reads commands from the server until a 'Close' status is received.
  250. // It simply reads or writes a file 'superbak.dmp' in the current directory.
  251. //
  252. void performTransfer (
  253.     IClientVirtualDevice*   vd,
  254.     int                     backup )
  255. {
  256.     FILE *          fh;
  257.     char*           fname = "superbak.dmp";
  258.     VDC_Command *   cmd;
  259.     DWORD           completionCode;
  260.     DWORD           bytesTransferred;
  261.     HRESULT         hr;
  262.  
  263.     fh = fopen (fname, (backup)? "wb" : "rb");
  264.     if (fh == NULL )
  265.     {
  266.         printf ("Failed to open: %s\n", fname);
  267.         return;
  268.     }
  269.  
  270.     while (SUCCEEDED (hr=vd->GetCommand (INFINITE, &cmd)))
  271.     {
  272.         bytesTransferred = 0;
  273.         switch (cmd->commandCode)
  274.         {
  275.             case VDC_Read:
  276.                 bytesTransferred = fread (cmd->buffer, 1, cmd->size, fh);
  277.                 if (bytesTransferred == cmd->size)
  278.                     completionCode = ERROR_SUCCESS;
  279.                 else
  280.                     // assume failure is eof
  281.                     completionCode = ERROR_HANDLE_EOF;
  282.                 break;
  283.  
  284.             case VDC_Write:
  285.                 bytesTransferred = fwrite (cmd->buffer, 1, cmd->size, fh);
  286.                 if (bytesTransferred == cmd->size )
  287.                 {
  288.                     completionCode = ERROR_SUCCESS;
  289.                 }
  290.                 else
  291.                     // assume failure is disk full
  292.                     completionCode = ERROR_DISK_FULL;
  293.                 break;
  294.  
  295.             case VDC_Flush:
  296.                 fflush (fh);
  297.                 completionCode = ERROR_SUCCESS;
  298.                 break;
  299.     
  300.             case VDC_ClearError:
  301.                 completionCode = ERROR_SUCCESS;
  302.                 break;
  303.  
  304.             default:
  305.                 // If command is unknown...
  306.                 completionCode = ERROR_NOT_SUPPORTED;
  307.         }
  308.  
  309.         hr = vd->CompleteCommand (cmd, completionCode, bytesTransferred, 0);
  310.         if (!SUCCEEDED (hr))
  311.         {
  312.             printf ("Completion Failed: x%X\n", hr);
  313.             break;
  314.         }
  315.     }
  316.  
  317.     if (hr != VD_E_CLOSE)
  318.     {
  319.         printf ("Unexpected termination: x%X\n", hr);
  320.     }
  321.     else
  322.     {
  323.         // As far as the data transfer is concerned, no
  324.         // errors occurred.  The code which issues the SQL
  325.         // must determine if the backup/restore was
  326.         // really successful.
  327.         //
  328.         printf ("Successfully completed data transfer.\n");
  329.     }
  330.  
  331.     fclose (fh);
  332. }
  333.  
  334.  
  335.