Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Como leer un valor REG_MULTI_SZ del Registro de Windows

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Como leer un valor REG_MULTI_SZ del Registro de Windows Responder citando

¿Como puedo leer un valor REG_MULTI_SZ y guardarlo en un String o TStringList?

Lo que pretendo saber es si la Impresora Predeterminada de Windows su PAPEL DEFINIDO o SELECCIONADO POR DEFECTO es de Tamaño A4
Código:

    EdImpresoraWindowsPred->Text = Printer()->Printers->Strings[Printer()->PrinterIndex];

    TRegistry *Registro = new TRegistry;
    Registro->RootKey = HKEY_LOCAL_MACHINE;
    String Papel = NULL;
    String Cadena_Completa = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\" + EdImpresoraWindowsPred->Text + "\\DsDriver";
    if(fV->SV->WinSO_bits == 64)
        Cadena_Completa = L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\" + EdImpresoraWindowsPred->Text + "\\DsDriver";

    if(Registro->OpenKeyReadOnly(Cadena_Completa))
        Papel = Registro->ReadString(L"printMediaReady");//Valor REG_MULTI_SZ
//La asignacion a Papel me da error y si en lugar de un String lo hago con un StringList sigue dándome error


    delete Registro;
    if(Papel.Pos("A4"))
    {//Impresora Predeterminada de Windows no es A4
        EdImpresoraWindowsPred->EditLabel->Font->Color = clRed;
        EdImpresoraWindowsPred->EditLabel->Twinkle = true;
    }

_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

Puedes hacerlo de varias maneras, una de ellas:
Código:
//Añadimos: #include<memory> #include<Registry.hpp>
//--- Leer REG_MULTI_SZ
bool RegLeeMulti(HKEY raiz, String clave, String valor, TStrings* sl)
{   
    bool bRet = false;
    std::unique_ptr<TRegistry> reg(new TRegistry);
    reg->RootKey = raiz;
    if (reg->OpenKeyReadOnly(clave))
    {
        int size = reg->GetDataSize(valor);
        if (size > 0)
        {
            String buffer("", size/sizeof(TCHAR));
            reg->ReadBinaryData(valor, buffer.c_str(), size);
            for (unsigned i = 1; i <= size/sizeof(TCHAR)-1; i++)
                if (!buffer[i]) buffer[i] = '\r';
            sl->Text = buffer;
            bRet = true;
        }
    }
    return bRet;
}

//---Un ejemplo de uso:
  RegLeeMulti(HKEY_LOCAL_MACHINE,
    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
    "\\Print\\Printers\\Microsoft Print to PDF\\DsDriver",
    "printMediaSupported", Memo1->Lines);

Aunque para lo que quieres no te va a servir ya que no todas las impresoras rellenan datos como "printMediaReady" en el registro. Pero podrías usar la siguiente función:
Código:
bool IsSelectedPrinterA4(void)
{
  bool ret = false;
  TCHAR ignore[MAX_PATH];
  HGLOBAL hMem = NULL;
  Printer()->GetPrinter(ignore, ignore, ignore, (UINT&)hMem);
  PDEVMODE dev = (PDEVMODE) GlobalLock(hMem);
  try {
   ret = (dev->dmFields & DM_PAPERSIZE) && (dev->dmPaperSize == DMPAPER_A4);
  }
  __finally {
   GlobalUnlock(hMem);
  }
  return ret;
}
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Leo... Desconocía el segundo método que por supuesto es el debo utilizar.
Muchas gracias por el aporte y también por la primera función que de seguro a más de uno del foro le vendrá muy bien.

Pero la segunda opción que sería la correcta me da un error de EAccessViolation:
Access violation at address 0065FD4E in module.
Read of address 0000004E

He ovservado que el error siempre se produce al intentar leer el OBJETO:
PDEVMODE dev = (PDEVMODE) GlobalLock(hMem);


Es decir siempre me da error cuanto intento leer cualquier valor:
Estoy Utilizando: Studio 2010 + Proyectos wchar_t + Windows 10 64bits
Código:

SowMessage(dev->dmPaperWidth);//ERROR
dev->xxx_lo_que_sea




Por otro lado, dices:
"Aunque para lo que quieres no te va a servir ya que no todas las impresoras rellenan datos como "printMediaReady" en el registro."

Pero veo que utilizas otro valor para leer "printMediaSupported"

¿Dicho valor si que es seguro para la lectura?
_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

JesúsGandia escribió:
me da un error de EAccessViolation:
Access violation at address 0065FD4E in module.

No tengo la versión 2010 instalada, pero lo he probado en la 6 y en la XE4 con Windows 10 64bits y con Windows XP SP3 con varias impresoras y no me ha dado problemas.

Aquí tienes otra versión a ver si va mejor:
Código:
// Añadimos: #include<vector>
bool IsSelectedPrinterA4(void)
{
  bool ret = false;
  HANDLE hPrinter = 0;
  TCHAR szPrinter[MAX_PATH];
  DWORD cbNeeded = sizeof(szPrinter);
  if (GetDefaultPrinter(szPrinter, &cbNeeded))
  {
    if (OpenPrinter(szPrinter, &hPrinter, 0))
    {
      if (!GetPrinter(hPrinter, 9, 0, 0, &cbNeeded))
      {
        std::vector<BYTE> buffer(cbNeeded);
        if (GetPrinter(hPrinter, 9, &buffer[0], cbNeeded, &cbNeeded))
        {
          PDEVMODE dev = reinterpret_cast<PPRINTER_INFO_9>(&buffer[0])->pDevMode;
          ret = (dev->dmFields & DM_PAPERSIZE) && (dev->dmPaperSize == DMPAPER_A4);
          ClosePrinter(hPrinter);
        }
      }
    }
  }
  return ret;
}


JesúsGandia escribió:
Pero veo que utilizas otro valor para leer "printMediaSupported"

¿Dicho valor si que es seguro para la lectura?

No, solo era un ejemplo, me pareció mejor para la prueba ya que cuando existe contiene varias líneas.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Leo he tenido que hacer un cambio para evitar el error en ejecución.
He tenido que cambiar el 9 por el 8 y PPRINTER_INFO_9 por PPRINTER_INFO_8

Según la información del Builder:
Windows 2000/XP: A PRINTER_INFO_8 structure specifying the global default printer settings.
9 Windows 2000/XP: A PRINTER_INFO_9 structure specifying the per-user default printer settings.

y de esta forma funciona aunque en EJECUCIÓN del PROGRAMA se cambie la IMPRESORA PREDETERMINADA.
La pregunta es si es CORRECTO y si afectará a todos los USUARIOS WINDOWS, ya que tu habías sugerido "the per-user default" pero me da ERROR y yo lo he cambiado por "the global default "

Código:

//Función que comprueba que la Impresora predeterminada de Windows sea o soporte A4
#pragma option push -Od
bool __fastcall IsSelectedPrinterA4(void)
{
   bool ret = false;
     HANDLE hPrinter = 0;
     TCHAR szPrinter[MAX_PATH];
     DWORD cbNeeded = sizeof(szPrinter);
     if(GetDefaultPrinter(szPrinter, &cbNeeded))
     {
       if(OpenPrinter(szPrinter, &hPrinter, 0))
       {
            if(!GetPrinter(hPrinter, 8, 0, 0, &cbNeeded))
            {
              std::vector<BYTE> buffer(cbNeeded);
              if(GetPrinter(hPrinter, 8, &buffer[0], cbNeeded, &cbNeeded))
              {
                   PDEVMODE dev = reinterpret_cast<PPRINTER_INFO_8>(&buffer[0])->pDevMode;
                   ret = (dev->dmFields & DM_PAPERSIZE) && (dev->dmPaperSize == DMPAPER_A4);
                   ClosePrinter(hPrinter);
              }
            }
       }
  }
  return ret;
}
#pragma option pop
//---------------------------------------------------------------------------

_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

No afecta a nada ya que la función es de solo lectura. Y aunque yo preferiría leer los valores por defecto del usuario activo, tampoco pasa nada importante por leer los ajustes por defecto globales mientras se tenga en cuenta cuando se cambie algún valor por defecto.

Si tienes alguna otra versión de C++Builder instalada prueba la función que te falle para descartar que los errores sean por alguna cosa de la versión de C++Builder, y también hacer alguna prueba en un proyecto nuevo vacío.

Y si aun así te falla, sería interesante que hicieras pruebas hasta descubrir a partir de que línea ocurre el error, y alrededor de esa línea compruebes lo que devuelven las distintas funciones, etc., ya que yo al no poder reproducirlo no se me ocurre porque te puede estar fallando.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Las imágenes 1, 2 y 3 pertenecen al error.
Las imágenes 4 y 5 pertenecen a la compilación sin error.
Las únicas diferencias que aprecio es que en opción del error:
ret = false
buffer = NADA o VACIO
dev = NULL





_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

OK, según esas capturas veo que pasa bien por todas las funciones,
pero "dev" tiene un valor nulo al final. Para mejorarlo habría que
comprobar si es nulo antes de usarlo. Con eso por lo menos evitamos
el error y decidir que otra acción realizar, como leer el nivel 8 o 2 por ejemplo.

Haz una prueba con otra impresora por defecto a ver si solo te
pasa con esa o te pasa con todas.

Según la documentación de Microsoft dice lo siguiente:

"The pDevMode member in the PRINTER_INFO_2, PRINTER_INFO_8,
and PRINTER_INFO_9 structures can be NULL. When this happens,
the printer is unusable until the driver is reinstalled successfully.
"
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Me da el mismo error en otras impresoras, pero no en todas.
Sin embargo con la opción <PPRINTER_INFO_8> no me da error en ninguna ocasión.

Para más seguridad lo protegido con una clausula try...__finally
Con este código ya me vale para mi propósito.
Quizás la opción <PPRINTER_INFO_9> sea más adecuada, pero no me da confianza.
Gracias Leo, mi código final que nunca falla:
Código:

//------------------------------------------------------------------------------
//Función que comprueba que la Impresora predeterminada de Windows sea o soporte A4
#pragma option push -Od
bool __fastcall IsSelectedPrinterA4(void)
{
   bool ret = false;
     HANDLE hPrinter = 0;
     TCHAR szPrinter[MAX_PATH];
     DWORD cbNeeded = sizeof(szPrinter);
     if(GetDefaultPrinter(szPrinter, &cbNeeded))
     {
       if(OpenPrinter(szPrinter, &hPrinter, 0))
       {
            try
            {
                if(!GetPrinter(hPrinter, 8, 0, 0, &cbNeeded))
                {
                    std::vector<BYTE> buffer(cbNeeded);
                    if(GetPrinter(hPrinter, 8, &buffer[0], cbNeeded, &cbNeeded))
                    {
                        PDEVMODE dev = reinterpret_cast<PPRINTER_INFO_8>(&buffer[0])->pDevMode;
                        ret = (dev->dmFields & DM_PAPERSIZE) && (dev->dmPaperSize == DMPAPER_A4);
                    }
                }
            }
            __finally
               {
                   ClosePrinter(hPrinter);
                }
       }
  }
  return ret;
}
#pragma option pop
//---------------------------------------------------------------------------

_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

Como rasgo curioso...
La función funciona perfecta, incluso si cambio la IMPRESORA PREDETERMINADA de WINDOWS con el PROGRAMA EN EJECUCIÓN, solo que ahora tengo un pequeño problema.
Tengo este código que muestra en EDIT la impresora PREDETERMINADA:

Código:

EdImpresoraWindowsPred->Text = Printer()->Printers->Strings[Printer()->PrinterIndex];
if(!IsSelectedPrinterA4())
{//Impresora Predeterminada de Windows no es A4
    EdImpresoraWindowsPred->EditLabel->Font->Color = clRed;
    EdImpresoraWindowsPred->EditLabel->Twinkle = true;
}

Pero la primera LINEA no me actualiza la IMPRESORA PREDETERMINADA aunque la siguiente LINEA del <if> si que funciona avisándome perfectamente de si es A4 o NO.
Es decir... <IsSelectedPrinterA4> si que actualiza y funciona,
pero... <EdImpresoraWindowsPred>Text = Printer()->Printers->Strings[Printer()->PrinterIndex];>
No me actualiza la Impresora hasta que vuelvo a salir y entrar de la aplicación.

Que puedo hacer?
_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mensaje    Asunto: Responder citando

El problema de "Printer()" es que carga la lista la primera vez que se usa y no la refresca. Puedes usar:
Código:
String GetDefaultPrinterName(void)
{
   TCHAR szBuffer[MAX_PATH] = {0};
   DWORD cchBuffer = sizeof(szBuffer);
   GetDefaultPrinter(szBuffer, &cchBuffer);
   return String(szBuffer);
}
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Gracias Leo, funciona perfecto.
_________________
Muchos hombres no se equivocan jamás porque no se proponen nada razonable.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email Visitar sitio web del autor
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.