Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   TresourceStream con archivo de Recursos .rc (https://www.clubdelphi.com/foros/showthread.php?t=96611)

jesusgandia1966 20-02-2024 13:04:58

TresourceStream con archivo de Recursos .rc
 
Anteriormente en Studio 2010 tenia un código que no consigo hacer funcionar en RIO 1.3.
Tenia este código que podía llamar a varios archivos del fichero de recursos, pero ahora no sé como hacerlo sin tener que crear un puntero para cada uno de los ficheros contenido en el fichero de recursos.
CODIGO ANTIGUO:
Código PHP:

String CAB Ruta L"dat.cab";
String RAR Ruta L"rar.exe";
if(!
FileExists(RAR.w_str()))//Si no existe Rar.exe
      
TResourceStream(0L"C"RT_RCDATA).SaveToFile(CAB.w_str());

if(!
FileExists(IMG.w_str()))
      
TResourceStream(0L"R"RT_RCDATA).SaveToFile(RAR.w_str());

//... y así sucesivamente hasta sacar todos los ficheros del RECURSO. 

ERROR QUE ME APARECE:
[ilink32 Error] Error: Unresolved external 'System::Classes::TResourceStream::{1173}...' referenced from D:\BDS_10_3\TPV-START\WIN32\DEBUG\UNIDADTPVBARMAN_START.OBJ
[ilink32 Error] Error: Unable to perform link

Ahora solo he encontrado esta forma de hacerlo con la creación de un PUNTERO, puesto que la forma anterior compila en .cpp de la llamada pero al generar el fichero del proyecto me da error y no los consigo hacer funcionar.

CODIGO NUEVO:
Código PHP:

String CAB Ruta L"dat.cab";
String RAR Ruta L"rar.exe";

TResourceStream *= new TResourceStream((int)HInstance"C"RT_RCDATA);
   
__try
   
{
      
B->SaveToFile(CAB.w_str());
/* La pregunta es... ¿Como sacar los otros ficheros del recurso antes de destruir el PUNTERO?*/

   
}
   
__finally
      
{
         
delete B;
      } 

Fichero de RECURSOS. IB_Replicador.rc
Código PHP:

/*IB_Replicador.rc*/
C RCDATA "dat.cab"
R RCDATA "rar.exe"
D RCDATA "divisas.cab"
B RCDATA "Barman.dat"
W RCDATA "nzw.dll"
IMG_1 RCDATA "IMG\\Inicio_2.jpg"
IMG_2 RCDATA "IMG\\imagen_jpg_error.jpg"
IMG_3 RCDATA "IMG\\Inicio_3.jpg"
IMG_4 RCDATA "IMG\\imagen_articulos.jpg"
IMG_5 RCDATA "IMG\\imagen_comanda.jpg"
IMG_6 RCDATA "IMG\\imagen_familias.jpg"
IMG_7 RCDATA "IMG\\imagen_operador.jpg"
IMG_8 RCDATA "IMG\\BalanzaDibal.jpg"
IMG_9 RCDATA "IMG\\CashDro.jpg"
IMG_10 RCDATA "IMG\\CashGuard.jpg"
IMG_11 RCDATA "IMG\\CashKeeper.jpg"
IMG_12 RCDATA "IMG\\CashLogy.jpg"
IMG_13 RCDATA "IMG\\Modo_Limpieza.jpg"
IMG_14 RCDATA "IMG\\display.jpg"
IMG_15 RCDATA "IMG\\display_2.jpg"
IMG_16 RCDATA "IMG\\1024_768.jpg"
IMG_17 RCDATA "IMG\\1280_800.jpg"
IMG_18 RCDATA "IMG\\1280_1024.jpg"
IMG_19 RCDATA "IMG\\1360_768.jpg"
IMG_20 RCDATA "IMG\\1920_1080.jpg"
IMG_21 RCDATA "IMG\\Color1.jpg"
IMG_22 RCDATA "IMG\\Color2.jpg"
IMG_23 RCDATA "IMG\\Color3.jpg"
IMG_24 RCDATA "IMG\\Color4.jpg"
IMG_25 RCDATA "IMG\\Color5.jpg"
IMG_26 RCDATA "IMG\\Color6.jpg"
IMG_27 RCDATA "IMG\\Mesas_Repres_Iconos.jpg"
IMG_28 RCDATA "IMG\\Mesas_Cod_Daltonicos.jpg"
IMG_29 RCDATA "IMG\\porciones.jpg" 


Neftali [Germán.Estévez] 21-02-2024 13:58:03

Cita:

Empezado por jesusgandia1966 (Mensaje 554541)
...
Tenia este código que podía llamar a varios archivos del fichero de recursos, pero ahora no sé como hacerlo sin tener que crear un puntero para cada uno de los ficheros contenido en el fichero de recursos.

No explicas muy bien lo que necesitas. A veces en lugar de centrarte en lo que tienes, sale más a cuenta explicar bien lo que necesitas desde cero.

Cita:

Empezado por jesusgandia1966 (Mensaje 554541)
[/php]ERROR QUE ME APARECE:
[ilink32 Error] Error: Unresolved external 'System::Classes::TResourceStream::{1173}...' referenced from D:\BDS_10_3\TPV-START\WIN32\DEBUG\UNIDADTPVBARMAN_START.OBJ

Parece que ese recurso no está disponible. ¿Realmente lo tienes?

Cita:

Empezado por jesusgandia1966 (Mensaje 554541)
Ahora solo he encontrado esta forma de hacerlo con la creación de un PUNTERO, puesto que la forma anterior compila en .cpp de la llamada pero al generar el fichero del proyecto me da error y no los consigo hacer funcionar.

Aquí hablas de otro error que tampoco especificas.
Supongo que tú tienes claro el problema y lo que necesitas, pero creo que para los que no sabemos nada la pregunta es bastante confusa.

Un saludo.

jesusgandia1966 21-02-2024 18:54:35

Creo haber realizado la pregunta correctamente y bien explicada.
La pregunta simple viendo el fichero de recursos que contiene varios archivos es que con el código que muestro como puedo acceder a los otros ficheros del recurso desde el mismo PUNTERO que he creado.
Código PHP:

String CAB Ruta L"dat.cab";
String RAR Ruta L"rar.exe";

TResourceStream *= new TResourceStream((int)HInstance"C"RT_RCDATA);
   
__try
   
{
      
B->SaveToFile(CAB.w_str());
/* La pregunta es... ¿Como sacar los otros ficheros del recurso antes de destruir el PUNTERO?*/

   
}
   
__finally
      
{
         
delete B;
      } 

El fichero de recursos contine 29 ficheros entre ellos estos 2:
C RCDATA "dat.cab"
R RCDATA "rar.exe"
en el codigo extraigo el "dat.cab" y la pregunta es:
¿Como hago ahora para extraer el "rar.exe" antes de destruir el PUNTERO B*?

escafandra 21-02-2024 21:54:50

Puedes hacer algo como esto:


Código PHP:

void __fastcall SaveResource(String ResNameString FileName)
{
  
TResourceStream *Res = new TResourceStream((int)HInstanceResNameRT_RCDATA);
  
__try{
     
Res->SaveToFile(FileName);
  }
  
__finally{
     
delete Res;
  }
}


//---------------------------------------------------------------------------

String CAB Ruta L"dat.cab";
String RAR Ruta L"rar.exe";

if(!
FileExists(RAR))//Si no existe Rar.exe
   
SaveResource(L"C"CAB);
if(!
FileExists(IMG))
  
SaveResource(L"R"RAR);
................... 




Saludos.

jesusgandia1966 22-02-2024 11:17:58

SaveResource(L"C", CAB); NO RESPONDE...
Necesita alguna LIBRERIA?

O de qué objeto desciende?

jesusgandia1966 22-02-2024 15:20:03

Gracias pero lo que haces es automatizar los procesos por medio de una función, pero crea y destruye el PUNTERO en cada llamada.
Eso no es lo que preguntaba, ya se que así se ahorra código... pero no es lo que preguntaba precisamente.
La pregunta correcta sin poner CODIGO seria...
Como puedo EXTRAER varios FICHEROS de varios TIPOS Y CONTENIDOS en un Fichero de RECURSOS sin tener que crear un puntero con [new] y destruir con [delete] en cada llamada?

Antes en Studio 2010 podía hacer esto:
Código PHP:

String CAB Ruta L"dat.cab";
String RAR Ruta L"rar.exe";
if(!
FileExists(RAR.w_str()))//Si no existe Rar.exe
      
TResourceStream(0L"C"RT_RCDATA).SaveToFile(CAB.w_str());

if(!
FileExists(IMG.w_str()))
      
TResourceStream(0L"R"RT_RCDATA).SaveToFile(RAR.w_str());

//... y así sucesivamente hasta sacar todos los ficheros del RECURSO. 


jesusgandia1966 23-02-2024 13:47:57

EN CUALQUIER CASO GRACIAS POR EL APORTE, no se me había ocurrido hacer una función tal como muestras para simplificar muchísimo el código, ya que tengo que extraer 33 ficheros del RECURSO.
GRACIAS OTRA VEZ.

escafandra 23-02-2024 21:55:59

En C++ puedes crear un objeto directamente con el constructor (función de nombre igual al de la clase) o indirectamente con el operador new + el constructor. En la primera forma el objeto vive lo que dure su ámbito, en la segunda vive hasta que uses delete.
El las clases de la VCL debes usar el operador new por exigencia de la VCL. Aunque funcione la cración directa de TResourceStream con versiones de Builder (en Berlin funciona) no es la forma apropiada y la ayuda te indica que debes crearlo de forma indirecta.


No se porqué tienes esa idea de no destruir el puntero, ten en cuenta que cada instancia que usas es un objeto diferente que se va a destruir sola, si usas la forma directa o con delete si usas la indirecta.

Existe una forma de que el puntero se autodestruya con los punteros inteligentes: auto_ptr, pero el puntero se destruirá de igual forma tras el uso de cada instancia.


Si lo que pretendes es usar auto_ptr, aquí tienen un esquema:
Código:

#include <memory>


...........
if(!FileExists(RAR))
  std::auto_ptr <TResourceStream> (new TResourceStream(0, L"C", RT_RCDATA))->SaveToFile(RAR);
if(!FileExists(IMG))
  std::auto_ptr <TResourceStream> (new TResourceStream(0, L"R", RT_RCDATA))->SaveToFile(IMG);


Usa Templates en lugar de una función como te puse arriba que quizás es más fácil de entender. Eso significa que el compilador expande el código del template a cada llamada.


Saludos.

escafandra 23-02-2024 23:49:30

...............................................

jesusgandia1966 24-02-2024 12:20:54

Si me quedó claro, y entendí que al crear el puntero con:
Código PHP:

TResourceStream *Res = new TResourceStream((int)HInstance"C"RT_RCDATA); 

Estoy accediendo a la posición de memoria que solo ocupa el fichero "C" y no a todo el contenido del fichero de RECURSOS. Por tanto mi petición no tenía ninguna lógica.
Es normal crear una instancia para cada fichero contenido en el fichero de recursos y empleando la función sencilla que escribiste a mi entender es la forma correcta.
Código PHP:

void __fastcall SaveResource(String ResNameString FileName)
{
  
TResourceStream *Res = new TResourceStream((int)HInstanceResNameRT_RCDATA);
  
__try{
     
Res->SaveToFile(FileName);
  }
  
__finally{
     
delete Res;
  }


Tal como tu dices, ya vi que en la ayuda del STUDIO 10.3.3 se dice como crear y utilizar el FICHERO DE RECURSOS, la confusion me llego porque del STUDIO 2010 al STUDIO 10.3 ha cambiado su forma.
AYUDA STUDIO 10.3.3:
Código PHP:

/*This example shows how to load the text from a txt file using a resource file. 

To build and test this example: 

Create a Multi-Device Application.
Add the following controls on the form: 
TButton
TLabel
Add the txt file to the project's folder.
Go to Project > Resources and Images... and add the txt file.
Build the project to generate the .rc file that contains the reference to the txt file.
Open the <project_name>_<resources>.rc file where you can see the name of the resource, the type, and the name of the file.
Resource_1 RCDATA "<file_name>.txt"
*/

void __fastcall TForm1::Button1Click(TObject *Sender) {
  
TResourceStream *Stream = new TResourceStream((int)HInstance"<Resource identifier>"RT_RCDATA); //RT_RCDATA is the Resource Type.
  
__try {
    
TStringList *List = new TStringList;
    
__try {
      List->
LoadFromStream(Stream);
      
Label1->Text = List->Text;
    }
    
__finally {
      List->
DisposeOf();
    }
  }
  
__finally {
    
Stream->DisposeOf();
  }



Gracias escafandra...


La franja horaria es GMT +2. Ahora son las 13:20:39.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi