Você está na página 1de 17

Estava procurando no forum mas no achei o que eu gostaria, preciso chamar o Excel via delphi 7 e juntamente com a chamada

abrir uma planilha que se encontra em outra pasta. Utilizo o XP Home.

ShellExecute(Handle, nil, PChar(\'c:\\meus documentos\\teste1.xls\'), nil, nil, SW_SHOWNORMAL)

declarar: ShellApi

Delphi Abrir arquivo de qualquer extenso


Delphi

adicionar clusula uses da unit: ComObj var Msword: Variant; procedure TForm1.Button1Click(Sender: TObject); begin Msword:=createoleObject("Word.Basic"); Msword.AppShow; Msword.fileopen("c:\documento.doc"); end; adicionar clusula uses da unit: ShellApi procedure TForm1.Button1Click(Sender: TObject); begin ShellExecute(handle,nil,"winword.exe","c:\DadosLaurinha.doc",nil,sw_ShowMaximized); end; var caminho: string; begin caminho := "D:\Meus documentos\VigilanciaSanit\Fontes\Nice.doc"; if (fileExists(caminho)) then ShellExecute(Handle, nil, Pchar(caminho), nil, nil, SW_SHOWNORMAL); end;

procedure TForm1.Button1Click(Sender: TObject); var objExcel,Sheet,Chart,s : Variant; cTitulo : string; i : integer; begin //OBS: Voce deve usar a Clausula ComObj no USES para usar o EXCEL // Utilize tambm a Clausula Clipbrd pois neste exemplo faremos uso da memria // Cria uma instancia para utilizar o Excel cTitulo := 'Planilha de Teste'; objExcel := CreateOleObject('Excel.Application'); objExcel.Visible := True; objExcel.Caption := cTitulo; // Caso queria abrir uma planilha ao invz de gera-la use os comandos abaixo //objExcel.Workbooks.Open('c:\teste.xls'); //Sheet := objExcel.Workbooks[1].WorkSheets[cTitulo]; // Daqui em diante os comandos na Planilha so os mesmos do resto do Exemplo //Sheet.Range['A1','Z70'].Replace('Nome','Alterado'); // Adiciona planilha(sheet) objExcel.Workbooks.Add; objExcel.Workbooks[1].Sheets.Add; objExcel.Workbooks[1].WorkSheets[1].Name := cTitulo; Sheet := objExcel.Workbooks[1].WorkSheets[cTitulo]; // possivel copiar um valor da memria diretamente para a planilha // mas como no se tem controle de onde ele ser colado, este processo pode // ser meio inconveniente //Clipboard.AsText := 'Linha Copiada para Memria'; //Sheet.paste; // Nota: // Pode-se preencher as linhas usando o comando abaixo, desta forma vc usaria // a planilha como se ela fosse uma Array, em alguns casos pode ser interessante // mas no geral considero bem mais trabalhoso, abaixo demonstro outra forma de trabalho // usando o RANGE que torna o trabalho bem mais simples //Sheet.Cells[1,1] := 'Coluna[1,1]'; // Preenchendo as Colunas // Usando o RANGE vc pode preencher vrias colunas ao mesmo tempo usando ['A1','A10'] // Ou preencher apenas uma usando ['A1'], isso torna o processo gil e simples Sheet.Range['A1'] := 'Cdigo'; Sheet.Range['B1'] := 'Nome'; Sheet.Range['C1'] := 'Fone'; Sheet.Range['D1'] := 'Salrio'; // por aqui tu limparias a planilha

// No caso do FOR se torna interessante usar o SHEET.CELLS (veja como)

// Atente que usei o FOR a partir do numero 2 desta forma pularemos a // primeira linha que ja contem um cabealho preenchido acima for i := 2 to 10 do begin Sheet.Cells[i,1] := i; Sheet.Cells[i,2] := 'Nome Cliente '+inttostr(i); Sheet.Cells[i,3] := 'Fone Cliente '+inttostr(i); // Formata o Numero para se tornar MOEDA Sheet.Cells[i,4].NumberFormat := 'R$ #.##0,00_);(R$ #.##0,00)'; Sheet.Cells[i,4] := 1000*i; end; // Formatando o Cabealho Sheet.Range['A1','D1'].font.name := 'Verdana'; // Fonte Sheet.Range['A1','D1'].font.size := 12; // Tamanho da Fonte Sheet.Range['A1','D1'].font.bold := true; // Negrito Sheet.Range['A1','D1'].font.italic := true; // Italico Sheet.Range['A1','D1'].font.color := clYellow; // Cor da Fonte Sheet.Range['A1','D1'].Interior.Color := $00ffcf9c; // Cor da Clula // Define o tamanho das Colunas (basta fazer em uma delas e as demais sero alteradas) Sheet.Range['B1','C1' ].ColumnWidth := 27; Sheet.Range['B1','C1' ].RowHeight := 25; Sheet.Range['D1'] .ColumnWidth := 16; // Outras formas de Formatar Sheet.Range['E1'] := 'Subscrito'; Sheet.Range['E2'] := 'Superescrito'; Sheet.Range['E3'] := 'Sublinhado'; Sheet.Range['E4'] := 'Strike'; Sheet.Range['E1'].font.Subscript := true; // Subscrito Sheet.Range['E2'].font.Superscript := true; // Superescrito Sheet.Range['E3'].font.Underline := true; // Sublinhado Sheet.Range['E4'].font.Strikethrough := true; // Strike // Colocando a Borda em um unico lado da Clula Sheet.Range['E5'].Font.size := 7; Sheet.Range['E5'].ColumnWidth := 20; Sheet.Range['E5'] := 'S um lado da Celula com Borda'; Sheet.Range['E5'].Borders.Item[$00000009].Weight := $FFFFEFD6; Sheet.Range['E5'].Borders.Item[$00000009].Color := clRed; //-- Espessura da Linha //======================== {xlHairline = $00000001; xlMedium = $FFFFEFD6; xlThick = $00000004; xlThin = $00000002;} //-- Posio da Celula que se deseja colocar a Borda //===================================================== {xlInsideHorizontal = $0000000C; xlInsideVertical = $0000000B; xlDiagonalDown = $00000005; xlDiagonalUp = $00000006; xlEdgeBottom = $00000009; xlEdgeLeft = $00000007; xlEdgeRight = $0000000A; xlEdgeTop = $00000008;} // Incluindo Formulas (a formula deve ser incluida com seu nome original em Ingls // caso contrrio podera ocorrer problemas) Sheet.Cells[i,3] := 'Total R$';

// Na linha abaixo inclui uma soma e converti para Moeda atravez do NUMBERFORMAT Sheet.Cells[i,4].NumberFormat := 'R$ #.##0,00_);(R$ #.##0,00)'; Sheet.Cells[i,4].formula := '=SUM(D210)'; // Alinhando as Clulas Sheet.Range['A1'].VerticalAlignment := 1; // 1=Top - 2=Center - 3=Bottom Sheet.Range['B1'].VerticalAlignment := 2; Sheet.Range['C1'].VerticalAlignment := 3; Sheet.Range['B1'].HorizontalAlignment := 3; // 3=Center - 4=Right Sheet.Range['C1'].HorizontalAlignment := 3; Sheet.Range['D1'].HorizontalAlignment := 4; // Adiciona Grade nas Colunas Sheet.Range['A1','D11'].Borders.LineStyle := 1; Sheet.Range['A1','D11'].Borders.Weight := 2; Sheet.Range['A1','D11'].Borders.ColorIndex := 1; // Excecuta um Replace na Celula localizada // Lembre-se que ele alterara todas as celulas localizadas dentro // do RANGE escolhido, ou seja, se ouverem 10 Colunas com o texto // desejado este comando alterara as 10 Sheet.Range['A1','Z70'].Replace('Fone Cliente 10','Repassou o Texto'); // Cria Grafico Sheet.ChartObjects.Add(10,160,450,130); // Coordenadas (Left,Top,Width,Height) Chart := Sheet.ChartObjects[1]; // Cria o Grafico Chart.Chart.ChartType := $FFFFEFFA; // Tipo do Grafico (veja tabela abaixo) Chart.Chart.SeriesCollection.Add(Sheet.Range['D210']); // Pode-se dar um PrintPreview apenas no Grfico, use o comando abaixo //Chart.Chart.PrintPreview; //--TIPOS DE GRAFICOS //====================== {xlColumnClustered = $00000033; xlColumnStacked = $00000034; xlColumnStacked100 = $00000035; xl3DColumnClustered = $00000036; xl3DColumnStacked = $00000037; xl3DColumnStacked100 = $00000038; xlBarClustered = $00000039; xlBarStacked = $0000003A; xlBarStacked100 = $0000003B; xl3DBarClustered = $0000003C; xl3DBarStacked = $0000003D; xl3DBarStacked100 = $0000003E; xlLineStacked = $0000003F; xlLineStacked100 = $00000040; xlLineMarkers = $00000041; xlLineMarkersStacked = $00000042; xlLineMarkersStacked100 = $00000043; xlPieOfPie = $00000044; xlPieExploded = $00000045; xl3DPieExploded = $00000046; xlBarOfPie = $00000047; xlXYScatterSmooth = $00000048; xlXYScatterSmoothNoMarkers = $00000049; xlXYScatterLines = $0000004A; xlXYScatterLinesNoMarkers = $0000004B; xlAreaStacked = $0000004C;

xlAreaStacked100 = $0000004D; xl3DAreaStacked = $0000004E; xl3DAreaStacked100 = $0000004F; xlDoughnutExploded = $00000050; xlRadarMarkers = $00000051; xlRadarFilled = $00000052; xlSurface = $00000053; xlSurfaceWireframe = $00000054; xlSurfaceTopView = $00000055; xlSurfaceTopViewWireframe = $00000056; xlBubble = $0000000F; xlBubble3DEffect = $00000057; xlStockHLC = $00000058; xlStockOHLC = $00000059; xlStockVHLC = $0000005A; xlStockVOHLC = $0000005B; xlCylinderColClustered = $0000005C; xlCylinderColStacked = $0000005D; xlCylinderColStacked100 = $0000005E; xlCylinderBarClustered = $0000005F; xlCylinderBarStacked = $00000060; xlCylinderBarStacked100 = $00000061; xlCylinderCol = $00000062; xlConeColClustered = $00000063; xlConeColStacked = $00000064; xlConeColStacked100 = $00000065; xlConeBarClustered = $00000066; xlConeBarStacked = $00000067; xlConeBarStacked100 = $00000068; xlConeCol = $00000069; xlPyramidColClustered = $0000006A; xlPyramidColStacked = $0000006B; xlPyramidColStacked100 = $0000006C; xlPyramidBarClustered = $0000006D; xlPyramidBarStacked = $0000006E; xlPyramidBarStacked100 = $0000006F; xlPyramidCol = $00000070; xl3DColumn = $FFFFEFFC; xlLine = $00000004; xl3DLine = $FFFFEFFB; xl3DPie = $FFFFEFFA; xlPie = $00000005; xlXYScatter = $FFFFEFB7; xl3DArea = $FFFFEFFE; xlArea = $00000001; xlDoughnut = $FFFFEFE8; xlRadar = $FFFFEFC9; } // O PrintPreview abre a tela de visualizao do Excel // e o PrintOut imprime na impressora padro do Windows //Sheet.PrintPreview; //Sheet.PrintOut; // o SaveAs permite que vc salve automticamente o relatrio gerado //Sheet.SaveAs('c:\teste.xls');

__________________________________________________________________________

Recibo de Pagamento: Integrando Delphi com Word


Integrando uma aplicao Delphi com um documento Microsoft Word para realizar a emisso de recibos de pagamentos: 1 Passo: modelo do recibo no Word

Criar um novo documento no Microsof Word e desenvolver o modelo do recibo de pagamento acrescentando campos de texto que sero substitudos por valores definidos na aplicao Delphi. O "Campo de Texto", indicado pela seta azul na Figura 1, encontra-se na barra de ferramentas formulrios disponvel na "Guia Desenvolvedor" na verso 2010 do Microsoft Word. Para mostrar a "Guia Desenvolvedor" na barra de menu do Word deve-se: a) No menu Arquivo, clicar em Opes. b) Na janela "Opes do Word", clicar em Personalizar Faixa de Opes e a seguir marcar a caixa Desenvolvedor em "Guias Principais". Dois aspectos importantes devem ser observados na construo do modelo do recibo no Word: 1) Os campos de texto devem ser identificados na caixa "Indicador" da janela "Opes de formulrio de texto" aberta atravs de um duplo clique do mouse sobre o respectivo campo. Na Figura 1 pode-se observar os nomes sugeridos para os campos de texto, na ordem: Pagador, Extenso, Referente, Valor, Tipo, Local e Assina. Estes nomes sero usados pelo Delphi para atribuir os valores dos componentes de entrada da interface da aplicao aos respectivos campos no documento Word. 2) Concludo o modelo do recibo ele dever ser salvo na pasta da aplicao com o nome "RECIBO" do tipo "Modelo do Word" (RECIBO.dot).

Figura 1. Modelo do recido desenvolvido no Word.

2 Passo: desenvolvendo a aplicao Delphi Criar uma nova aplicao no ambiente de desenvolvimento Delphi 7 atravs da opo do menu "File|New|Application..." e implementar o formulrio principal como sugere a Figura 2.

Figura 2. Formulrio principal da aplicao. Relao dos componentes do formulrio principal com a ordem sequencial, o nome do componente, a pgina da sua localizao e as propriedades que devem ser alteradas com os seus respectivos valores. 1. Label pg. Standard Caption Left Top Valor: 10 5 2. Edit pg. Standard Name Left Top Font Text Width 4. Edit pg. Standard Name Left Top Text edPagador 10 64 apagar edValor 10 19 negrito, azul apagar 100 6. Edit pg. Standard Name Left Top Text edReferente 10 109 apagar 3. Label pg. Standard Caption Left Top Pagador: 10 50

5. Label pg. Standard Caption Left Top Referente a: 10 95

Width

430

Width

430

7. RadioGroup pg. Standard Name Caption Left Top Items ItemIndex Columns Height Width rgTipo Pagamento: 10 140 Dinheiro Cheque 0 1 70 125

8. GroupBox pg. Standard 9. Label pg. Standard Caption Left Top Height Width Cheque: 150 140 70 288 Caption Left Top Banco: 10 24

10. Edit pg. Standard Name Left Top Text Width edBanco 10 38 apagar 75

11. Label pg. Standard Caption Left Top Agncia: 105 24

12. Edit pg. Standard Name Left Top Text Width edAgencia 105 38 apagar 75

13. Label pg. Standard Caption Left Top Conta: 200 24

14. Edit pg. Standard Name Left Top Text Width edConta 200 38 apagar 75

15. Label pg. Standard Caption Left Top Local: 10 220

16. Edit pg. Standard Name Left Top Text Width edLocal 10 234 apagar 430

17. Label pg. Standard Caption Left Top Assina: 10 265

18. Edit pg. Standard Name Left Top Text Width edAssina 10 279 apagar 430

19. Button pg. Standard Name Caption Left Top Button1 &Imprimir 125 17

20. BitBtn pg. Additional Kind Caption Left Top bkClose &Fechar 365 17

3 Passo: adicionando a unit "Um" ao projeto O valor do recibo tambm ser apresentado por extenso no documento. No artigo Valor Por Extenso: Delphi foi desenvolvida a unit "Um" com a funo

"valorPorExtenso" que recebe um valor do tipo real e retorna o extenso deste valor. Para utilizar a unit citada neste projeto deve-se: a) Fazer o download em http://www.pb.utfpr.edu.br/omero/Delphi/Artigos/Um.rar e extrair a unit na pasta do projeto. b) Adicionar a unit ao projeto atravs da opo do menu "Project|Add to project..." 4 Passo: implementao a) Fazer referncia as unit's "ComObj" e "Um" no incio da implementation do formulrio da aplicao como mostra a Listagem 1. A unit "ComObj" disponibiliza a funoCreateOleObject utilizada para criar uma instncia do aplicativo Microsoft Word. J a unit "Um" oferece a funo valorPorExtenso para retornar um valor monetrio por extenso.

Listagem 1. Fazendo referncia as units "ComObj" e "Um". 1 uses ComObj, Um; b) No evento "onClick" do boto "Imprimir" o aplicativo Microsoft Word aberto com um novo documento, criado a partir do modelo do recibo, e os componentes de entrada so atribuidos aos respectivos campos de formulrio como mostra a Listagem 2. Listagem 2. Evento "onClick" do boto "Imprimir". procedure TForm1.Button1Click(Sender: TObject); 1 var WApp: variant; // varivel associada ao aplicativo Microsoft Word 2 WDoc: variant; // varivel associada ao documento criado no Word 3 path: string; 4 vlr: real; begin 5 // verifica se o Microsoft Word j est aberto 6 if (VarIsEmpty(WApp)) 7 then WApp := CreateOleObject('Word.Application');

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

path := ExtractFilePath(Application.ExeName); // cria um documento no Word a partir do modelo do recibo WDoc := WApp.Documents.Open(path + 'RECIBO.dot'); WApp.Visible := True; try vlr := StrToFloat(edValor.Text); // move os componentes de entrada da aplicacao Delphi // para os campos de texto do recibo no Microsoft Word WDoc.FormFields.Item('Valor').Result := Format('%m', [vlr]); WDoc.FormFields.Item('Pagador').Result := edPagador.Text; WDoc.FormFields.Item('Referente').Result := edReferente.Text; WDoc.FormFields.Item('Extenso').Result := valorPorExtenso(vlr); WDoc.FormFields.Item('Referente').Result := edReferente.Text; WDoc.FormFields.Item('Local').Result := edLocal.Text; WDoc.FormFields.Item('Assina').Result := edAssina.Text; if (rgTipo.ItemIndex = 0) // pagamento em dinheiro then WDoc.FormFields.Item('Tipo').Result := 'Pagamento em Dinheiro.'

25 26 27 28 29 30 31 32 33 34 35 36 37

else // pagamento com cheque WDoc.FormFields.Item('Tipo').Result := 'Pagamento efetuado com o Cheque do Banco: ' + edBanco.Text + ', Agncia: ' + edAgencia.Text + ', Conta: ' + edConta.Text + '.'; except end; end;

Aspectos importantes da codificao apresentada na Listagem 2: 1) A varivel "WApp" recebe uma instncia do aplicativo Microsoft Word atravs da instruo: WApp := CreateOleObject('Word.Application'); 2) A varivel "WDoc" recebe o documento criado no Word a partir do modelo salvo na pasta da aplicao atravs da instruo: WDoc := WApp.Documents.Open(path + 'RECIBO.dot'); 3) Os valores dos componentes de entrada na interface so atribudos aos respectivos campos de texto no documento Word atravs de instrues, como por exemplo: WDoc.FormFields.Item('Valor').Result := Format('%m', [vlr]); WDoc.FormFields.Item('Pagador').Result := edPagador.Text; WDoc.FormFields.Item('Extenso').Result := valorPorExtenso(vlr); Executando a aplicao deve-se informar todos as informaes relacionadas ao recibo: valor (R$), nome do pagador, finalidade do recibo, tipo do pagamento (em dinheiro ou cheque), local do pagamento e o nome de quem assina, como mostra o exemplo apresentado naFigura 2.

Figura 2. Ilustrando a execuo da aplicao.

Pressionando o boto "Imprimir" os dados de entrada sero atribudos aos respectivos campos texto no recibo criado no Word como mostra a Figura 3.

Figura 3. Documento criado no Word com os valores atribuidos pela aplicao Delphi.

Boa noite a todos. Utilizo Delphi 7. Nao sei se eh bug no componente MEMO ou eu q nao sei usar direito... No meu software, eu tenho um componente MEMO... Entao, faz de conta q eu tenho um MEMO com 2 linhas ABCD 12345 //var LINHA1, LINHA2: string; LINHA1 := Memo.Lines.ValueFromIndex[0]; LINHA2 := Memo.Lines.ValueFromIndex[1]; Entao, a string LINHA1, fica como BCD e o LINHA2 fica como 2345 O foda eh q eu tenho uma rotina q le centenas de linhas em 1 memo, entao uso um "repeat" com um contador pra varrer o memo e processar os dados, e nisso todas as linhas perdem o 1 caracter. Alguem me ajuda??
Editado pela ltima vez por Marc-br em Seg Mai 12, 2008 2:16 pm, num total de 2 vezes

Voltar ao Topo

Flavio_Ctba
Novato

Enviada: Seg Mai 12, 2008 10:38 am Assunto:

Registrado: Quinta-Feira, 7 de Fevereiro de 2008 Mensagens: 87 Localizao: Curitiba

oi Marc-br, Realmente eu testei o metodo Memo.Lines.ValueFromIndex[0]; e a primeira letra da linha comida. No sei se a finalidade deste mtodo essa mesmo de pegar as informaes da linha inteira ou outro... Mas pra resolver o seu problema voce pode fazer o seguinte: ShowMessage(Memo.Lines[0]); //mostra a linha1 do memo

ShowMessage(Memo.Lines[1]); //mostra a linha2 do memo espero q ajude, flw


Voltar ao Topo

Marc-br
Aprendiz

Enviada: Seg Mai 12, 2008 2:10 pm Assunto:

Registrado: Tera-Feira, 3 de Julho de 2007 Mensagens: 117 Localizao: Franca-SP

Do seu jeito funcionou deve ser bug da funo ValueFromIndex[x] mesmo, sempre come a 1 letra... Outro jeito q funcionou MEMO1.Lines.Strings[i]

Primeira Dica: 174 - Criar um documento no Word Uses ComObj procedure TForm1.Button1Click(Sender: TObject); var MSWord: Variant; begin MSWord:= CreateOleObject (Word.Basic); MSWord.AppShow;//mostra o word MSWord.FileNew;//inicia um novo documento MSWord.insert(Contrato de Locao); //Escreve algo MSWord.insert(#13+Contrato de Locao);//Pula uma linha e escreve MSWord.FontSize(24);//muda o tamanho da fonte MSWord.italic;//coloca italico MSWord.bold;//coloca negrito MSWord.underline;//sublina MSWord.insert(13+Contrato de Locao);//pula a linha e escreve novamente MSWord.FontSize(12);//muda o tamanho da fonte MSWord.Font(Arial);//muda a fonte usada MSWord.underline(false);//retira o sublinhado MSWord.italic(false);//retira o italico MSWord.bold(false);//retira o bold MSWord.insert(13 +teste); MSWord.insert(#13+9 +teste);//nova linha e um TAB MSWord.insert(13+Table1Razao_Social.Value);//insere algo de uma tabela MSWord.LineUp(2, 1); //seleciona uma parte do texto MSWord.TextToTable(ConvertFrom := 2, NumColumns := 1);// monta uma tabela com o texto selecionado MSWord.FileSaveAs(c:\temp\test.txt, 3); //Salva o arquivo end; Obs feita pelo Ruberval

MSWord.JustifyPara; // alinhamento justificado MSWord.RightPara; // alinhamento a direita MSWord.LeftPara; // alinhamento a esquerda MSWord.InsertPageBreak; // quebrar pgina Segunda Dica

421 - Gerar uma tabela no Word atravs do Delphi Inclua na seo uses: ComObj { - Coloque um boto no Form; - Altere o evento OnClick do boto conforme abaixo: } procedure TForm1.Button1Click(Sender: TObject); var Word: Variant; begin { Abre o Word } Word := CreateOleObject(Word.Application); try { Novo documento } Word.Documents.Add; try { Adiciona tabela de 2 linhas e 3 colunas } Word.ActiveDocument.Tables.Add( Range := Word.Selection.Range, NumRows := 2, NumColumns := 3); { Escreve na primeira clula } Word.Selection.TypeText(Text := Linha 1, Coluna 1); { Prxima clula } Word.Selection.MoveRight(12); { Escreve } Word.Selection.TypeText(Text := Linha 1, Coluna 2); Word.Selection.MoveRight(12); Word.Selection.TypeText(Text := Linha 1, Coluna 3); Word.Selection.MoveRight(12); Word.Selection.TypeText(Text := Linha 2, Coluna 1); Word.Selection.MoveRight(12); Word.Selection.TypeText(Text := Linha 2, Coluna 2); Word.Selection.MoveRight(12); Word.Selection.TypeText(Text := Linha 2, Coluna 3); { Auto-Formata } Word.Selection.Tables.Item(1).Select; { Seleciona a 1 tabela } Word.Selection.Cells.AutoFit; { auto-formata } { Imprime 1 cpia } Word.ActiveDocument.PrintOut(Copies := 1); ShowMessage(Aguarde o trmino da impresso...); { Para salvar... } Word.ActiveDocument.SaveAs(FileName := c:\Tabela.doc); finally { Fecha documento } Word.ActiveDocument.Close(SaveChanges := 0); end; finally

{ Fecha o Word } Word.Quit; end; end; Observaes Foram usados neste exemplo o Delphi4 e MS-Word97.