#delphi #delphi-2010
#delphi #delphi-2010
Вопрос:
Я пытаюсь изменить принтер по умолчанию в событии on change в поле со списком, в котором указан индекс принтера. Я использую «Принтеры» для получения индекса принтера, но фактическая печать выполняется с помощью проприетарного кода печати, который позволяет печатать непосредственно в формате PDF и упрощает макет страницы. Я пытаюсь использовать приведенный ниже код для изменения принтера по умолчанию, а затем мой код печати будет напечатан на этом принтере. Однако программа перестает отвечать на запросы без каких-либо ошибок или сообщений о том, что программа не отвечает при выполнении этой строки кода:
SendMessage( HWND_BROADCAST, WM_WININICHANGE, 0,LongInt(cs1));
Вот полная функция.
function TMainFrm.SetDefaultPrinter(const PrinterName: string): boolean;
// Printername is bv: '\MYPRINTERHP5-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;
У кого-нибудь есть какие-либо советы или лучший способ сделать это?
В качестве примечания это не моя функция. Это фрагмент кода, который я подобрал во время поиска решения моей проблемы.
Еще несколько фрагментов информации:
Задание на печать на самом деле представляет собой PDF-файл, который печатается с помощью
ShellExecute(Application.Handle, 'print', PChar(sPath), nil, nil, SW_HIDE);
Цель состоит в том, чтобы изменить принтер по умолчанию на выбранный принтер, чтобы распечатать pdf на желаемом принтере, а затем вернуть принтеру исходное значение по умолчанию при выходе из приложения
Комментарии:
1. Вы пробовали
Printers.PrinterIndex := IndexOfYourPrinter
2. У меня нет. Я предположил, что принтеры. PrinterIndex будет работать, только если я использую принтеры для печати вместо пользовательского класса печати, который мы используем. Я протестирую его и посмотрю, даст ли это желаемый результат
3. Стоило попробовать, но мой пользовательский класс печати использует принтер по умолчанию для печати и принтеров. PrinterIndex не изменяет значение по умолчанию
4. Вы не должны использовать принтер по умолчанию. Вы должны использовать выбранный принтер. Изменение принтера по умолчанию — это то, что должен сделать пользователь. Вы не должны делать это за их спиной.
5. Вам не нужен случай платформы, поскольку
WM_WININICHANGE = WM_SETTINGCHANGE
.
Ответ №1:
Попробуйте использовать Win32_Printer
класс WMI для перечисления принтеров и 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', 'rootCIMV2', '', '');
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', 'rootCIMV2', '', '');
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:
Просто бегло взгляните на эту ссылку, и, похоже, вы ошибаетесь с наиболее важной функцией SetDefaultPrinterA / SetDefaultPrinterW в ‘winspool.drv’
Также широковещательное сообщение предназначено для вежливости по отношению к другим запущенным программам, чтобы сообщить им, что что-то изменило принтер по умолчанию, даже в приведенной выше статье, похоже, не обращает никакого внимания на результат, поэтому вы можете изменить вызов на postMessage
Комментарии:
1. postMessage решил проблему. Теперь программа работает по назначению, спасибо @JamesB
Ответ №3:
Я также пытался использовать блок кода «SendMessage (HWND_BROADCAST, WM_WININICHANGE, 0, LongInt (cs1))», и моя программа зависала. Итак, я попытался просто написать SetDefaultPrinter как локальную функцию, а затем никаких зависаний не произошло. Вот код, который отлично работает для меня.
function SetDefaultPrinter(const PrinterName: string): boolean;
// Printername is bv: '\MYPRINTERHP5-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;