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