Iniciar Sesión

Ver la Versión Completa : [Duda] Cobol + Python


Fito
13 de junio de 2025, 16:34
Hola Amigos:

Hay alguna menera de trabajar con PowerCobol y Python que no sea correr por linea de comando y leer un resultado en un txt?

Algo mas tipo funcion u ocx.

Saludos

Fito

Jorgeanna
13 de junio de 2025, 18:09
Quick Start to Server side COM and Python (https://timgolden.me.uk/pywin32-docs/html/com/win32com/HTML/QuickStartServerCom.html)

ayuda para generar un servidor com para utiliza como interface en powercobol

Fito
17 de junio de 2025, 13:10
Hola Jorge:

Gracias, me voy a poner a ver eso, a ver si entiendo algo...

Saludos...

Fito..

Jorgeanna
19 de junio de 2025, 16:50
Por si ayuda en algo, te paso un script, que llamado de powercobol, devuelve el resultado de una operacion aritmetica utilizando ROUND_HALF_EVEN para el resultado, y otra que llama y ejecuta un link web, nada que extraordinario pero que te facilitara ver la mecanica de llamadas y respuestas via COM, tenia mas funciones que entregaban diferentes resultados, pero para mejor analisis las exclui y veas que no es dificil interacturar desde powercobol.

import win32com.client as wc
import win32com.server.register
import time
import sys
from decimal import *
import os
import winreg
import pythoncom

class MODULOSCOM:
_public_methods_ = ['Calculo', 'Navegador']
_reg_progid_ = "MODULOS.COM"
_reg_clsid_ = "{80317A85-F824-45CD-82AC-3B3546C359EE}"
_reg_desc_ = "Servidor COM Python Para PowerVISUAL"

def Navegador(self, Texto):
import webbrowser
webbrowser.open(Texto)
return True

def Calculo(self, NumeroA, NumeroB, Operador, CantidadDecimales=2):
if type(NumeroA) != Decimal:
try:
NumeroA = Decimal(str(NumeroA))
except:
return 0
if type(NumeroB) != Decimal:
try:
NumeroB = Decimal(str(NumeroB))
except:
return 0

if Operador == '+':
Operacion = NumeroA + NumeroB
elif Operador == '-':
Operacion = NumeroA - NumeroB
elif Operador == '*':
Operacion = NumeroA * NumeroB
elif Operador == '/':
try:
Operacion = Decimal(str(NumeroA)) / Decimal(NumeroB)
except:
return 0

ResultadoPrevio = Decimal(str(Operacion))
Resultado = ResultadoPrevio.quantize(Decimal('1') / Decimal('10') ** Decimal(str(CantidadDecimales)),
rounding=ROUND_HALF_EVEN)

return Resultado

def remove_registry_entry(clsid):
try:
reg_key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, f"CLSID\\{clsid}", 0, winreg.KEY_SET_VALUE)
winreg.DeleteKey(reg_key, "")
print(f"Clave de registro de {clsid} eliminada.")
winreg.CloseKey(reg_key)
except Exception as e:
print(f"Error al eliminar la clave de registro: {e}")

def check_registry_clsid(clsid):
try:
reg_key = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, f"CLSID\\{clsid}")
winreg.CloseKey(reg_key)
return True
except FileNotFoundError:
return False

if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1].lower() == "register":
# Registra el servidor COM
win32com.server.register.UseCommandLine(MODULOSCOM )
print("Servidor COM registrado.")
elif len(sys.argv) > 1 and sys.argv[1].lower() == "unregister":
try:
print("Desregistrando el servidor COM...")

# Intentamos desregistrar usando UseCommandLine
win32com.server.register.UseCommandLine(MODULOSCOM , unregister=True)
print("Desregistro usando UseCommandLine completado.")

# Ahora eliminamos manualmente la clave del registro
remove_registry_entry(MODULOSCOM._reg_clsid_)

# Verificamos si la clave ha sido eliminada
if not check_registry_clsid(MODULOSCOM._reg_clsid_):
print("Servidor COM desregistrado correctamente.")
else:
print("El servidor COM sigue registrado.")

# Liberar las instancias COM si están en memoria
pythoncom.CoUninitialize()
print("Instancias COM liberadas.")

except Exception as e:
print(f"Error al desregistrar el servidor COM: {e}")
else:
print("Usar 'register' o 'unregister' como argumento.")

desde POWERCOBOL
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Objeto pic x(14) value "MODULOS.COM".
01 ModulosCom object reference COM.
01 NumeroA Pic X(15).
01 NumeroB Pic X(15).
01 Operador Pic X.
01 Resultado Pic X(15).
PROCEDURE DIVISION.
invoke COM "CREATE-OBJECT" using Objeto returning ModulosCom. *> creo el objeto

move "Text" OF CmText3 to NumeroA
move "Text" OF CmText5 to NumeroB
move "Text" OF CmText4 to Operador
invoke ModulosCom "Calculo" using NumeroA NumeroB Operador returning Resultado

move Resultado to "Caption" OF CmStatic6
move Resultado to "Text" OF pasartexto
* INVOKE pow-self "DisplayMessage" USING resultado

set ModulosCom to null

LLAMADO AL NAVEGADOR VIA COM

ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Objeto pic x(14) value "MODULOS.COM".
01 ModulosCom object reference COM.
01 cuit pic x(11).
01 Resultado Pic X(15).
01 Texto pic x(100).
PROCEDURE DIVISION.
invoke COM "CREATE-OBJECT" using Objeto returning ModulosCom. *> creo el objeto
move spaces to texto
move "Text" OF dire to texto
invoke ModulosCom "Navegador" using texto returning Resultado

set ModulosCom to null

Espero que te sea util la información, no hay mucho en la web que nos pueda ayudar.
Suerte.

Kuk
20 de junio de 2025, 12:19
@Jorgeanna, usa los botones de resalto de sintaxis ;)

Muy interesante tu aportación.

Según entiendo, hay que ejecutar primero el código Python que llama al Registro de Windows para agregar la referencia a las funciones definidas en el mismo.
Luego vía COM, PowerCOBOL puede acceder a estas funciones puesto que existen declaradas en el Registro de Windows.
¿Es así?

Jorgeanna
20 de junio de 2025, 15:37
Muy interesante tu aportación.

Según entiendo, hay que ejecutar primero el código Python que llama al Registro de Windows para agregar la referencia a las funciones definidas en el mismo.
Luego vía COM, PowerCOBOL puede acceder a estas funciones puesto que existen declaradas en el Registro de Windows.
¿Es así?


Es correcto el analisis. Desde Cobol es muy simple pasa datos y la funcion en python la ejecuta y devuelve los resultados.
Todo lo que se te ocurra que puedas llegar a utilizar a traves de un script python se puede ejecutar desde nuestro lenguaje y ademas si lo convertimos a exe o dll, se registra una vez cuando se instala la app y luego solo solo se llama desde nuestra app.
Actua como interface entre ambos lenguajes y nos exime de utilizar archivos de texto para comunicar entre ambos lenguajes.
Lo tengo implementado en diversas necesidades para cubrir algunas funciones que no puedo hacer en cobol y es genial ya que esto amplia las posibilidades de no quedarnos estancados en el tiempo.
Como siempre digo, la imaginacion es el limite!!!
saludos cordiales

Eslopes
14 de agosto de 2025, 06:59
Adjunto un video del código que creé para que GNU Cobol ejecute Python, pasando datos de un informe Cobol al LLM y permitiendo hacer preguntas sobre el contenido.

El video (https://www.youtube.com/watch?v=k0vRtKx1xv8) muestra el código en funcionamiento. Todavía estoy evaluando el rendimiento de LLaMa 3 ejecutándose localmente. Mi equipo es un MacBook Pro M3, así que el rendimiento en una estación Windows típica (8 núcleos, 8 GB de RAM) probablemente será deficiente.

Otra posibilidad real es usar un servicio en la nube como Amazon Bedrock. De esta forma, tendríamos acceso a decenas de Foundation Models (FM), con un rendimiento enorme y aptos para producción. El punto es que, usando solo prompt engineering básico, es posible lograr cosas extraordinarias. En el caso del ejemplo del video, estoy pasando un informe generado por un programa COBOL y el LLM interpreta los datos y genera respuestas sobre los mismos, por ejemplo:
(Esta vez cambié el prompt para forzar las respuestas en español.)
---------------------------------------------------------------------------------------------

How can I help you?
Muéstre los 10 clientes más grandes, listando nombre y ventas hasta la fecha actual.

¡Claro! Aquí te presento los 10 mayores clientes según el informe:

1. **CORAL2INDIA FINANCE** con ventas de **57,481.45**
2. **TATA CONSUMER CO.** con ventas de **57,481.45**
3. **CORAL1INDIA FINANCE.** con ventas de **47,481.45**
4. **SENTIALS LOCAL PVT** con ventas de **37,481.45**
5. **ZINTEC PRVIATE LTD** con ventas de **27,481.45**
6. **TATA COFFEE PRIVATE.** con ventas de **27,483.45**
7. **INFO MANGEMENT CO.** con ventas de **17,481.45**
8. **COAL INDIA PVT LTD** con ventas de **17,481.45**
9. **GENERAL SERVICES CO.** con ventas de **11,444.00**
10. **DAUPHIN DEPOSIT BANK** con ventas de **14,099.00**

Espero que esto te ayude. ¡Si necesitas algo más, no dudes en preguntar!
---------------------------------------------------------------------------------------------

¡Las posibilidades son infinitas!]

fastpho
10 de septiembre de 2025, 15:29
✅ *Interpolaridad de Python con PowerCobol*
ℹEjemplo de geolocalizacion usando la api de Nominatim
para procesar enviando direccion para obtener los datos
y genera un archivo .csv

Gracias a @@Jorgeanna,


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ObjetoGenerico pic x(21) value "LocPyCOM.elsCOMObject".
01 URLCom object reference COM.
01 TextoDireccion pic x(100).
01 ResultadoUrl pic x(100).

01 Numero pic s9(9) comp-5.


*>Geolocalizacion
01 ResultadoGeol pic x(100).
01 valorEstado pic x(5).
01 valorLatitud.
03 v-Lat pic x(15).
01 valorLongitud.
03 v-Lon pic x(15).

01 Tiempo pic s9(9) comp-5.
01 Url pic x(512).
01 url-maps pic x(34) value "https://www.google.com/maps/place/".
01 returnvalue pic s9(9) comp-5.
01 lang pic x(3) value "esp".
PROCEDURE DIVISION.
*> Objeto Creo
invoke COM "CREATE-OBJECT" using ObjetoGenerico returning URLCom. *> creo el objeto

if URLCom = NULL
display "ERROR: No se pudo crear objeto URLCom COM"
exit program
else
display "OK: se pudo crear objeto URLCom COM"
end-if.

*> Set Atributo numero cliente
move 530 to Numero.

invoke URLCom "setValue" using Numero returning ResultadoUrl. *>Metodo.
* display ResultadoUrl.

* *> Get Atributo numero cliente
move zeros to Numero.
invoke URLCom "getValue" returning Numero.
display "Retorno getValue:" , Numero.


*> Metodo Geola
move "Text" OF CmText-DIREC to TextoDireccion.
move spaces to ResultadoGeol.
invoke URLCom "CrearLocalizacion" using TextoDireccion returning ResultadoGeol. *>Metodo.
display "ResultadoGeol:" , ResultadoGeol.
unstring ResultadoGeol delimited by "|" into valorEstado valorLatitud valorLongitud
end-unstring.

* CALL "Sleep" WITH STDCALL USING BY VALUE Tiempo.

display "Estado:" , valorEstado.
display "LAtitud:" , v-Lat.
display "LOngitud:" , v-Lon.

*muestro valores
move valorLatitud to "Text" OF CmText-Latitud.

move valorLongitud to "Text" OF CmText-Longitud.

move valorEstado to "Text" OF CmText-ESTADO.


*Muestra Maps

string
url-maps delimited by spaces

valorLatitud delimited by spaces

"," delimited by spaces
valorLongitud delimited by spaces

into Url
end-string.
display Url.
MOVE Url TO "Text" OF CmText-URL.


*Rutina OrdoWebView
* INVOKE OrdoWebView1 "About".
MOVE POW-TRUE TO "Anchor" OF OrdoWebView1.
MOVE "https://www.google.com/" TO "HomeURL" OF OrdoWebView1.
MOVE Url TO "HomeURL" OF OrdoWebView1.

*> Metodo url
move spaces to ResultadoUrl.
move Url to TextoDireccion.
invoke URLCom "url" using TextoDireccion returning ResultadoUrl. *>Metodo.


MOVE 2 to "SearchEngine" OF OrdoWebView1. *>Google.
INVOKE OrdoWebView1 "Init" USING Lang.
move 0 to "MousePointer" OF pow-self.


*final.
set URLCom to NULL.






#Fecha 08-09-2025
#Programa:elsisloc.py
#para ejectuar ambiente desarrollo : python elsisloc.py --register o python elsisloc.py --unregister


# Método 1: Eliminar claves del registro manualmente
#reg delete "HKEY_CLASSES_ROOT\LocPyCOM.elsCOMObject" /f
#reg delete "HKEY_CLASSES_ROOT\LocPyCOM.elsCOMObject.1" /f
#reg delete "HKEY_CLASSES_ROOT\CLSID\{fc6bf508-392e-45e9-bd6e-44943fcb216f}" /f

import pythoncom
import win32com.server.register
from win32com.server.exception import COMException
import ctypes
import csv
import os
import sys
import time
from geopy.geocoders import Nominatim

# Configuración
user_agent = "mi_aplicacion_geolocalizacion_v1"
timeout = 10
max_retries = 3
retry_delay = 1

# Archivo de salida - usar ruta absoluta para evitar problemas con .exe
if getattr(sys, 'frozen', False):
# Si estamos en un ejecutable PyInstaller
base_path = os.path.dirname(sys.executable)
else:
# Si estamos ejecutando desde Python
base_path = os.path.dirname(os.path.abspath(__file__))
output_file = os.path.join(base_path, "coordenadas.csv")

# Geolocalizador (mover a función para evitar problemas de inicialización)
def get_geolocator():
return Nominatim(user_agent=user_agent, timeout=timeout)

class Controller:

_public_methods_ = ['setValue', 'getValue','url','CrearLocalizacion']
_reg_progid_ = "LocPyCOM.elsCOMObject"
_reg_verprogid_ = "LocPyCOM.elsCOMObject.1"
_reg_desc_ = "Python Test COM Servicio"
_reg_class_spec_ = "elsisloc.Controller"
_reg_clsid_ = "{fc6bf508-392e-45e9-bd6e-44943fcb216f}"

def __init__(self):
"""Constructor de la clase"""
print("Servidor COM correctamente")
self.value = 1
# Inicializar el archivo CSV
self.inicializar_archivo_csv()


def inicializar_archivo_csv(self):
"""Inicializa el archivo CSV si no existe"""
try:
if not os.path.exists(output_file):
with open(output_file, "w", newline="", encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["Cliente" , "Dirección", "Latitud", "Longitud", "Estado","Timestamp"])
except Exception as e:
print(f"Error al inicializar CSV: {str(e)}")

def CrearLocalizacion(self, direccion):
"""
Procesa una sola dirección y la geocodifica
Args:
direccion (str): La dirección a geocodificar
Returns:
str: Resultado del proceso o mensaje de error
"""
try:
# Validar que se proporcione la dirección
if not direccion or direccion.strip() == "":
return "ERROR: La dirección no puede estar vacía"

direccion = direccion.strip()
print(f"Procesando dirección: {direccion}")

latitud, longitud = self.geocodificar(direccion)

if latitud and longitud:
resultado = f"Dirección: {direccion}, Latitud: {latitud}, Longitud: {longitud}"
print(resultado)
self.guardar_resultado(direccion, latitud, longitud, "OK")
return f"OK|{latitud}|{longitud}"
else:
error_msg = f"Error al geocodificar la dirección: {direccion}"
print(error_msg)
self.guardar_resultado(direccion, "", "", "ERROR")
return f"ERROR|No se pudo geocodificar la dirección"

except Exception as e:
error_msg = f"ERROR: {str(e)}"
print(error_msg)
return error_msg
def geocodificar(self, direccion):
"""
Geocodifica una dirección con reintentos
"""
geolocator = get_geolocator()

for attempt in range(max_retries):
try:
print(f"Intento {attempt + 1} para: {direccion}")
location = geolocator.geocode(direccion)

if location:
return location.latitude, location.longitude
else:
print(f"No se encontraron resultados para: {direccion}")
return None, None

except Exception as e:
print(f"Error en intento {attempt + 1}: {str(e)}")
if attempt < max_retries - 1:
time.sleep(retry_delay * (attempt + 1)) # Aumentar delay progresivamente
else:
print(f"Falló después de {max_retries} intentos")
return None, None

def guardar_resultado(self, direccion, latitud, longitud, estado):
"""
Guarda el resultado en el archivo CSV
"""
try:
with open(output_file, "a", newline="", encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
nrocliente = self.value
writer.writerow([nrocliente,direccion, latitud, longitud, estado, timestamp])
except Exception as e:
print(f"Error al guardar en CSV: {str(e)}")

def setValue(self, new_value):
"""
Set Numero del cliente
"""
try:
self.value = new_value
return
except Exception as e:
raise COMException(f"Error en el valor enviado: {str(e)}")

def getValue(self):
"""
Get Numero del cliente
"""
try:
return self.value if self.value is not None else "Value not set"
except Exception as e:
raise COMException(f"Error al obtener valor: {str(e)}")

def url(self, Texto):
try:
import webbrowser
webbrowser.open(Texto)
return Texto

except Exception as e:
raise COMException(f"Error navegador: {str(e)}")

def show_message(message, title="Informacion"):
ctypes.windll.user32.MessageBoxW(0, message, title, 0x40)

def DllRegisterServer(silent=False):
try:
pythoncom.CoInitialize()
win32com.server.register.UseCommandLine(Controller )
message = "Objeto registrado exitosamente."
except Exception as e:
message = f"Error al registrar el objeto: {e}"
finally:
pythoncom.CoUninitialize()
if not silent:
show_message(message, "Objeto registrado")

def DllUnregisterServer(silent=False):
try:
pythoncom.CoInitialize()
win32com.server.register.UnregisterServer(
Controller._reg_clsid_,
Controller._reg_progid_
)
message = "Objeto anulado exitosamente."
except Exception as e:
message = f"Error al anular el registro del objeto: {e}"
finally:
pythoncom.CoUninitialize()
if not silent:
show_message(message, "Objeto no registrado")

if __name__ == '__main__':
import sys
silent = False
if len(sys.argv) > 1:
if len(sys.argv) > 2:
if sys.argv[2] == '--silent':
silent = True
if sys.argv[1] == '--register':
DllRegisterServer(silent)
elif sys.argv[1] == '--unregister':
DllUnregisterServer(silent)
elif "/Automate" in sys.argv:
import win32com.server.localserver
win32com.server.localserver.serve([Controller._reg_clsid_])
else:
show_message("Use:\nelsisloc.exe --register\nelsisloc.exe --unregister\n--silent: Silent mode", "Ayuda")

Saludos ...

Jorgeanna
11 de septiembre de 2025, 01:44
Muy bueno, felicitaciones por implementar algo que en el futuro le encontraras multiples uso.

Ajusta el siguiente setup.py a tus necesidades, descarga python 2.7 e instala py2exe, deberas correr: python setup.py py2exe
esto te generara una carpeta dist y en ella vas a encontrar su script xxxx.exe y xxx.dll, te recomiendo por rapidez trabajar con los dll y llamar al mismo como cualquier otra llamada a un objeto com.
Te digo descargues y pruebes con python 2.7 porque el setup.py que te paso esta para py2exe y se complica bastante, por lo menos a mi, ejecutarlo en veriones de la 3.11 en adelante.

Con perseverancia y trabajo todo se logra, adelante!!!.

script: setup.ini
Se puede convertir el ejemplo que puse anteriormente y utilizarlo desde powercobol

# Created on 02/2021
# @author: fastpho

from distutils.core import setup
import py2exe
import sys
sys.argv.append('py2exe')
sys.path.append('C:\\WINDOWS\\WinSxS\\x86_microsof t.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_50 90ab56bcba71c2')

#Fuente: https://www.iteramos.com/pregunta/27742/py2exe-es-incapaz-de-generar-un-ejecutable

setup(
# Nombre de la Clase
name = "MODULOSCOM",
# nombre del script
com_server = ["ModulosCOM"],
)

fastpho
11 de septiembre de 2025, 18:53
Hola @Jorgeanna , el problema que tuve no fue con python en desarrollo
por que me corria perfectamente tengo varias implementaciones que hice
en python , estoy usando la version 3.13 de 64 bits , perdi mucho
tiempo para poder compilarlo a .exe y poder correrlo sin el ide
de python , logre despues de renegar tanto :loco: y perder mucho tiempo
por que no hay mucha informacion , inclusive las ia tampoco fueron
de gran ayuda , finalmente con pyinstaller logra hacerlo funcionar a .exe

Todavia tengo que aprender ... :cool:, pero la idea es seguir estudiando
python , y poder resolver algunos temas que son muy sencillos , con
un par de api's o librerias resolverlo.

Muchas gracias nuevamente por tu aporte :beber:

Saludos....

Kuk
11 de septiembre de 2025, 19:47
@fastpho, lo mismo me he perdido algo pero... para qué quieres generar un EXE con código Python? :piensa::losiento:

Claro está que por poder se pueden hacer muchas cosas, pero es que si quieres un EXE, por qué aprender Python que es un lenguaje de scripting (interpretado), por defecto sin opciones para generar binarios (y menos nativos).

fastpho
11 de septiembre de 2025, 21:31
@kuk , El tema es la distribucion , por eso convierto .py a . exe , sin tener dependencias.
Me encanto python es muy facil , pocas lineas , etc .....:cool:

Saludos...

Fito
11 de septiembre de 2025, 23:22
Hola Amigos:

Coincido con Osvaldo en Python, es muy sencillo, y hay mucho código dando vueltas para hacer lo que quieras, de manera bastante sencilla. Al integrarlo por COM en PowerCobol, nos corre la línea de los límites mucho más allá.

Saludos.

Fito...

Jorgeanna
12 de septiembre de 2025, 18:50
hola fastpho!!
Veo que estas utilizando python 64 bits por lo que dices, convertido a exe mediante Pyinstaller

1. Por si ayuda en algo a alguien que esta empezando a probar, para registrar un servidorCOM la forma correcta de hacerlo es en modo adminitrador.

2. Para que esta comunicación funcione, el cliente (PowerCOBOL) carga al servidor (Python COM) dentro de su propio espacio de trabajo. La regla fundamental es que un programa de 32 bits solo puede cargar componentes de 32 bits.

Si intentaras usar Python de 64 bits como dices, tu aplicación de PowerCOBOL de 32 bits simplemente no podría "ver" ni cargar el servidor COM de 64 bits. Te daría un error, típicamente diciendo que "la clase no está registrada" o que "no se puede crear el objeto", porque para él, ese componente de 64 bits es incompatible.

No entiendo como lo haces funcionar entonces, salvo que estes llamando a un exe, ejecute su rutina generando un archivo de texto con la respuesta y luego desde powerCOBOL leer ese archivo y mostrar la respuesta. Pero aun asi lo que no me cierra de este analisis, es que para generar la respuesta tiene que haber recibido la orden correcta????

Si esto fuera mas o menos asi, estarias desaprovechando el retorno de los datos de python y su aplicacion directa en en tu programa en powerCOBOL.
Pregungo porque es interesante y no se me dio por probar con python 64 bits, entendiendo que no seria logico recibir los datos usando esa tecnologia.
Cualquier avance que hayas realizado, todo sirve y ampliamos conocimientos.
Saludos cordiales.

fastpho
15 de septiembre de 2025, 14:40
Hola @Jorgeanna , entiendo lo que planteas , la version que tengo instalada es 3.13.6(64-bit) adjunto imagen ,
el ejemplo que pase es tal cual , por que funciona me parece que la clave es el archivo elsloc_file.spec (*'pywin32_system32*)


* como administrador (cmd) corro esto --> : python elsisloc.py --register
* Convertir de .py .exe
#_reg_class_spec_ = "elsisloc.Controller" esta linea la tengo que comentar para que funcione python elsisloc.py --register
_reg_class_spec_ = "elsisloc.Controller" esta linea la tengo que descomentar para que funcione cuando uso pyinstaller

desde cmd : #para convertir a .exe : pyinstaller elsloc_file.spec


# -*- mode: python ; coding: utf-8 -*-

import os
import sys
import time
import win32com

a = Analysis(
['elsisloc.py'],
pathex=[],
binaries=[
(os.path.join(sys.prefix, 'Lib', 'site-packages', 'pywin32_system32', f'pythoncom{sys.version_info.major}{sys.version_in fo.minor}.dll'), '.'),
(os.path.join(sys.prefix, 'Lib', 'site-packages', 'pywin32_system32', f'pywintypes{sys.version_info.major}{sys.version_i nfo.minor}.dll'), '.')
],
datas=[('elsisloc.py', '.')],
hiddenimports=[
'pythoncom',
'win32com',
'win32com.server',
'win32com.server.register',
'win32com.server.localserver',
'pywintypes',
'win32timezone',
'ctypes',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='elsisloc',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)



y funciona perfectamente en windows 10 de 64 bits , no probado windows 11, meti pruebas en windows 7 de 64 y me saco peinado con muchos erroress
osea no funcione en windows 7 , mi version de Pwc es la 5 ,
si miras el ejemplo veras que es todo por object reference COM. (*COM) , no hay .txt , que esa era la idea incial que planteo
@Fito , si devuelve un .csv con lo solicitado


Saludos ...

Jorgeanna
16 de septiembre de 2025, 05:29
hola @fastpho:

Felicitaciones, he probado el script que pasaste y quedo gratamente sorprendido, lo estoy corriendo desde un cliente 32 bits, como asi tambien desde un cliente 64 bits y tambien funciona, no entiendo como puede ser, se me quemaron los manuales, pero FUNCIONA y no deberiamos entonces preocuparnos por el entorno en que se desarrolle el servidorCOM.

Ademas lo he probado en windows 11 y anda perfectamente.

Creo que la magia esta en la configuracion del archivo spec, incorporando las librerias en el mismo, soluciona los problemas de empaquetado de pyinstaller, que no era suficiente con por ejemplo: pyinstaller --onefile --windowed --hidden-import=win32timezone elsisloc.py ya que cada error habia que incorporar las librerias que no detectaba el compilador, IMPECABLE LO TUYO y UN APORTE SIGNIFICATIVO.

Respecto del archivo de texto, hice una mala lectura, vi que guardaba la consulta en un archivo csv y asumi que luego lo leian y no era asi, lo genera, no se el objetivo pero la informacion es tomada del propio return.

Archivo generado al momento de la consulta.
1,"monumental, buenos aires, argentina",-34.5452932,-58.4497385,OK,2025-09-15 23:58:44
1,"bombonera, buenos aires, argentina",-34.6355171,-58.3649163,OK,2025-09-15 23:59:33

Veo que el tema ha tenido muchas lecturas, no veo reportes de si lo estan utilizando o solo leen los post, pero si quieren probar el servidorCOM generado y presentado gentilmente por @fastpho, le dejo un script en vbs para que puedan probar en forma rapida el mismo, y vean la magia de trabajar desde otro lenguaje y utilizar el mundo python:

abre navegador en la ubicacion especificada
64 bits
wscript.exe C:\PyPracticas\fastpro\ localizar_con_mapa.vbs
32 bits
C:\Windows\SysWOW64\wscript.exe C:\PyPracticas\fastpro\ localizar_con_mapa.vbs

Obs. cambiar la ubicacion del script.


' ================================================== ===============
' servidorCOM autor: @fastpho:
' Script: localizar_con_mapa.vbs
' Propósito: Probar el objeto COM, geocodificar una dirección
' y abrir la ubicación resultante en un mapa.
' ================================================== ===============

' --- 1. Declaración de variables ---
Dim objGeo, direccion, resultado, partesResultado
Dim estado, latitud, longitud, mensaje
Dim askToOpenMap, mapURL, shell

' --- 2. Solicitar dirección al usuario ---
direccion = InputBox("Introduce la direccion a geocodificar:", "Geolocalizacion")

If direccion = "" Then
MsgBox "No se ingreso ninguna direccion. El script finalizara.", vbExclamation, "Sin direccion"
WScript.Quit
End If

' --- 3. Creación del Objeto COM ---
On Error Resume Next
Set objGeo = CreateObject("LocPyCOM.elsCOMObject")
On Error GoTo 0

' --- 4. Verificación y uso del objeto ---
If objGeo Is Nothing Then
MsgBox "ERROR: No se pudo crear el objeto COM 'LocPyCOM.elsCOMObject'." & vbCrLf & vbCrLf & _
"Por favor, asegurate de haber registrado el servidor COM.", vbCritical, "Error de Objeto"
Else
' Llamamos al método para obtener las coordenadas
resultado = objGeo.CrearLocalizacion(direccion)

' Procesamos la respuesta que viene separada por "|"
partesResultado = Split(resultado, "|")
estado = partesResultado(0)

If UCase(estado) = "OK" Then
latitud = partesResultado(1)
longitud = partesResultado(2)

' Mostramos el mensaje con el resultado exitoso
mensaje = "Geocodificacion Exitosa" & vbCrLf & vbCrLf & _
"Latitud: " & latitud & vbCrLf & _
"Longitud: " & longitud
MsgBox mensaje, vbInformation, "Resultado"

' Preguntamos al usuario si desea abrir el mapa
askToOpenMap = MsgBox("¿Deseas abrir esta ubicacion en un mapa?", vbYesNo + vbQuestion, "Abrir Mapa")

If askToOpenMap = vbYes Then
' Construye una URL de Google Maps moderna y confiable
mapURL = "https://www.google.com/maps/search/?api=1&query=" & latitud & "," & longitud

' Abrimos la URL en el navegador por defecto
Set shell = CreateObject("WScript.Shell")
shell.Run mapURL
Set shell = Nothing
End If
Else
' Mostramos el mensaje de error devuelto por el objeto COM
mensaje = "La geocodificación fallo." & vbCrLf & vbCrLf & _
"Mensaje del servidor: " & partesResultado(1)
MsgBox mensaje, vbExclamation, "Resultado con Error"
End If

' Liberamos el objeto de la memoria
Set objGeo = Nothing
End If


Saludos cordiales

Por favor, usar los resaltes de sintaxis para que quede "elegante" el post

Paulo
1 de octubre de 2025, 18:30
Olá a todos.
Este é um excelente tema, realmente permite ultrapassar algumas limitações do Cobol.

Obrigado a todos os que aqui deram estas informações.

Estive a testar e realmente funciona (estou a usar Python 3.13.7 (64bits).
Também já converti um script .py para. exe
A minha duvida é: como se usa o .exe gerado pelo py2exe no cobol ?
Já tentei chamar com argumentos, mas não consegui resulltados...

Podem ajudar ?
Gracias

Jorgeanna
3 de octubre de 2025, 01:17
Hola, especificamente no se tus dudas, pero por la version de python que estas trabajando deberias empaquetar la app con pyinstaller, con una serie de parametros para que incluya todas las librerias en un solo ejecutable.
Dicho esto te paso un resumen que armo la IA en funcion de parametros que le pase y creo queda bastante claro para entender el uso de esta herramienta:

Diferencias Clave entre Servidores COM: DLL (In-Process) vs. EXE (Out-of-Process)

1. ¿Qué es un Servidor COM?
Un servidor COM es un componente de software que permite que diferentes aplicaciones se comuniquen entre sí. Por ejemplo, una aplicación antigua desarrollada en Visual Basic 6, PowerCOBOL puede utilizar funcionalidades modernas de Python a través de un objeto COM. La forma en que este servidor se ejecuta determina su rendimiento y sus características.

2. Tipos de Servidores COM y sus Diferencias Fundamentales. Existen dos maneras principales de implementar un servidor COM:

a) Servidor COM In-Process (.dll)
¿Cómo funciona? El servidor se carga directamente en el mismo espacio de memoria de la aplicación que lo está utilizando (la aplicación cliente). No se crea un proceso nuevo.

Ventaja Principal: Velocidad. La comunicación es extremadamente rápida porque es una llamada directa a una función dentro del mismo proceso. No hay sobrecarga por la comunicación entre procesos distintos.

b) Servidor COM Out-of-Process (.exe)
¿Cómo funciona? El servidor se ejecuta en su propio proceso, separado de la aplicación cliente. Cada vez que la aplicación cliente necesita algo, el sistema operativo debe gestionar la comunicación entre ambos procesos.

Desventaja Principal: Velocidad. Es inherentemente más lento que un servidor in-process. Aunque la diferencia puede ser de milisegundos, en operaciones muy frecuentes o intensivas puede ser notable.

Ventaja Principal: Aislamiento y Estabilidad. Si el servidor COM falla o se bloquea, no afecta a la aplicación cliente, que puede seguir funcionando.

3. Aplicación en el Mundo Python
La elección entre un .dll y un .exe en Python está fuertemente ligada a la versión del lenguaje que se utilice.

Python 2.7: La Vía Rápida con DLLs

Utilizando la herramienta py2exe (en su versión clásica), es posible empaquetar un servidor COM como una DLL in-process.

Ideal para: Sistemas que requieren máxima velocidad e integración directa, como aplicaciones de escritorio en VB6, Delphi o PowerCOBOL que necesitan respuestas instantáneas.

Limitación: Estarás atado a Python 2.7 y no podrás utilizar las bibliotecas más modernas que solo son compatibles con Python 3 (como versiones recientes de Pandas, TensorFlow, etc.).

Python 3.x: Modernidad y Flexibilidad con EXEs

La versión moderna de py2exe para Python 3 no soporta la creación de DLLs COM. Sin embargo, se pueden crear servidores COM out-of-process (.exe) utilizando la librería pywin32.

Ideal para: Proyectos que necesitan acceder a las últimas bibliotecas de Python para ciencia de datos, inteligencia artificial, análisis de datos, etc. La pequeña pérdida de rendimiento es un compromiso aceptable a cambio de la potencia y el soporte de las nuevas tecnologías.

Conclusión: Si necesitas librerías modernas, esta es la única vía.

4. Flujo de Trabajo Recomendado para el Desarrollo
No es necesario empaquetar el servidor en un .dll o .exe desde el primer día. El proceso recomendado es:

Desarrollo y Pruebas (usando el .py): Durante la fase de programación, puedes registrar directamente tu archivo .py como un servidor COM en el sistema. Esto te permite probar la comunicación con la aplicación cliente de forma rápida y sencilla sin necesidad de compilar nada.

Empaquetado para Distribución (creando el .dll o .exe): Una vez que la lógica del servidor está validada y funciona correctamente, el siguiente paso es empaquetarlo. Esto permite distribuir e instalar el servidor en máquinas cliente sin necesidad de tener Python instalado en ellas.

Si decides probar un ejemplo simple con py2exe recurda bajar la version de python 2.7.18 en su version 32 bits, ya que powerCOBOL es de 32 bits y como trabaja en el mismo espacio de memoria debe ser ambos de 32 bits.

Si necesitas algo en concreto, contacta por privado o espera que algunos foreros dijeron que publicarian novedades cuando las tengan.

Mucha Suerte, no dejes de intentarlo.