Как сменить принтер по умолчанию - PullRequest
1 голос
/ 14 октября 2011

Я пытаюсь изменить принтер по умолчанию в событии при изменении поля со списком, в котором указан индекс принтера. Я использую «Принтеры», чтобы получить индекс принтера, но фактическая печать выполняется с помощью проприетарного кода печати, который позволяет напрямую печатать в формате PDF и упростить макет страницы. Я пытаюсь использовать приведенный ниже код для замены принтера по умолчанию, и затем мой код печати будет распечатан на этом принтере. Однако программа перестает отвечать на запросы без каких-либо ошибок или программ, не отвечающих на сообщения при выполнении этой строки кода:

SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0,LongInt(cs1));

Вот полная функция.

function TMainFrm.SetDefaultPrinter(const PrinterName: string): boolean;
// Printername is bv: '\\MYPRINTER\HP5-k'
var
s2 : string;
dum1 : Pchar;
xx, qq : integer;

const
cs1 : pchar = 'Windows';
cs2 : pchar = 'Device';
cs3 : pchar = 'Devices';
cs4 : pchar = #0;

begin
    xx := 254;
    GetMem( dum1, xx);
    Result := False;
    try
        qq := GetProfileString( cs3, pchar( PrinterName ), #0, dum1, xx);
    if (qq > 0) and (trim( strpas( dum1 )) <> '') then
    begin
        s2 := PrinterName + ',' + strpas( dum1 );
        while GetProfileString( cs1, cs2, cs4, dum1, xx) > 0 do
            WriteProfileString( cs1, cs2, #0);
            WriteProfileString( cs1, cs2, pchar( s2 ));
        case Win32Platform of
        VER_PLATFORM_WIN32_NT :
            SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0,LongInt(cs1));
        VER_PLATFORM_WIN32_WINDOWS :
            SendMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0,LongInt(cs1));
        end; { case }
        Result := True;
    end;
    finally
        FreeMem( dum1 );
    end;
end;

У кого-нибудь есть какие-либо советы или лучший способ сделать это?

Как примечание стороны, это не моя функция. Это кусок кода, который я выбрал во время поиска решения моей проблемы.

Еще немного информации:

The user selects the printer in the drop down. This is where the PDF will be sent

Задание на печать - это фактически PDF-файл, печатаемый с использованием

 ShellExecute(Application.Handle, 'print', PChar(sPath), nil, nil, SW_HIDE); 

Цель состоит в том, чтобы изменить принтер по умолчанию на выбранный принтер, чтобы распечатать PDF-файл на желаемом принтере, а затем вернуть принтер к исходному значению по умолчанию при выходе из приложения

Ответы [ 3 ]

3 голосов
/ 14 октября 2011

Попробуйте использовать класс WMI Win32_Printer для отображения списка принтеров и метод SetDefaultPrinter для установки принтера по умолчанию.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

procedure  ListPrinters;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT DeviceID, Name FROM Win32_Printer','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('DeviceID %s Name %s',[FWbemObject.DeviceID,FWbemObject.Name]));
    FWbemObject:=Unassigned;
  end;
end;

function  SetDefaultPrinter(const DeviceID:string):boolean;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObject   : OLEVariant;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObject   := FWMIService.Get(Format('Win32_Printer.DeviceID="%s"',[DeviceID]));
  if not VarIsClear(FWbemObject) then
   Result:=FWbemObject.SetDefaultPrinter()=0
  else
   Result:=false;
end;


begin
 try
    CoInitialize(nil);
    try
      ListPrinters;
      SetDefaultPrinter('HP LaserJet'); //here you must pass the DeviceID of one the printers listed above
    finally
      CoUninitialize;
    end;
 except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
 end;
 Writeln('Press Enter to exit');
 Readln;
end.
2 голосов
/ 14 октября 2011

Просто кратко рассмотрим эту ссылку , и кажется, что вы отключаете самую критическую функцию SetDefaultPrinterA / SetDefaultPrinterW в 'winspool.drv'

Также широковещательное сообщение предназначено длявежлив с другими запущенными программами, чтобы сообщить им, что что-то изменило принтер по умолчанию, даже в приведенной выше статье он, похоже, не обращает никакого внимания на результат, поэтому вы можете изменить вызов на PostMessage

0 голосов
/ 04 октября 2017

Я также попытался использовать блок кода «SendMessage (HWND_BROADCAST, WM_WININICHANGE, 0, LongInt (cs1))», и моя программа зависла.Итак, я попытался просто написать SetDefaultPrinter как локальную функцию, а затем никаких зависаний.Вот код, который отлично работает для меня.

function SetDefaultPrinter(const PrinterName: string): boolean;
// Printername is bv: '\\MYPRINTER\HP5-k'
var
s2 : string;
dum1 : PChar;
xx, qq : integer;

const
cs1 : pChar = 'Windows';
cs2 : pChar = 'Device';
cs3 : pChar = 'Devices';
cs4 : pChar = #0;

begin
    xx := 254;
    GetMem( dum1, xx);
    Result := False;
    try
            qq := GetProfileString( cs3, pChar( PrinterName ), #0, dum1, xx);
            if (qq > 0) and (trim( strpas( dum1 )) <> '') then
            begin
                s2 := PrinterName + ',' + strpas( dum1 );
                while GetProfileString( cs1, cs2, cs4, dum1, xx) > 0 do
                    WriteProfileString( cs1, cs2, #0);
                    WriteProfileString( cs1, cs2, pChar( s2 ));

                case Win32Platform of
                VER_PLATFORM_WIN32_NT :
                    SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0, LongInt(cs1));
                VER_PLATFORM_WIN32_WINDOWS :
                    SendMessage( HWND_BROADCAST, WM_SETTINGCHANGE, 0,LongInt(cs1));
                end; { case }
                Result := True;
            end;
    finally
        FreeMem( dum1 );
    end;
end;
...