martes, 17 de abril de 2007

Error ASP.NET 2.0.50727.42

A más de uno le habrá ocurrido este error. Llega a ser realmente molesto, sobre todo porque suele aparecer justo cuando hay una reunión y has de mostrar algo.

Tras probar varias soluciones por fin hay una realmente efectiva. El problema surgía cuando se cargaba el Framework 2.0 en lugar de 1.1, entonces al intentar cargar algún sitio de SharePoint 2003 aparecía el mensaje “no se ha configurado este servidor virtual de Windows SharePoint Services para usarlo con ASP.NET 2.0.50727.42”. Se soluciona creando un archivo de configuración de la siguiente manera:
  • Abrir el administrador de IIS.
  • Seleccionar Extensiones de servicio Web.Seleccionar ASP.NET 1.1 y pulsar en Permitir.
  • Abrir en un explorador la carpeta contenedora de W3wp.exe que se haya por defecto en windir\system32\inetsrv
  • En esta carpeta crear un nuevo documento W3wp.exe.config con el texto siguiente:

  • Guardar el archivo.
  • Reiniciar el IIS.
Despues de esto ya no deberia volver a aparecer el molesto mensaje.

Artículo de la KB de Microsoft 928607

martes, 10 de abril de 2007

Feliz 100.000.000 iPod

No he podido evitarlo, tengo que poner una entrada del iPod.

Se ha vendido el iPod 100.000.000, ese aparatito que se ha convertido en indispensable en mi día a día. Enhorabuena.

Gracias a él ahora mi vida tiene banda sonora.

El mío es el iPod mini. ¿Cuál es el tuyo?

miércoles, 28 de marzo de 2007

Generar y agregar un WebPart con C#

Tal vez no parezca realmente útil generar una WebPart mediante código para agregarlo a un sitio, pero nunca se aprende suficiente y menos en SharePoint.

El caso es que necesitaba que un sitio tuviera un WebPart, pero el contenido del WebPart no se sabría hasta que el usuario no seleccionara una serie de opciones, así que investigando y probando llegué a esta solución. Puede que no sea la solución más efectiva o elegante, pero por lo menos aprendí algo nuevo.

El método en cuestión es muy sencillo, solo hay que obtener el sitio que se quiera, su colección de WebPart de la página donde queramos agregarlo, construir el WebPart y añadirlo a la colección. Veamos el código:

Está en una imagen debido a problemas con las etiquetas del WebPart, espero que sea perfectamente legible.

Donde indica ruta_sitio es un string con la ruta relativa del sitio de SharePoint donde queremos agregar el WebPart (por ejemplo: “/sites/proyectos/”).

Donde pone Contenido del WebPart (donde si no) va nuestro código HTML con el WebPart que queremos generar, cualquier cosa que se nos ocurra. En el HTML podemos integrar cualquier dato que podamos obtener del modelo de objetos de SharePoint.

lunes, 26 de marzo de 2007

Gráficos en SharePoint

Como se suele decir una imagen vale más que mil palabras, así que extrapolándolo a SharePoint, una gráfico vale más que mil listados. Bueno, tal vez sea un poco exagerado, pero lo cierto es que un gráfico bien pensado complementa y da mucha riqueza a un sitio y además mostramos información, no solo datos como con las listas.
Lo más cómodo y a mi parecer indicado para hacer gráficos es tener una base de datos en nuestro SQL Server donde almacenar las consultas que hagamos, de las cuales se nutrirá nuestro gráfico. En esta base de datos crearemos un usuario con permisos de lectura que usaremos para acceder desde SharePoint. También crearemos una nueva vista de todos los datos de las listas y bibliotecas de nuestro SharePoint, la consulta será:

SELECT li.tp_Title, ud.*
FROM [BD SharePoint].dbo.UserData ud INNER JOIN
     [BD SharePoint].dbo.Lists li ON
     li.tp_ID = ud.tp_ListId

De esta vista podremos extraer los datos de una lista concreta mediante el campo tp_Title realizando una consulta y guardándola en una nueva vista. Muy interesante resultan los gráficos de barras para extraer las medias en encuestas o los gráficos circulares para porcentajes por ejemplo de tipos de contenido, todo depende de nuestra pericia con las consultas SQL. Aquí van dos ejemplos:



Para poder poner nuestro gráfico en SharePoint necesitamos tener instalado los Office Web Components.
Una vez tengamos los Office Web components agregamos la WebPart Gráfico Dinámico de Office que está en la galería de servidor virtual.

Al agregarlo a nuestra página nos dará la opción de conectarse a un origen de datos externo y al pulsar sobre ella seleccionamos agregar una conexión con SQL Server.
Nos saldrá un asistente donde primero deberemos poner el nombre de nuestro servidor y la opción de usar nombre de usuario y contraseñas, donde pondremos el usuario que nos creamos en nuestra base de datos para las vistas, el cual tenía acceso de lectura.

En el siguiente paso seleccionamos nuestra base de datos y la vista con los datos para nuestro gráfico.
En el último paso marcamos la casilla para guardar la contraseña en el archivo y almacenamos el archivo de conexión en una biblioteca de SharePoint donde todos los usuarios tengan acceso, si no habrá usuarios que no puedan visualizar el gráfico.

Una vez tenemos todo esto ya solo queda pelearse con las opciones de la WebPart para dejar nuestro gráfico como nos guste.

Un sitio bien configurado al que le agreguemos un gráfico puede ser un gran sitio. Podemos por ejemplo configurar un sitio para evaluación de proveedores o clientes, donde tengamos la ficha con la información del cliente, unas listas con sus pedidos y lo complementemos con unos gráficos sobre su media en las evaluaciones y sobre sus pedido o histórico de ventas.

Además de todo esto los gráficos entran mas por los ojos, sobre todo si tienen unos buenos colores.

miércoles, 21 de marzo de 2007

Disponible la Web del V CAIQ


Como anuncié anteriormente, los días 19, 20 y 21 de Abril se celebrará en Almería el V Congreso Andaluz de Ingeniería Química.

El V CAIQ contará con el patrocinio y colaboración de numerosas empresas del sector y asociaciones, muy especialmente AIQU, asociación organizadora del congreso.

No dudeis en visitar la Web del V CAIQ que ya se encuentra operativa, donde podéis encontrar toda la información del congreso.

miércoles, 7 de marzo de 2007

E=MC2 ¿Es realmente cierto?


Científicos del NEC Research Institute de Princeton han conseguido superar en 300 veces la velocidad de la luz.

Los investigadores manipularon un vapor de átomos irradiados por laser que acelera la velocidad de las ondas de luz, produciendo que un pulso atravesara la cámara preparada con el vapor unas 300 veces más rápido que si lo hiciera en el vacío.

El hecho invita a pensar que Albert Einstein no estaba en lo cierto en su teoría de la relatividad, ya que según esta nada puede viajar más rápido que la luz. Pero parece ser que la teoría de la relatividad es relativa. Me explico, nada con masa puede viajar más rápido que la luz.

Lo mas curioso del experimento es que el pulso salió de la cámara antes de entrar en ella. Cito textualmente del artículo original "cuando las ondas de luz están distorsionadas, el pulso viaja hacia delante en el tiempo", parece de ciencia ficción.

La investigación del NEC se publicara en la revista Nature.

Artículo original en CBC News.

lunes, 5 de marzo de 2007

Creación de Informes Word de Listas de SharePoint

Todos conocemos las bondades de SharePoint, pero a pesar de tener toda la información que se pueda desear bien almacenada y organizada y de las herramientas de filtro, búsqueda, vistas y demás, se sigue queriendo tener un informe en papel para distribuir, anotar, leer, etc.
Para solventar esa ‘necesidad’ de imprimir de los usuarios se puede crear una aplicación de escritorio para generar informes de las listas que nos interesen. Para ello crearemos una aplicación Windows Form en la que usaremos los WebService que nos brinda SharePoint y el modelo de objetos de Microsoft Word.


Primero deberemos obtener los elementos de la lista que nos interesa. Para usar el WebService que nos hace falta debemos agregar una referencia web a nuestro proyecto, para ello pulsamos con el botón derecho en “Referencias Web” y seleccionamos agregar. En la zona URL ponemos “http://spserver/_vti_bin/lists.asmx” (donde spserver es la ruta del sitio donde se halla la lista que nos interesa) y cambiamos el nombre de referencia web por “WSList” para que nos sea más fácil a la hora de programar. También deberemos añadir los espacios de nombres System.Net y System.Xml para poder implementar el siguiente método:

public bool obtenerElementos()
{
  try
  {
    WSList.Lists lista = new WSList.Lists();
    lista.Credentials = new NetworkCredential(usuario, password, dominio);

    lista.Url = "http://spserver/_vti_bin/lists.asmx";

    XmlDocument xmlDoc = new XmlDocument();
    XmlNode nodeQ = xmlDoc.CreateNode(XmlNodeType.Element, "Query","");
    XmlNode nodeVF = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields","");
    XmlNode nodeQO = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions","");

    XmlNode xmlNode = lista.GetListItems("Noticias",null,nodeQ,nodeVF,null,nodeQO);

    string xpathQuery = "//*[local-name() = 'data' and namespace-uri() = 'urn:schemas-microsoft-com:rowset']/*[local-name() = 'row' and namespace-uri() = '#RowsetSchema']";

    noticias = xmlNode.SelectNodes(xpathQuery);

    return true;
  }
  catch(Exception ex)
  {
    return false;
  }
}

Con este método ya tenemos almacenados los elementos de nuestra lista de Noticias en un objeto XmlElement que lo declararemos de forma global para la aplicación. Ahora solo queda crear el informe en Word.

Para poder crear un informe en Word deberemos primero agregar unas referencias a nuestro proyecto. Para ello seleccionamos agregar nueva referencia y en la pestaña COM seleccionamos “Microsoft Word Object Library” y la agregamos.

Para poder implementar el método hemos de poner en nuestro código la llamada a la librería de Word, using Word = Microsoft.Office.Interop.Word. Y el código de nuestro método para generar un informe en Word es:
public string crearInformeWord()
{
/* Creamos la aplicacion word y el documento */
Word._Application oWord;
  Word._Document oDoc;
  oWord = new Word.Application();

  for(int i=0; i'<'noticias.Count; i++)
  {
    try
    {
      object oMissing = System.Reflection.Missing.Value;
/* \endofdoc es un bookmark predefinido
* para el final del documento */
      object oEndOfDoc = "\\endofdoc";

/* Creamos un nuevo documento de Word */
      oDoc = oWord.Documents.Add(ref oMissing,ref oMissing,ref oMissing,ref oMissing);
      object oRng;

/* Creamos el párrafo para insertar el titulo */
Word.Paragraph oParrafoTitulo;

/* Establecemos la referencia del parrafo
* al final del documento */
      oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
      oParrafoTitulo = oDoc.Content.Paragraphs.Add(ref oRng);

/* El texto del párrafo será el título de la noticia */
      oParrafoTitulo.Range.Text = noticias[i].Attributes[“ows_Title”].Value;
      oParrafoTitulo.Range.Font.Name = "Tahoma"; //Fuente de la letra
      oParrafoTitulo.Range.Font.Size = 12; //Tamaño de la letra
      oParrafoTitulo.Range.Font.Bold = 1; //Negrita SI/NO
      oParrafoTitulo.Format.SpaceAfter = 12; //Espacio con el parrafo siguiente
      oParrafoTitulo.Range.InsertParagraphAfter(); //Inserta el párrafo

/* Creamos el párrafo para insertar el cuerpo */
      Word.Paragraph oParrafoCuerpo;

/* Establecemos la referencia del parrafo al final del documento */
      oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
      oParrafoCuerpo = oDoc.Content.Paragraphs.Add(ref oRng);

/* El texto del párrafo será la descripción de la noticia */
      oParrafoCuerpo.Range.Text = noticias[i].Attributes[“ows_Descripcion”].Value;
      oParrafoCuerpo.Range.Font.Name = "Tahoma"; //Fuente de la letra
      oParrafoCuerpo.Range.Font.Size = 10; //Tamaño de la letra
      oParrafoCuerpo.Range.Font.Bold = 0; //Negrita SI/NO
      oParrafoCuerpo.Format.SpaceAfter = 6; //Espacio con el parrafo siguiente
      oParrafoCuerpo.Range.InsertParagraphAfter(); //Inserta el párrafo

/* Salto de página para poner una noticia en cada página del informe
* Solo saltamos de página si no es la última noticia */
      if(i+1 < noticias.Count)
      {
        Word.Paragraph oParaSalto;
        oRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;
        oParaSalto = oDoc.Content.Paragraphs.Add(ref oRng);
        object oPageBreak = Word.WdBreakType.wdPageBreak;
        oParaSalto.Range.InsertBreak(ref oPageBreak);
      }

    }
    catch(Exception ex)
    {
/* Muy importante ponerlo también en el catch
* Ya que si falla y no se pone Word queda abierto en segundo plano */
      oWord.Visible = true;
    }
  }
}

También podemos generar una tabla con todas las noticias:

public string crearTablaWord()
{
/* Creamos la aplicación Word y el documento */
  Word._Application oWord;
  Word._Document oDoc;
  oWord = new Word.Application();

  try
  {
/* Calculo del numero de filas
* para poner en cada fila dos noticias (2 columnas) */
    int filas = 1;

    if(noticias.Count%2 == 1)
    {
      filas = (noticias.Count/2)+1;
    }
    else
    {
      filas = noticias.Count/2;
    }

/* Creamos el objeto tabla */
    Word.Table oTable;

/* Establecemos la posición al final del documento */
    Word.Range wrdRng = oDoc.Bookmarks.get_Item(ref oEndOfDoc).Range;

/* Indicamos el numero de filas y columnas */
    oTable = oDoc.Tables.Add(wrdRng, filas, 2, ref oMissing, ref oMissing);
    oTable.Range.ParagraphFormat.SpaceAfter = 6;
    oTable.Columns.Borders.Enable = 1; //ponemos bordes a la tabla
oTable.Range.Font.Bold = 0;

/* Agregamos el texto a las celdas */
    int r, c, pos;
    pos = 0;
    string text;
    for(r = 1; r '<'= filas; r++)
    {
      for(c = 1; c '<'= 2; c++)
      {
/* Controlamos si en la última celda no se va a escribir nada */
      if(r==filas && c==2)
      {
        text = "Título: ";
        oTable.Cell(r, c).Range.Text = text;
        text = "Autor: ";
        oTable.Cell(r, c).Range.Text += text;
        text = "Creado: ";
        oTable.Cell(r, c).Range.Text += text;
      }
      else
      {
/* Ponemos el titulo, autor y fecha de creación de la noticia */
          text = "Título: "+ noticias[pos].Attributes["ows_title"].Value;
          oTable.Cell(r, c).Range.Text = text;
          text = "Autor: "+ noticias[pos].Attributes["ows_Author"].Value;
          oTable.Cell(r, c).Range.Text += text;
          text = "Creado: "+ noticias[pos].Attributes["ows_Created"].Value;
          oTable.Cell(r, c).Range.Text += text;
        }

        pos++;
      }
    }
  }
  catch(Exception ex)
  {
/* Muy importante ponerlo también en el catch ya que si falla
* y no se pone, Word queda abierto en segundo plano */

    oWord.Visible = true;
  }

  oWord.Visible = true;
}

Si queremos que nuestro informe quede mejor, podemos crear una plantilla de Word con un encabezado y pie de página, donde podremos poner un logo, número de páginas, etc y crear el informe a partir de esa plantilla. Para hacer esto solo habrá que cambiar lo siguiente al principio del método:

/* Hay que cambiar esto */
oDoc = oWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing);

/* Por esto otro */
object oPlantilla = "c:\\plantilla.dot";
oDoc = oWord.Documents.Add(ref oPlantilla,ref oMissing,ref oMissing, ref oMissing);

Con esto tenemos un generador de informes de cualquier lista de SharePoint que a más de un usuario le puede interesar.

viernes, 2 de marzo de 2007

No es una producción de Jerry Bruckheimer


Vía Xataka me he encontrado con este vídeo, en el cual se ve una nueva investigación para mejorar el transporte ferroviario, pero por lo que se ve se podría aplicar a muchos tipos de transporte (habéis visto los coches en Minority Report).

Se trata básicamente de enfriar un imán con nitrógeno líquido y al ponerlo sobre una superficie metálica el imán la repele pero a su vez la atrae, permitiendo al tren levitar sobre los raíles pero sin separarse de ellos ni salirse. Las vías pueden estar debajo, en el lateral o incluso encima del medio de transporte. El único inconveniente es que se evapore el nitrógeno líquido.

Ya me veo subiendo a mi 117º piso en mi coche.

viernes, 23 de febrero de 2007

Agregar integrantes a un sitio de SharePoint


Como complemento a Creación de Sitios de SharePoint con C#, publicado unas entradas más abajo, expondré ahora como agregar integrantes a los sitios de SharePoint desde nuestro código, lo que puede ser muy útil para dejar configurado por completo un sitio desde nuestra aplicación.

Para agregar un integrante necesitamos la ruta del sitio en cuestión y que la persona que queremos agregar ya sea usuario de nuestro SharePoint. La ruta que hace falta para la implementación que expondré es relativa al servidor (si el sitio es “http://spserver/sites/proyectos/” la ruta que nos hace falta es solo “/sites/proyectos/”). El usuario que le vamos a pasar al método debe tener el formato “DOMINIO\nombre_usuario”, así lo podremos obtener la colección de usuarios de SharePoint sin problemas.

Para agregar uno o varios integrantes hay que introducir los datos en un vector SPUserInfo (correo electrónico, nombre de usuario y nombre para mostrar) y será dicho vector el que añadamos a la colección de usuarios. También tendremos que decidir que rol le otorgaremos a los usuarios que agreguemos ya que si no agregamos los usuarios también al rol no llegarán a formar parte del sitio.

El método que a continuación se expone es para agregar un solo usuario:

private bool agregarIntegrante(string ruta, string usuario)
{
  try
  {

/* Obtenemos la colección de sitios de nuestro portal
* y el sitio especificado por 'ruta' */

    SPGlobalAdmin ga = new SPGlobalAdmin();
    SPSiteCollection col = ga.VirtualServers[0].Sites;
    SPSite s = col[ruta];

    s.AllowUnsafeUpdates = true;

/* Obtenemos la colección de usuarios del sitio
* y creamos el rol que tendrán los nuevos integrantes
* en este caso el rol es de Administrador */

    SPWeb w = s.OpenWeb();
    SPUserCollection ucoll = w.SiteUsers;
    SPRole rol = w.Roles["Administrador"];

/* Obtenemos al usuario que queremos agregar como integrante
* del portal principal, creamos el vector de SPUserInfo
* y agregamos los datos del usuario */

    SPUser u = col[0].OpenWeb().Users[usuario];
    SPUserInfo[] ui = new SPUserInfo[1];

    ui[0].Email = u.Email;
    ui[0].LoginName = u.LoginName;
    ui[0].Name = u.Name;

/* Agregamos el vector SPUserInfo a la colección de usuarios
* y al usuario en concreto en el rol especificado anteriormente */

    ucoll.AddCollection(ui);
    rol.AddUser(u.LoginName, u.Email, u.Name, u.Notes);

    return true;
  }
  catch(Exception ex)
  {
    return false;
  }
}



Como también dije con la creación de sitios, agregar integrantes desde nuestro código puede ser muy interesante si lo aplicamos a un flujo de trabajo y muchísimo más interesante si combinamos la creación de sitios con el método para agregar integrantes.

martes, 20 de febrero de 2007

Interfaces naturales





Increíble ¿no os parece? Este video está en FastCompany, en el se puede ver una demostración de Perceptive Pixel, una empresa creada por Jeff Han para el desarrollo de los sistemas táctiles multi-punto. En este desarrollo de Jeff Han está la evolución de los sistemas táctiles. Este siguiente paso nos lleva a un manejo natural y sencillo de las aplicaciones.
Solo hay que fijarse en el éxito de un producto, supongo todos conocéis, el Apple iPhone. Todos están de acuerdo en que podría ser 3G, llevar GPS, tener una pantalla 16:9 en lugar del formato que usa, incorporar lector de tarjetas y más cosas que todo teléfono móvil-SmartPhone-PDA-reproductor audio/video debería llevar. Pero aun así es el objeto de deseo de numerosas personas (entre las cuales me incluyo).

Creo que su éxito se debe a la facilidad de uso, a su pantalla táctil multi-punto, a lo simple y completa de su interfaz (puede que también a que es la siguiente generación del iPod). ¿A cuántos nos cuesta realizar una multiconferencia o dejar en espera la llamada que atendemos porque hay otra entrante? Pues fíjense en lo fácil que resulta con el iPhone, en cómo se desplaza a través de la lista de contactos o del Cover Flow (los álbumes de música) y lo fácil que es el manejo de las fotos.

Espero que dentro de poco no necesitemos ni teclado ni ratón para usar nuestro ordenador, simplemente una pantalla táctil como la de Jeff Han.

lunes, 19 de febrero de 2007

V Congreso Andaluz de Ingeniería Química (V CAIQ)

En próximas fechas, concretamente el 19, 20 y 21 de Abril, se celebrará en Almería el V Congreso Andaluz de Ingeniería Química.

No es que la ingeniería química sea un tema que me apasione, pero hay que darlo a conocer y de paso ofrezco un poco de apoyo a AIQU (es especial a Eli y Estefanía), la asociación que se está encargando de toda la organización del congreso.

Les deseo que todo les salga bien y que sea un éxito.


Por cierto, el cartel lo ha creado un servidor con la encomiable colaboración de un amigo. En breve también tendremos lista la página web del congreso, donde se podrá consultar toda la información referente al V CAIQ.

Creación de sitios de SharePoint con C#

Crear sitios de SharePoint mediante programación puede ser realmente útil. Si combinamos dicha creación de sitios con aplicaciones remotas, de consola, WebParts o los nuevos flujos de trabajo (work flows), se pueden hacer cosas muy interesantes.

Lo primero que nos hace falta para crear un sitio es obtener el sitio bajo el cual lo crearemos y de él obtener su SPWebCollection. Esta colección será la que nos proporcione el método necesario para crear un sitio.
Otra cosa que nos hace falta es la plantilla que vamos a usar en ese sitio. Se puede usar una de las plantillas que tiene SharePoint o una que hayamos creado nosotros. En definitiva, necesitamos el objeto SPWebTemplate de la plantilla que vayamos a usar.

El método que nos proporciona nuestra SPWebCollection añade una nueva SPWeb a la colección. A continuación se muestra el método con los parámetros necesarios:

webCollection.Add(Ruta, Titulo, Descripcion, LOCALID, Plantilla, Permisos, Convertir);

  • Ruta: String con la ruta por la que se accederá al nuevo sitio. Solo ha de contener el nuevo nombre, omitiendo la ruta hasta el sitio al que pertenece la nueva SPWeb. Ej.: Si el nuevo sitio que queremos crear bajo “proyectos” es “informes” la ruta de acceso seria “http://spserver/sites/proyectos/informes”, pero el parámetro para el método seria únicamente “informes”.
  • Titulo: String con el título que se dará al nuevo sitio.
  • Descripción: String con la descripción del nuevo sitio.
  • LOCALID: UInt32. En nuestro caso es 3082, que identifica el idioma español de nuestro Sharepoint.
  • Plantilla: SPWebTemplate que indica la plantilla que se va a utilizar para la creación del nuevo sitio. Esta plantilla se podrá obtener de la colección de plantillas del sitio.
  • Permisos: Bolean que indica si se utilizarán permisos exclusivos o heredados del sitio al que pertenece.
  • Convertir: Bolean para definir si se sobrescribirá el sitio si la ruta ya existe o si lanzará una excepción. Si se establece el valor a verdadero se sustituirá el sitio existente con el que se cree nuevo, por el contrario si se establece a falso, el método devolverá una excepción indicando que la ruta ya existe.

Si se sabe cuando utilizar puede resultar realmente útil crear los sitios a través de nuestro código y se podrían crear flujos de trabajos muy completos que automatizarán la creación de sitios.

viernes, 16 de febrero de 2007

Convertir de JPG a PDF

Hace unos días ayude un poco a mis compañeros de trabajo que estaban muy ocupados. El trabajo consistía en convertir unas fichas generadas por un programa de formato JPG a PDF. Puede parecer fácil, que lo es, pero cuando son cientos de archivos los que hay que convertir se convierte en tedioso y requiere una inversión de tiempo considerable.
Mientras estaba en ello, pensé en lo lento que estaba resultando y que no podía hacer otra cosa mientras. Así que se me ocurrió hacer un pequeño programa que lo hiciera por mí. Y a ello me puse.
Tras unas pocas pruebas en el Visual Studio conseguí hacerlo más fácilmente de lo que esperaba. Agregando una referencia al componente COM Acrobat (por supuesto hay que tener instalado Adobe Acrobat Profesional) en un proyecto Windows Forms y escribir la correspondiente llamada using Acrobat, este es el código para convertir los archivos:

AcroAVDocClass avdoc = new AcroAVDocClass();
avdoc.Open(ruta_archivoJPG, titulo_documento);

AcroPDDoc pddoc = (AcroPDDoc)avdoc.GetPDDoc();
pddoc.Save(3, ruta_destino_archivoPDF);

avdoc.Close(1);
pddoc.Close();

Agregando un OpenFileDialog y un foreach conseguí que hiciera el trabajo por mí. Mientras se convertían los cientos de archivos yo podía dedicarme a hacer otras cosas.
Queda pendiente una mejora para poder convertir otros tipos de archivos, pero eso para más adelante.

El porqué

Pues aqui estoy, creando mi primera entrada de mi primer blog.
Yo mismo aun estoy preguntándome porque he creado un blog. Tal vez solo quiera un sitio donde poder escribir sobre mis pequeños avances en el mundo de la programación y poder compartirlos, o sobre los gadget que me fascinan, o sobre las opiniones que me rondan la cabeza. O simplemente sea que un dia me negué a crear un Space (ya sabeis, esos Windows Live Spaces) y de ahi no hay quien me mueva.
En todo caso, bienbenido sea.