Migración a PowerBuilder 2025 R2 b6430 y .Net10


Esta semana, con la excusa de la nueva versión de PowerBuilder 2025 R2 build 6430 —que trae el flamante soporte a .NET 10— he decidido migrar todos mis ejemplos que usan librerías .NET a la nueva versión. Son los que muchos de vosotros habéis ido clonando del GitHub, hasta ahora sobre .NET 8. Y es que, al instalar la nueva versión, es imprescindible instalar también el SDK de .NET 10, así que ya lo tenía en la máquina: la excusa perfecta para ponerlo todo al día. Con .NET 10 ya como versión LTS, me dije: «vamos a subirlo TODO de golpe y a dejarlo fino para los próximos años».

Que conste: migré toda la carpeta de ejemplos, pero en este artículo me centro solo en las librerías .NET que consume PowerBuilder (las DLLs que carga el IDE), que son las que de verdad nos interesan aquí. Las apps de consola sueltas, la API web y mi Cloud Framework las dejo fuera, que son otra historia.

Spoiler: hablamos de más de una docena de librerías —las que han ido saliendo en el blog estos años: OCR, escáner, firma de PDF, códigos de barras y un largo etcétera— todas compilando con cero warnings. Y por el camino me encontré un puñado de sorpresas con dependencias que ya estaban muertas, una librería que se ha vuelto de pago, y un COM de los de toda la vida que se resistía. Os cuento lo aprendido, que es justo el tipo de cosa que da rabia descubrir tú solo.

Resumen rápido: migré mis librerías .NET para PowerBuilder (más de una docena) de net8.0 a net10.0 (SDK 10.0.301), subiendo cada dependencia a su última versión compatible y libre. Lo hice a cuatro manos con Claude Code. Los peros: ImageSharp 4.x ahora es de pago, iTextSharp 5 y PdfiumViewer están muertos, y el COMReference de WIA no compila por línea de comandos. Todo tiene solución, y aquí la tenéis.

¿Por qué .NET 10 y por qué ahora?

¡Y aquí viene lo que me tiene entusiasmado! PowerBuilder 2025 R2 ya soporta .NET 10, y eso es justo el empujón que estaba esperando. .NET 10 es LTS (soporte largo), trae mejoras de rendimiento «gratis» con solo recompilar, y mantenerse al día evita el efecto bola de nieve de saltar tres versiones de golpe dentro de dos años. Aproveché para actualizar el IDE a la flamante build 6430 y, ya puestos, migrar de un tirón todas mis librerías al runtime nuevo. Cuando una herramienta te pone las cosas tan fáciles, dan ganas de usarla.

Y lo mejor: PowerBuilder 2025 R2 hospeda el CLR moderno sin dramas. Las DLLs que consumimos como dotnetobject o vía el .NET DLL Importer cargan como un guante. Y, como siempre, mi obsesión: que esto se mantenga sencillo. Clonas el repo «en modo solución», abres, compilas y funciona. Sin malabares.

Los cuatro "peros" que me encontré (y cómo los resolví)

El 90% de los proyectos fue cambiar <TargetFramework>net8.0</TargetFramework> por net10.0, actualizar paquetes y a volar. Pero hubo cuatro casos que merecen su párrafo, porque os van a pasar a vosotros también:

1. ImageSharp: ojo, que la v4 ahora es de pago

Si tenéis SixLabors.ImageSharp, NO lo subáis a la rama 4.x. A partir de la v4 cambiaron a la «Six Labors Split License», que es comercial, y el build directamente falla si no tienes clave. La solución es quedarse en la rama 3.1.x, que sigue siendo Apache-2.0 (libre). Yo me quedé en la 3.1.12 y tan contento.

2. iTextSharp 5 está muerto → iText 7 (9.x)

Los ejemplos de PDF que aún usaban iTextSharp 5 (que lleva años sin mantenimiento) los reescribí a itext7 9.6.0. Y aquí hablamos de varios de mis clásicos: la firma digital de PDF, el extractor de texto, el relleno de formularios y el Split & Merge. Y con la firma digital se cierra, de paso, una vieja espina. Cuando en su día actualicé aquel ejemplo, la librería me fallaba al consumirla en proceso desde PowerBuilder, así que tuve que apañarme con una versión ejecutable aparte; y en el resto de ejemplos que aún tiraban de iTextSharp lo mantuve tal cual, para no enredarlos. Pues bien: esta vez por fin he dado con lo que fallaba y los he dejado actualizados y funcionando de verdad, con la DLL consumida directamente en proceso. Os lo contaré con todo detalle en el próximo artículo, que va justo de la firma digital con itext7 y python. Aviso: en iText 9 la API de firma cambió bastante respecto a versiones anteriores. Si venís de ahí, los puntos que más me tocaron:

  • Los setters de PdfSigner se movieron a SignerProperties.
  • PdfSignatureAppearance pasó a SignatureFieldAppearance.
  • DigestAlgorithms ahora vive en el namespace iText.Kernel.Crypto.

¡Y de regalo, un viejo fantasma exorcizado! 🎉 Ya que estábamos con iText, por fin hemos conseguido que iText7 funcione como librería .NET consumida en proceso desde PowerBuilder, algo que hasta ahora se me resistía: en consola firmaba de maravilla, pero al cargar la misma DLL desde PB reventaba con el críptico «The type initializer for 'iText.IO.Util.ResourceUtil' threw an exception».

Llevaba años con eso marcado como «imposible» —ni el soporte de Appeon ni el de iText supieron decirme por qué— y por fin tiene explicación y arreglo. Toda la cacería, con el porqué del error y cómo lo resolví, en el próximo artículo de firma digital.

3. PdfiumViewer (abandonado desde 2018) → PDFtoImage

Para rasterizar PDF a imagen yo arrastraba PdfiumViewer, que está abandonado desde 2018. Lo sustituí por PDFtoImage (de sungaila, MIT, mantenido, basado en PDFium + SkiaSharp). Un detalle fino: SkiaSharp no exporta BMP, así que cuando hacía falta ese formato lo re-codifico con System.Drawing. En los ejemplos de códigos de barras (los de QR y EAN-13) la lectura/generación pasó al binding ZXing.Net.Bindings.SkiaSharp.

4. El COM de WIA que no compilaba por CLI

El ejemplo del escáner (ScannerWia) —el mismo que luego amplié a escaneo multipágina— usaba un <COMReference> a WIA, y eso revienta al compilar por línea de comandos con el clásico error MSB4803. La solución que me funcionó es el truco del interop pregenerado:

tlbimp C:\Windows\System32\wiaaut.dll /namespace:WIA /out:Interop.WIA.dll

Y luego, en el .csproj, en vez del COMReference, una referencia normal a ese DLL con el interop embebido:

<Reference Include="Interop.WIA">
    <HintPath>Interop.WIA.dll</HintPath>
    <EmbedInteropTypes>true</EmbedInteropTypes>
    <Private>false</Private>
</Reference>

Con eso compila y publica por CLI con cero warnings, y el interop va dentro del ensamblado. Punto para nosotros.

Un par de detalles de System.Drawing (que despistan)

En proyectos net10.0-windows con UseWindowsForms, System.Drawing.Common ya lo aporta el propio framework: si lo referenciáis explícito os saltará el aviso NU1510. Y al revés: en un net10.0 «pelado» (sin -windows), usar System.Drawing dispara el analizador CA1416 (solo Windows). La regla práctica que seguí: si el ejemplo toca dibujo/GDI, va a net10.0-windows y listo. Esto me pasó, por ejemplo, con el de OCR con Tesseract.

Lo que he aprendido por el camino

  • Migrar no es solo cambiar un número. El verdadero trabajo está en las dependencias que se han muerto o han cambiado de licencia por debajo.
  • Lee la licencia antes de subir de major. Lo de ImageSharp 4.x me habría costado un disgusto en un cliente.
  • Lo abandonado, fuera. iTextSharp 5 y PdfiumViewer llevaban años sin tocarse; cambiarlos ahora es deuda técnica que dejo saldada.
  • 0 warnings o no me vale. Un ejemplo que enseña debe compilar limpio; si no, transmites malos hábitos.
Todo esto lo fui haciendo apoyándome en Claude Code: él se encargó del trabajo repetitivo entre la docena larga de librerías (detectar paquetes obsoletos, proponer la versión compatible, reescribir las APIs que cambiaron) y yo iba validando en el IDE de PowerBuilder. Para una migración masiva como esta, tener un compañero que no se cansa de repetir el mismo patrón 20 veces es oro.

El catálogo, ejemplo por ejemplo

Por si os habéis perdido alguno por el camino, aquí tenéis el mapa: cada ejemplo migrado a .NET 10, con qué dependencia tocaba y el artículo original donde lo conté en su día. Si lo estabais usando, este es el momento de bajaros la versión nueva.

Ejemplo Qué cambió al migrar Artículo original
Firma digital de PDFiTextSharp 5 → itext7 9.6.0Firma Digital PDF (2022)
PDF Text ExtractoriTextSharp 5 → itext7 9.6.0PDF Text Extractor (2024)
Rellenar formularios PDFiTextSharp 5 → itext7 9.6.0Rellenar formulario PDF (2024)
Split & Merge PDFPdfiumViewer → PDFtoImage; itext7PDF Utilities: Split & Merge (2022)
OCRTesseract; pasa a net10.0-windowsOCR en PowerBuilder (2024)
Escáner (WIA)COMReference → interop con tlbimpEscanear con WIA (2023) · multipágina (2024)
Códigos QR / EAN-13ZXing → Bindings.SkiaSharpQR (2023) · EAN-13 (2022)
Envío de correo (SMTP)MailKit al díaSMTP con MailKit (2022)
FileServiceSystem.IO; recompila limpioFileService (2022)
Impresión directaRawPrint al díaImpresión directa (2022)

Disponible en modo solución

Como siempre, tenéis los ejemplos publicados en modo solución en mi GitHub (github.com/rasanfe): clonáis el repo que os interese, abrís la solución y compila. Ya actualizados a .NET 10 y probados con PowerBuilder 2025 R2 build 6430.

Y para los nostálgicos —o por si necesitáis comparar—, he guardado una copia de los proyectos en .NET 8 en un repositorio aparte llamado «archivo». Eso sí, no he grabado copia de PowerBuilder 2025: esa parte es fácilmente sustituible, así que no merecía la pena duplicarla.


Artículos relacionados:

¡Nos vemos en el próximo artículo! Y recuerda: en PowerBuilder, los límites solo están en nuestra imaginación. 🚀

Comentarios