Конференция "WinAPI" » Сохранение/чтение DEVMODE [D7, WinXP]
 
  • Циркуль (22.04.08 18:34) [0]
    Собсно, стоит задача один раз задав настройки печати для принтера, их потом использовать. Для этого, видимо, надо как-то уметь хранить DEVMODE. Сделал тестовую прогу. По нажатию одной кнопки вызываем диалог свойств принтера, по закрытии которого полученный DEVMODE пишем в файл. По нажатию второй кнопки читаем из файла DEVMODE, и подсовываем его в диалог свойств принтера. Код модуля:


    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls;

    type
     TForm1 = class(TForm)
       btnSaveDevMode: TButton;
       edPrinterName: TEdit;
       btnGetDevMode: TButton;
       procedure btnSaveDevModeClick(Sender: TObject);
       procedure btnGetDevModeClick(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    uses
     winspool;

    procedure TForm1.btnSaveDevModeClick(Sender: TObject);
    var
     StubDevMode: TDeviceMode;
     DevMode: PDevMode;
     hPrinter: THandle;
     dmSize: Cardinal;
     Stream: TFileStream;
    begin
     if OpenPrinter(PChar(edPrinterName.Text), hPrinter, nil) then
     begin
       try
         dmSize := DocumentProperties(Handle, hPrinter, PChar(edPrinterName.Text), StubDevMode, StubDevMode, 0);
         GetMem(DevMode, dmSize);
         try
           case DocumentProperties(Handle, hPrinter, PChar(edPrinterName.Text), DevMode^, StubDevMode,
                                   DM_OUT_BUFFER or DM_IN_PROMPT) of
             IDOK:
               begin
                 Stream := TFileStream.Create('C:\11111.ini', fmCreate);
                 try
                   Stream.Write(DevMode, dmSize);
                 finally
                   Stream.Free;
                 end;
               end;
             IDCANCEL:
               Exit;
             else
               ShowMessage('Ошибка при получении свойств принтера');
           end;
         finally
           FreeMem(DevMode);
         end;
       finally
         ClosePrinter(hPrinter);
       end;
     end
     else
       ShowMessageFmt('Не удалось открыть принтер \"%s\"', [edPrinterName.Text]);
    end;

    procedure TForm1.btnGetDevModeClick(Sender: TObject);
    var
     StubDevMode: TDeviceMode;
     DevMode: PDevMode;
     hPrinter: THandle;
     dmSize: Cardinal;
     dmFileSize: Integer;
     Stream: TFileStream;
    begin
     if OpenPrinter(PChar(edPrinterName.Text), hPrinter, nil) then
       try
         dmSize := DocumentProperties(Handle, hPrinter, PChar(edPrinterName.Text), StubDevMode, StubDevMode, 0);
         GetMem(DevMode, dmSize);
         try
           Stream := TFileStream.Create('C:\11111.ini', fmOpenRead);
           try
             if dmSize = Stream.Size then
             begin
               Stream.Seek(0, soFromBeginning);
               Stream.ReadBuffer(DevMode, dmSize);
               case DocumentProperties(Handle, hPrinter, PChar(edPrinterName.Text), DevMode^, DevMode^,
                                  DM_IN_BUFFER or DM_OUT_BUFFER or DM_IN_PROMPT) of
                 IDOK: Caption := 'OK';
                 IDCANCEL: Caption := 'Cancel'
                 else
                   Caption := 'Err'
               end;
             end
             else
               ShowMessage('Ошибка: отличаются размеры DEVMODE выбранного принтера и полученные из файла');
           finally
             Stream.Free;
           end;
         finally
           FreeMem(DevMode);
         end;
       finally
         ClosePrinter(hPrinter);
       end
     else
       ShowMessageFmt('Не удалось открыть принтер \"%s\"', [edPrinterName.Text]);
    end;

    end.



    Пока оба действия происходят в рамках одного запуска приложения - все работает. Но если приложение закрыть, запустить заново и нажать вторую кнопку - DEVMODE прочитается из файла, но в диалоге все равно будут значения по умолчанию. Причем в этом случае при закрытии диалога само по себе закрывается и приложение, без каких-либо ошибок.
  • Игорь Шевченко © (22.04.08 20:31) [1]
    Я конечно извиняюсь, но TStream.ReadBuffer объявлен как
    ReadBuffer(var Buffer; Count: Longint);

    а Write как function Write(const Buffer; Count: Longint): Longint;

    То есть, при Write неплохо бы говорить Write (DevMode^, ...)
    а при ReadBuffer, соответственн, ReadBuffer (DevMode^, ...)
    В твоем случае ты пишешь указатель и мусор в стеке за ним, а при чтении затираешь память
  • Циркуль (22.04.08 21:37) [2]
    ээээ... спасибо, конечно :)
    а как это объясняет нормальную работу в случае когда жмем вторую кнопку, не закрывая приложение?
    devmode тогда должен был бы заполняться мусором из файла, который туда попал при сохранении...
  • Циркуль (22.04.08 21:41) [3]
    блин, неужели из-за того, что при GetMem(DevMode, dmSize) во втором случае просто выделяется тотже самый кусок памяти, который освободился после вызова первой процедуры?
    жесть, сам бы ни за что не допер :)
  • Игорь Шевченко © (22.04.08 22:19) [4]
    Циркуль   (22.04.08 21:41) [3]

    Нет, он не выделяется. В указатель читается его значение из файла, а возможно, память к тому времени еще не успела перезаписаться.
  • Циркуль (22.04.08 23:30) [5]
    А, ну да... Ну все равно "везение" :)

    Еще раз спасибо
 
Конференция "WinAPI" » Сохранение/чтение DEVMODE [D7, WinXP]
Есть новые Нет новых   [134433   +22][b:0][p:0.003]