#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")