Este es precisamente la duda que me plantearon hace unos días. Se trataba de una aplicación en Android que estaba preparada para imprimir en una impresora de tickets con conexión ethernet pero solo se disponía de una impresora USB conectada a un PC con Windows. La solucion es este programa que nos permite compartir la impresora en red como si se tratara de un servidor de impresión TCP/IP
Al código:
program PrintSrv; {$APPTYPE CONSOLE} uses Windows, SysUtils, Winsock, WinSpool; const BUFFERSIZE = 4*1024; var Terminated: Boolean; // Esta rutina maneja la señal "Ctrl+C" function HandlerRoutine(dwCtrlType: DWORD): BOOL; stdcall; begin Result:= TRUE; case dwCtrlType of CTRL_C_EVENT: Terminated:= TRUE; CTRL_CLOSE_EVENT: Terminated:= TRUE; CTRL_LOGOFF_EVENT: Terminated:= TRUE; CTRL_SHUTDOWN_EVENT: Terminated:= TRUE; else Result:= FALSE; end; end; function Min(i,j: Integer): Integer; begin if i < j then Result:= i else Result:= j; end; // Muestra el mensage en hexadecimal y como texto procedure WriteHex(Buffer: PAnsiChar; Count: Integer); var i,j: Integer; begin j:= 0; while Count > 0 do begin Write(IntToHex(j,8) + ':' + #32#32); for i:= 0 to Min(Count,8) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); Write(#32); for i:= 8 to Min(Count,16) - 1 do Write(IntToHex(Byte(Buffer[i]),2) + #32); for i:= Min(Count,16) to 15 do Write(#32#32#32); Write(#32 + '|'); for i:= 0 to Min(Count,16) - 1 do if Char(Buffer[i]) in ['A'..'Z','a'..'z','0'..'9'] then Write(Buffer[i]) else Write('.'); Writeln('|'); Dec(Count,16); inc(Buffer,16); inc(j,16); end; end; function CheckAddress(Address: TSockAddr): Boolean; begin Writeln('Recibiendo documento desde: ' + AnsiString(PAnsiChar(inet_ntoa(Address.sin_addr)))); Writeln; Result:= TRUE; end; procedure Procesar(S: TSocket); var Prnt: THandle; DocInfo: TDocInfo1; Res: DWORD; Buffer: PAnsiChar; Len: Integer; begin try GetMem(Buffer,BUFFERSIZE); try if OpenPrinter(PAnsiChar(ParamStr(1)), Prnt, nil) then try FillChar(DocInfo,Sizeof(DocInfo),#0); with DocInfo do begin pDocName:= PChar('PrintSrv'); pOutputFile:= nil; pDataType:= 'RAW'; end; if StartDocPrinter(Prnt, 1, @DocInfo) <> 0 then try if StartPagePrinter(Prnt) then try Len:= Recv(S, Buffer^, BUFFERSIZE, 0); while Len > 0 do begin WritePrinter(Prnt, Buffer, Len, Res); WriteHex(Buffer,Len); Len:= Recv(S, Buffer^, BUFFERSIZE, 0); end; finally EndPagePrinter(Prnt); end; finally EndDocPrinter(Prnt); end; finally ClosePrinter(Prnt); end; finally FreeMem(Buffer); end; finally CloseSocket(S); end; end; var WSAData: TWSAData; SSocket, CSocket: TSocket; SAddr, CAddr: TSockAddr; Size: Integer; FDSet: TFDSet; TimeVal: TTimeVal; begin if ParamCount < 1 then begin Writeln('Ejemplo de uso:'); Writeln('PrintSrv "Nombre de la impresora"'); Writeln; Exit; end; Terminated:= FALSE; SetConsoleCtrlHandler(@HandlerRoutine,TRUE); if WSAStartup(MAKEWORD(1, 1), WSADATA) = 0 then try // Creamos un socket SSocket:= Socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if SSocket = INVALID_SOCKET then begin Writeln('Error en Socket()!'); Exit; end; // Configuramos la ip y el puerto del servidor with SAddr do begin sin_family:= AF_INET; sin_port:= htons(9100); sin_addr.s_addr:= Inet_Addr(PAnsiChar('0.0.0.0')); end; if Bind(SSocket, SAddr, SizeOf(SAddr)) = SOCKET_ERROR then begin CloseSocket(SSocket); Writeln('Error en Bind!'); Exit; end; // Ponemos el puerto a la escucha if Listen(SSocket, SOMAXCONN) = SOCKET_ERROR then begin CloseSocket(SSocket); Writeln('Error en Listen!'); Exit; end; Writeln('La impresora seleccionada es: ' + ParamStr(1)); Writeln('Escuchando en el puerto 9100, formato RAW'); Writeln('Pulsa Ctrl+C para salir ...'); Writeln; // Bucle del servidor while not Terminated do begin // Procesamos los mensajes TimeVal.tv_sec:= 0; TimeVal.tv_usec:= 500; FD_ZERO(FDSet); FD_SET(SSocket, FDSet); // Comprobamos si hay algun cliente esperando if Select(0, @FDSet, nil, nil, @TimeVal) > 0 then begin Size:= SizeOf(CAddr); // Aceptamos la conexion CSocket:= Accept(SSocket, @CAddr, @Size); // Si la conexion es correcta if CSocket <> INVALID_SOCKET then begin // Comprobamos la direccón del cliente if CheckAddress(CAddr) then begin // Aqui procesamos el envio try Procesar(CSocket); except On E: Exception do begin // Si no podemos crearlo cerramos el socket CloseSocket(CSocket); // Informamos del error Writeln(E.Message); end; end; end else // Si la direccion no es valida cerramos el socket CloseSocket(CSocket); end; end; end; // Cerramos el Socket del servidor CloseSocket(SSocket); finally // Limpiamos todo WSACleanup; end else Writeln('Error en WSAStartup!'); end.
Solamente hay que ejecutar la aplicación indicando el nombre de la impresora, y en la App de Android indicarle la IP del PC y el puerto 9100.
PD: Por aquí dejo el binario por si alguien no puede compilar el código (por ejemplo la persona que me lo pidió, que no tiene Delphi)