 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Dom 29 Abr, 2018 12:22 am Asunto: Como leer un valor REG_MULTI_SZ del Registro de Windows |
|
|
¿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 |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Dom 29 Abr, 2018 7:03 am Asunto: |
|
|
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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Dom 29 Abr, 2018 10:22 am Asunto: |
|
|
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 |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Dom 29 Abr, 2018 3:42 pm Asunto: |
|
|
| 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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Dom 06 May, 2018 1:32 pm Asunto: |
|
|
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 |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Dom 06 May, 2018 7:44 pm Asunto: |
|
|
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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Lun 07 May, 2018 1:30 pm Asunto: |
|
|
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 |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Lun 07 May, 2018 3:12 pm Asunto: |
|
|
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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Lun 07 May, 2018 4:56 pm Asunto: |
|
|
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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Lun 07 May, 2018 5:09 pm Asunto: |
|
|
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 |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Lun 07 May, 2018 5:52 pm Asunto: |
|
|
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 |
|
 |
JesúsGandia Master


Registrado: 17 Jul 2004Mensajes: 403Ubicación: Gandia, Valencia
|
Publicado: Lun 07 May, 2018 7:10 pm Asunto: |
|
|
Gracias Leo, funciona perfecto. _________________ Muchos hombres no se equivocan jamás porque no se proponen nada razonable. |
|
| Volver arriba |
|
 |
|
|
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
|
© 2002–2026 Club Builder · Funciona con phpBB.
|