get / set the default printer

本文介绍了一种使用Delphi实现获取和设置默认打印机的方法。通过API函数调用和注册表操作,可以实现读取当前系统的默认打印机名称及设置指定的打印机为默认打印机的功能。
get / set the default printer? 
 
 uses 
  Printers, Messages; 

function GetDefaultPrinter: string; 
var 
  ResStr: array[0..255] of Char; 
begin 
  GetProfileString('Windows', 'device', '', ResStr, 255); 
  Result := StrPas(ResStr); 
end; 

procedure SetDefaultPrinter1(NewDefPrinter: string); 
var 
  ResStr: array[0..255] of Char; 
begin 
  StrPCopy(ResStr, NewdefPrinter); 
  WriteProfileString('windows', 'device', ResStr); 
  StrCopy(ResStr, 'windows'); 
  SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, Longint(@ResStr)); 
end; 

procedure SetDefaultPrinter2(PrinterName: string); 
var 
  I: Integer; 
  Device: PChar; 
  Driver: PChar; 
  Port: PChar; 
  HdeviceMode: THandle; 
  aPrinter: TPrinter; 
begin 
  Printer.PrinterIndex := -1; 
  GetMem(Device, 255); 
  GetMem(Driver, 255); 
  GetMem(Port, 255); 
  aPrinter := TPrinter.Create; 
  try 
    for I := 0 to Printer.Printers.Count - 1 do 
    begin 
      if Printer.Printers = PrinterName then 
      begin 
        aprinter.PrinterIndex := i; 
        aPrinter.getprinter(device, driver, port, HdeviceMode); 
        StrCat(Device, ','); 
        StrCat(Device, Driver); 
        StrCat(Device, Port); 
        WriteProfileString('windows', 'device', Device); 
        StrCopy(Device, 'windows'); 
        SendMessage(HWND_BROADCAST, WM_WININICHANGE, 
          0, Longint(@Device)); 
      end; 
    end; 
  finally 
    aPrinter.Free; 
  end; 
  FreeMem(Device, 255); 
  FreeMem(Driver, 255); 
  FreeMem(Port, 255); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
  label1.Caption := GetDefaultPrinter2; 
end; 

//Fill the combobox with all available printers 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
  Combobox1.Items.Clear; 
  Combobox1.Items.AddStrings(Printer.Printers); 
end; 

//Set the selected printer in the combobox as default printer 
procedure TForm1.Button2Click(Sender: TObject); 
begin 
  SetDefaultPrinter(Combobox1.Text); 

end; 


unit Unit1;

interface

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

const
  MAXPRINTERBUFFER = 8000;
  MAXPRINTERNAME = 500;
  MAXPRINTERINFO = 50;

type
  TPrinterBuffer = array[0..MAXPRINTERBUFFER - 1] of char;
  TForm1 = class(TForm)
  ListBox1: TListBox;
  Button2: TButton;
  Button1: TButton;
  Label1: TLabel;
procedure Button2Click(Sender: TObject);
procedure GetPrinterNames;
function ParseNames(const namebuffer: TPrinterBuffer; var startPos: integer): string;
function SetPrinter(const PrinterName : String) : boolean;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
  Form1: TForm1;
  printerNames: TStringList;
  defaultPrinter: integer;

implementation

{$R *.DFM}

procedure TForm1.Button2Click(Sender: TObject);
var
  x : integer;
begin
  try
  for x := 0 to printerNames.Count -1 do begin
    If ListBox1.Selected[x] then begin
      if (SetPrinter(ListBox1.Items.Strings[x]))
      then label1.Caption := 'Printer set to ' + ListBox1.Items.Strings[x]
      else label1.Caption := 'Printer not set';
    end;
  end;
  except
    label1.Caption := 'An error occured while setting the printer';
  end;
end;

procedure TForm1.GetPrinterNames;
var
  buffer: TPrinterBuffer;
  currPos: integer;
  printerName: string;
begin
  printerNames.Free;
  printerNames := TStringList.Create;
  if GetProfileString(PChar('PrinterPorts'), nil, '', buffer, MAXPRINTERBUFFER) > 0 then
  begin
    currPos := 0;
    while (true) do
      begin
        printerName := ParseNames(buffer, currPos);
        if printerName <> '' then
        printerNames.Add(printerName)
    else
      break;
    end;
  end;
end;

function TForm1.ParseNames(const namebuffer: TPrinterBuffer;
var startPos: integer): string;
var
  i, j, NameLength: integer;
  str: string;
begin
  result := '';
  if (startPos > High(namebuffer)) or (namebuffer[startPos] = Chr(0))  

  then
    exit;
  for i := startPos to High(namebuffer) do begin
    if namebuffer[i] = Chr(0) 

    then begin
      nameLength := i - startPos;
      SetLength(str, nameLength);
      for j := 0 to nameLength - 1 do
      str[j+1] := namebuffer[startPos + j];
      result := str;
      startPos := i + 1;
      break;
    end;
  end;
end;

function TForm1.SetPrinter(const PrinterName: String): boolean;
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; 
  Result := True;
end;
finally
  FreeMem( dum1 );
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetPrinterNames;
  Listbox1.Items.AddStrings(PrinterNames);
end;

end.

<think>我们面对的用户问题:执行了 `systemctl set-default printer.target` 导致服务器无法进入系统,需要进入单用户模式进行还原。 根据引用[1]和引用[2]的内容,我们知道systemctl可以管理系统目标和状态。目标(target)相当于运行级别。正常情况下,我们使用multi-user.target(多用户命令行模式)或graphical.target(图形界面模式)。而救援模式(单用户模式)对应的是rescue.target。 用户错误地将默认目标设置成了printer.target(这通常不是标准的系统目标),导致系统启动时无法进入正确的运行级别。 解决方案思路: 1. 重启系统,在启动引导时进入救援模式(单用户模式)。 2. 在救援模式下,将默认目标改回正常的target(例如multi-user.target)。 3. 重启系统。 具体步骤(以CentOS 7为例,因为引用[4]提到了centos7启动原理,但引用[4]同时包含了centos6和7的内容,这里重点参考7): 步骤1:重启服务器,在GRUB2菜单界面进行中断 - 开机时,在出现GRUB2引导菜单时(通常有几秒的等待时间),按方向键(上下)选择要启动的内核(通常第一项),然后按“e”键进入编辑模式。 步骤2:修改启动参数 - 在编辑模式中,找到以“linux16”或“linux”开头的行(该行指定了内核参数),将光标移到该行末尾。 - 添加参数:`systemd.unit=rescue.target` 或者 `systemd.unit=emergency.target`(更紧急,更基础的环境) - 然后按Ctrl+X(或F10)使用修改后的配置启动。 步骤3:进入救援模式(单用户模式) - 系统将启动进入救援模式(单用户模式),此时可能需要输入root密码才能获得root shell。 步骤4:重新设置默认target - 在救援模式的shell中,执行以下命令将默认目标改回multi-user.target(或graphical.target,视情况而定): systemctl set-default multi-user.target - 也可以使用更直接的方式,删除错误的符号链接,重新建立: rm /etc/systemd/system/default.target ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target 步骤5:重启系统 - 执行 `reboot` 重启系统,系统应该可以正常进入多用户模式。 注意:如果用户之前使用的是图形界面,那么可能需要设置为graphical.target,但服务器通常使用multi-user.target。 另外,引用[2]中提到了使用`systemctl isolate`命令切换目标,但这是在系统已经启动的情况下使用的。现在系统无法正常启动,所以不能使用该命令。 根据引用[4]中关于centos7启动原理,我们知道systemd是centos7的初始化系统,所以上述方法适用于centos7。如果用户使用的是centos6,则方法不同(因为centos6使用init而不是systemd),但问题中提到了systemctl,所以应该是systemd的系统(centos7及以上)。 因此,我们给出针对centos7及以上的解决方案。 相关问题: 1. 如何进入CentOS 7的紧急救援模式(emergency mode)? 2. 除了单用户模式,还有哪些系统恢复模式? 3. 如何检查当前系统的默认target? 4. 如何临时切换target而不改变默认设置? </think>### 解决方案:进入单用户模式还原默认目标 #### 核心思路 通过 GRUB 引导菜单进入单用户模式(救援模式),删除错误的 `printer.target` 设置,还原为默认的 `multi-user.target` 或 `graphical.target`。 --- ### 具体操作步骤 1. **重启系统并中断引导** - 服务器启动时,在 **GRUB 引导界面** 快速按下 `↑`/`↓` 键暂停倒计时。 - 选择默认内核条目(通常为第一项),按 `e` 键进入编辑模式。 2. **修改启动参数** - 找到以 `linux16` 或 `linux` 开头的行(内核参数行)。 - 在行末追加参数: ```bash systemd.unit=rescue.target ``` ![](https://example.com/grub-edit.png) *图:内核参数编辑示意(实际无图形界面)[^4]* 3. **进入单用户模式** - 按 `Ctrl+X` 启动系统。 - 系统将进入 **救援模式(单用户模式)**,需输入 root 密码获取权限。 4. **还原默认目标** ```bash # 删除错误配置 rm /etc/systemd/system/default.target # 重置为多用户模式(推荐) ln -sf /usr/lib/systemd/system/multi-user.target /etc/systemd/system/default.target # 或重置为图形模式(若需图形界面) # ln -sf /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target ``` 5. **重启系统** ```bash reboot ``` --- ### 关键原理说明 1. **`printer.target` 的问题** 非标准目标(如 `printer.target`)缺失关键依赖服务,导致系统无法完成启动[^2]。 2. **救援模式的作用** `rescue.target` 提供最小化 Linux 环境,仅挂载根分区并启动基础服务,允许修复系统配置[^1][^2]。 3. **目标重置本质** `systemctl set-default` 实际创建符号链接 `/etc/systemd/system/default.target` → 目标 unit 文件,删除错误链接即可还原[^2]。 > ⚠️ **注意**:若救援模式提示 `/sbin/agetty` 错误,需在 GRUB 编辑界面追加 `init=/bin/bash` 直接进入 root shell。 --- ### 预防措施 ```bash # 查看所有可用目标 systemctl list-units --type=target # 查询当前默认目标 systemctl get-default # 应输出 multi-user.target 或 graphical.target ``` --- ### 相关问题 1. 如何修复因修改默认目标导致的系统黑屏/卡死? 2. `emergency.target` 和 `rescue.target` 有何区别? 3. 除了单用户模式,还有哪些系统恢复方法? 4. 如何永久禁用图形界面以节省服务器资源? 5. GRUB 引导失败时如何通过 LiveCD 修复系统? [^1]: `systemctl` 支持多种系统状态切换,错误的目标设置会导致系统无法启动。 [^2]: 救援模式(`rescue.target`)是修复系统配置的标准入口。 [^3]: 关键配置错误可能影响系统信任链,需谨慎操作。 [^4]: GRUB 引导过程是进入救援模式的关键环节。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值