I am finding that MS-Excel does not shut down if I read my entire spreadsheet 
of 4550 rows with Win32::OLE.  But if I read 500 rows and then close Excel and 
reopen it and read the next 500 rows (keeping track of where I left off) and 
continue this way to the end, then Excel closes down fine. Not sure why so I 
made a workaround as explained above. Must be a big memory overhead to read 
more than 500 rows without shutting down Excel when using Win32::OLE.   It 
could be something to do with running in conjunction with Win32::GUI.  Anybody 
had similar problems with OLE alone, or OLE and GUI  combined applications?
Thanks,
Eric
Garland, Texas USA


# This application transfers data from an Excel spreadsheet straight into an 
Access database.  Excel is shutdown
# after each read of 500 rows from the spreadsheet and restarted to read the 
next 500 rows and continued
# till all rows are read. The program keeps track of last record read in 
spreadsheet so knows where to begin
# reading of next 500 rows.

use Win32;
use Win32::GUI;
use Win32::ODBC;
use Win32::OLE;
use File::Copy;

$PWD=Win32::GetCwd();  # save application directory so ODBC knows where to look 
for MSAccess FILEDSN 
$FILEDSN="FILEDSN=$PWD\\MyAccessDB.dsn";

$M = new Win32::GUI::Menu(
    "&File"     => "File",
    " > &Port"  => "Port",
    " > E&xit"  => "Exit",
    "&Help"     => "Help",
    " > &About - Excel port to Access"  => "About",
);

$W = new Win32::GUI::Window(
    -title    => "Excel port to Access",
    -left     => 100, 
    -top      => 100, 
    -width    => 500, 
    -height   => 200,
    -menu     => $M,
    -style    => ws_sysmenu,
    -name     => "Window",
);

$B = new Win32::GUI::Bitmap("$PWD\\Logo.bmp"); 

$BITMAP = $W->AddLabel(
    -left => 0, 
    -top => 0,
    -style => 14 | WS_VISIBLE,
    -name => "Bitmap",
);
$BITMAP->SetImage($B);

$SFont = new Win32::GUI::Font(
    -name => "Courier New",
    -size => 8,
    -weight => 700,
    -height => -11,
);

$Status = $W->AddStatusBar(
    -name => "Status",
    -text => "Select menu option File->Port to begin.",
    -font => $SFont,
);

$W->Show();
$W->BringWindowToTop();

 #-------------------------------#
#     Event Handler 
#-------------------------------#
Win32::GUI::Dialog();

END {
   $db->Close;
   undef $db;
   $sheet->Close;
   undef $sheet;
   $book->Close;
   undef $book;
   $Excel->Quit;
   undef $Excel;
}

#------------------------------------#
#         Event Subroutines
#------------------------------------#

sub Exit_Click {
    return -1;   # exits the Win32 GUI Event Handler Win32::GUI::Dialog();
}

sub About_Click {
   $msg="";
   $msg=$msg . "Program:  Excel port to Access\n";
   $msg=$msg . " Version:  1.0\n";
   $msg=$msg . "     Date:   June 2002\n";
   $msg=$msg . "        By:  Eric Hansen\n";
    Win32::GUI::MessageBox($W,"$msg",
      "About -  Excel port to Access",64,);
}

sub Port_Click {
       
    # Open File DialogBox showing files with 
    # *.xls extension starting in application directory
    $file = "*.xls\0" . " " x 256;
    $file = Win32::GUI::GetOpenFileName(
        -owner => $W,
        -directory => $PWD,
        -title => "Select MS-Excel file to port to MS-Access", 
        -file => $file,
    );

    # if file is not valid, or contains no data, then return
    if (! -s $file) {
       Win32::GUI::MessageBox($W,"Microsoft Excel file notfound or is empty",
              "Excel port to Access - Error & Abort",16,);
       return -1;
    }
        
    $M->{'Exit'}->Enabled(0);  #-- Disable menu option
    $M->{'Port'}->Enabled(0);  #-- Disable menu option

    $Status->Text("Connecting.  Please wait...");
    $Status->Update();    
      
    $stat=copy("$PWD\\CopyOfMyAccessDB.mdb","$PWD\\MyAccessDB.mdb");  #-- 
File::Copy 
    if ($stat != 1) {
       $msg="Cannot COPY empty database file:\n" .
            "$PWD\\CopyOfMyAccessDB.mdb\n" .
            "to file:\n" .
            "$PWD\\MyAccessDB.mdb\n"; 
       Win32::GUI::MessageBox($W,$msg,
           "Excel port to Access - Error & Abort",16,);
       return -1;
    }       
              
    # connect to the MS-Access database      
    $db = new Win32::ODBC($FILEDSN);  
    if (! $db) {
        $error=Win32::ODBC::Error();
        Win32::GUI::MessageBox($W,
          "Can't Establish Database Connection using file 
DSN:\n$FILEDSN\n$error", 
          "Excel port to Access - Error & Abort",16,);
        return -1;
    }
        
    $exitwhileloop="N";   
    $cnt=0; 
    $j=1;
       
    # 500 times 130 = 65,000 which is max rows in an Excel spreadsheet 
worksheet.
    # We have to close Excel after each read of 500 records and restart Excel
    # otherwise Excel won't shutdown.  Some kind of memory problem develops. 
    
    while ($j <= 130) {
              
       if ($j > 1) {
          $sheet->Close;
          undef $sheet; 
          $book->Close;
          undef $book;
          $Excel->Quit;
          undef $Excel;
          $Excel = Win32::OLE->new('Excel.Application');
          $book  = $Excel->Workbooks->Open($file);
          $sheet = $book->Worksheets(1);
          $start=($stop + 1);
          $i=$start;
          $stop=($start + 499);
       } else {
          $Excel = Win32::OLE->new('Excel.Application');
          $book  = $Excel->Workbooks->Open($file);
          $sheet = $book->Worksheets(1);
          $i=2;
          $start=2;
          $stop=500;
       }
           
       for ($i=$start;$i<=$stop;$i++) {
             
         # build the sql insert statement
         $sqltxt="INSERT INTO MyAccessTBL VALUES (";    
        
         $cell="A" . $i;
         $market=$sheet->Range($cell)->{Value};
         $market=~s/\'/\"/g;
         $sqltxt=$sqltxt . "'" . $market . "'";
                  
         $cell="B" . $i;
         $custnbr=$sheet->Range($cell)->{Value};
         $custnbr=~s/\'/\"/g;
         $sqltxt=$sqltxt . ",'" . $custnbr . "'";
         
         $cell="C" . $i;
         $custname=$sheet->Range($cell)->{Value};
         $custname=~s/\'/\"/g;
         $sqltxt=$sqltxt . ",'" . $custname . "'";
                
         $cell="F" . $i;
         $current=sprintf("%9.2f",($sheet->Range($cell)->{Value}));
         $sqltxt=$sqltxt . "," . $balance;

        if ($market eq "" || $market eq " ") {
             # this check tells us when we are at the end of our data since we 
know in this case
             # that market field should not be blank.  Otherwise we would 
continue reading to the
             # 65,000th row in the spreadsheet which is a waste of time.  
             $exitwhileloop="Y";
             last;
         }
                      
         #######################################################      
         # execute the insert statement and get return status
         #######################################################
         $ret=$db->Sql($sqltxt);  
         if ($ret) {
             $error=$db->Error;  # capture the sql error message
                                  
             Win32::GUI::MessageBox($W,"$error\n$sqltxt",
                   "Excel port to Access - SQL Error($ret)",16,);
             return -1;  
         }

         $cnt++;
         
         $Status->Text($cnt);
         $Status->Update();
         
         Win32::GUI::DoEvents();  # keep screen refreshed
         
       } # end of for loop
       
       if ($exitwhileloop eq "Y") {
           last;
       }
       
       $j++;
       
    } # end of while loop
    
      
    Win32::GUI::MessageBox($W,"There were $cnt records ported to MS-Access.", 
            "Excel port to Access - Process Complete.",64,);
          
    $Status->Text("Exiting Program  - Please wait ...");
    $Status->Update();
    sleep 3;
   
    return -1;        
   
}  # Port_Click event


# End Script

Reply via email to