Page 1 of 2

Hix - Funciones

Posted: Wed Jan 07, 2026 8:51 am
by hmpaquito

Buenos días,

Buscando alguna funcion para ejecutar un ejecutable, veo que la unica disponible....
Me parece que en hix.exe faltan las funciones de manejo de la tabla de simbolos.
En realidad queria saber que funciones tiene disponibles hix.exe, más allá de las que interfacean con la web y que están en la lista https://github.com/carles9000/hix/wiki/Functions

¿ Se podría hacer una lista de las funciones disponibles o mejor no despertar a la fiera ?

Salu2


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 9:08 am
by Antonio Linares

Querido Paco,

symbols.prg

Code: Select all | Expand

function Main()

local n, lAll := .F., lCode := .F., lNonCode := .F. 
local cHtml := ""
local hPost := UPost()
local cFilter := "ALL"

if hb_HHasKey( hPost, "filter" )
   cFilter := hPost[ "filter" ]
endif

do case
   case cFilter == "CODE"
        lCode := .T.
   case cFilter == "NONCODE"
        lNonCode := .T.
   otherwise
        lAll := .T.
endcase

for n = __DynsCount() to 1 step -1
    if lAll .or. lCode 
        if __DynsIsFun( n )
           cHtml += '<p style="color:green; margin: 2px 0;">' + AllTrim( Str( __DynsCount() - n + 1 ) ) + ". " + __DynsGetName( n ) + "</p>" + hb_EoL()
        endif
    endif
    if lAll .or. lNonCode
        if ! __DynsIsFun( n )
           cHtml += '<p style="color:blue; margin: 2px 0;">' + AllTrim( Str( __DynsCount() - n + 1 ) ) + ". " + __DynsGetName( n ) + "</p>" + hb_EoL()
        endif
    endif
next

return View( "symbols", "cContent", cHtml )

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

function View( cName, cParamName, uParamValue )

   local cData
   local cViewPath := "./views/" + cName + ".view"

   if File( cViewPath )
      cData = MemoRead( cViewPath )
      while ReplaceBlocks( @cData, "{{", "}}", cParamName, uParamValue )
      end
   else
      cData = "<h2>" + cName + " not found!</h2>" 
   endif    

return cData

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

function ReplaceBlocks( cCode, cStartBlock, cEndBlock, cParamName, uParamValue )

   local nStart, nEnd, cBlock, nQ1, nQ2
   local lReplaced := .F.
   
while ( nStart := At( cStartBlock, cCode ) ) != 0 .and. ; ( nEnd := At( cEndBlock, cCode ) ) != 0 cBlock = SubStr( cCode, nStart + Len( cStartBlock ), nEnd - nStart - Len( cEndBlock ) )
// Keep it simple for this example, only support variable replacement or View call if "View" $ cBlock // Manual parsing to avoid macro compiler issues with function visibility: View("name") nQ1 := At( '"', cBlock ) nQ2 := RAt( '"', cBlock ) if nQ1 > 0 .and. nQ2 > nQ1 cCode = SubStr( cCode, 1, nStart - 1 ) + ; View( SubStr( cBlock, nQ1 + 1, nQ2 - nQ1 - 1 ) ) + ; SubStr( cCode, nEnd + Len( cEndBlock ) ) else cCode = SubStr( cCode, 1, nStart - 1 ) + ; "" + ; SubStr( cCode, nEnd + Len( cEndBlock ) ) endif else // Simple variable replacement if !Empty( cParamName ) .and. AllTrim( cBlock ) == cParamName cCode = SubStr( cCode, 1, nStart - 1 ) + ; ValToChar( uParamValue ) + ; SubStr( cCode, nEnd + Len( cEndBlock ) ) else // Unknown block, just remove brackets cCode = SubStr( cCode, 1, nStart - 1 ) + ; "" + ; SubStr( cCode, nEnd + Len( cEndBlock ) ) endif endif lReplaced = .T. end
return lReplaced //----------------------------------------------------------------------------// function ValToChar( u ) local cType := ValType( u ) local cResult do case case cType == "C" cResult = u case cType == "N" cResult = AllTrim( Str( u ) ) otherwise cResult = "" endcase return cResult

symbols.view

Code: Select all | Expand

<!DOCTYPE html>
<html>
<head>
  <title>System Symbols</title>
  {{View("style")}}
</head>
<body>
  <div class="container" style="display: flex; flex-direction: column; height: 90vh; padding-bottom: 20px;">
    <h1>System Symbols</h1>
    <form method="POST" action="symbols.prg" style="margin-bottom: 15px; text-align: center; flex-shrink: 0;">
        <button type="submit" name="filter" value="ALL" class="btn" style="width: auto; margin: 0 5px; background: #667eea;">All</button>
        <button type="submit" name="filter" value="CODE" class="btn" style="width: auto; margin: 0 5px; background: green;">Functions</button>
        <button type="submit" name="filter" value="NONCODE" class="btn" style="width: auto; margin: 0 5px; background: blue;">Non-Functions</button>
    </form>
    <div style="text-align: left; flex: 1; overflow-y: auto; border: 1px solid #eee; padding: 10px; border-radius: 4px;">
        {{cContent}}
    </div>
  </div>
</body>
</html>

Re: Hix - Funciones

Posted: Wed Jan 07, 2026 9:12 am
by Antonio Linares

Image


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 10:35 am
by hmpaquito

Gracias Antonio, en cuanto saque hueco lo pruebo.
Me equivoqué y si habia acceso, como no podia ser de otra forma, a la tabla de simbolos.
Gracias de nuevo


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 3:36 pm
by hmpaquito

Bien, la lista de funciones me sirve para comprobar que efectivamente hb_ProcessRun() y hb_Run() no están enlazadas en Hix.exe y por tanto no se puede ejecutar un ejecutable, al menos de la manera habitual.


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 3:40 pm
by Antonio Linares

Lo mas simple es editar el EXE (view desde el mismo Total Commander) y buscar por el nombre del símbolo :idea:


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 3:43 pm
by Antonio Linares

Tienes WAPI_SHELLEXECUTE() :wink:


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 4:01 pm
by hmpaquito

La que más control da es hb_processRun() pero voy a probar wapi_shellexecute() que igual me es suficiente

hb_processRun() - Ejecución de procesos avanzada
Función más flexible para ejecutar procesos con control de entrada/salida:

Code: Select all | Expand

Result := hb_processRun("mi_programa.exe", cStdIn, @cStdOut, @cStdErr, lAsync)

Re: Hix - Funciones

Posted: Wed Jan 07, 2026 4:31 pm
by Otto

Hello,
Yes, this is exactly the topic I’ve been working on over the last days.

For me this is mainly a design question, not a missing function problem.

In a web context, long-running jobs simply don’t belong inside the web server process.
Whether it’s Hix, PHP, or any other web runtime: blocking calls, process execution with I/O, or long database work will always clash with request/response handling.

My conclusion so far:

short, reactive logic → web layer (Hix / PHP / JS)

long-running or stateful jobs → external service process

Node.js, Python or even a standalone Harbour EXE

communication via HTTP or WebSocket

This keeps the web layer responsive and avoids timeouts, while still allowing full control over longer jobs.

So in my view, Hix behaving this way actually confirms a clean separation of concerns, rather than being a limitation.

Saludos
Otto


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 5:15 pm
by Bayron

Hi Otto,,,,, been following your posts,,,, very interesting to me,,,, sorry i had no comments so far, but I'm glad you are making all this extensive investigation....

Just something I want to share with you, is that HIX model works in a different way than the one you exposed, as i understand it.....

HIX->HTML->AJAX->JS

HIX becomes "PHP",
JS can make an events listener and communicate with HIX, via AJAX using Sockets...

Since HIX is the server, then no PHP to access, unless you create a php api on another server,,,, then you will be going in circles, creating a layer on top of several layers == Prone to multi-failures,,,, and extensive knowledge of multiple platforms....

HIX becoming PHP is a gigantic improvement, so you do not have to learn PHP,,, but you still have to be an expert on Html, Css, Java Script, Ajax, etc..., and without using an Ai, that will be impossible for the regular FiveWinner..., so if we see it the long way,,,, is caving in the use of Fivewin and only using Harbour semantic language...


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 6:49 pm
by Otto

Thanks Bayron for sharing your perspective and for following the discussion.
I appreciate your input and the time you took to explain how you see the Hix model.
My intention was not to challenge Hix itself, but simply to clarify the data flow and the separation of responsibilities in the architecture I’m proposing.

The model is exactly this – and nothing else:

Browser / UI
↓
Request (HTTP or WebSocket)
↓
lightweight web layer (Hix)
↓
Harbour microservice (EXE)

Important clarifications

Hix remains the web server
routing
request/response handling
optional WebSocket upgrade
no long-running jobs

The Harbour microservice is a separate process
standalone EXE
stateful
blocking operations allowed
controlled lifecycle
clearly defined responsibility

Best regards,
Otto


Re: Hix - Funciones

Posted: Wed Jan 07, 2026 11:23 pm
by Bayron

Hi Otto,,, our conversation was more about microservices, but HIX is absolutely very powerful,,,, it can create microservices as you say,,,, once the sql libraries are added to it,,,, and the multi-thread from harbour,,, you can have something as strong as apache,,,, here is a sample,,,, with persistent and transient microservices....

I love that HIX is and will serve the community,,, I even donated to the HIX event, even when i knew I wasn't going to be able to assist... I also buy Fivewin from time to time, not because i use it, but because i love it, since i saw it in compuserve magazine.... and I would love to see HIX and Fivewin growing along Harbour and xHarbour,,,, we all are working to make sure xBase coding doesn't die...

Image

Code: Select all | Expand

//backend_persistent.prg
// HIX Backend - Persistent Service
// Uses a simple JSON file to simulate persistent state across requests,
// bypassing thread/process isolation issues.

#pragma -w0
#pragma -es0

FUNCTION Main()
    LOCAL hState := {=>}
    LOCAL cStateFile := "server_state.json"
    LOCAL cJson_In, cJson_Out
    LOCAL hResponse := {=>}

// 1. LOAD STATE (Persistence Layer)
IF File( cStateFile )
cJson_In := MemoRead( cStateFile )
hState   := hb_jsonDecode( cJson_In )
ELSE
hState[ "hits" ]       := 0
hState[ "start_time" ] := Time()
ENDIF

// 2. MODIFY STATE
hState[ "hits" ] := hState[ "hits" ] + 1

// 3. SAVE STATE
hb_MemoWrit( cStateFile, hb_jsonEncode( hState ) )

// 4. PREPARE RESPONSE
hResponse[ "type" ]         := "PERSISTENT"
hResponse[ "status" ]       := "ok"
hResponse[ "hits" ]         := hState[ "hits" ]
hResponse[ "server_start" ] := hState[ "start_time" ]
hResponse[ "message" ]      := "State Updated"

?? hb_jsonEncode( hResponse )

RETURN ""

Code: Select all | Expand

//backend_transient.prg

// HIX Backend - Transient Service
// Stateless microservice. Does not read or write the shared state file.

#pragma -w0
#pragma -es0

FUNCTION Main()
    LOCAL hResponse := {=>}
   
// 1. DO WORK (Stateless) hResponse[ "type" ] := "TRANSIENT" hResponse[ "status" ] := "ok" hResponse[ "server_now" ] := Time() hResponse[ "message" ] := "Just a quick calculation" // We do NOT return 'hits' because we don't know them and don't care. ?? hb_jsonEncode( hResponse ) RETURN ""

Code: Select all | Expand

//client.prg

// HIX Client Logic (Server-Side)
// Uses a FUNCTIONAL approach instead of CLASS to avoid HRB syntax issues.
// Accessed via http://localhost:8080/client.prg

// Include HIX header just in case, though we rely on pure functions
#include "c:\xampp2025\htdocs\webx\hix\hix.ch"

FUNCTION Main()
    LOCAL hPage := THtml_New()
   
THtml_SetTitle( hPage, "HIX Microservice Client" ) THtml_CSS( hPage, "body { font-family: 'Segoe UI', sans-serif; background: #222; color: #eee; text-align: center; padding: 50px; }" ) THtml_CSS( hPage, "button { padding: 15px 30px; font-size: 18px; margin: 20px; cursor: pointer; border: none; border-radius: 4px; transition: transform 0.1s; }" ) THtml_CSS( hPage, ".btn-p { background: #d81b60; color: white; }" ) // Pink for Persistent THtml_CSS( hPage, ".btn-t { background: #00bcd4; color: white; }" ) // Cyan for Transient THtml_CSS( hPage, "button:active { transform: scale(0.95); }" ) THtml_CSS( hPage, "#result { margin-top: 20px; padding: 20px; border: 1px solid #444; background: #333; min-height: 100px; }" ) THtml_AddContent( hPage, "<h1>HIX Microservice Demo</h1>" ) THtml_AddContent( hPage, "<p>Select a Thread Model:</p>" ) // Two distinct buttons calling different endpoints THtml_AddButton( hPage, "Persistent Call", "callService('backend_persistent.prg')", "btn-p" ) THtml_AddButton( hPage, "Transient Call", "callService('backend_transient.prg')", "btn-t" ) THtml_AddContent( hPage, "<div id='result'>Ready...</div>" ) // JS Logic - Corrected JSON escaping THtml_AddScript( hPage, ; "async function callService( endpoint ) { " + ; " const resDiv = document.getElementById('result'); " + ; " resDiv.innerHTML = 'Executing ' + endpoint + '...'; " + ; " try { " + ; " const resp = await fetch(endpoint + '?_=' + Date.now()); " + ; " let text = await resp.text(); " + ; " text = text.replace('NIL', '').trim(); " + ; " const data = JSON.parse(text); " + ; " let html = ''; " + ; " html += '<h3 style=\x22color:' + (data.type==='PERSISTENT'?'#f06292':'#4dd0e1') + '\x22>' + data.type + ' RESPONSE</h3>'; " + ; " html += '<b>Message:</b> ' + data.message + '<br>'; " + ; " if(data.hits) html += '<b>Total Hits (Persistent):</b> ' + data.hits + '<br>'; " + ; " if(data.server_start) html += '<b>Server Started:</b> ' + data.server_start + '<br>'; " + ; " if(data.server_now) html += '<b>Current Time:</b> ' + data.server_now + '<br>'; " + ; " resDiv.innerHTML = html; " + ; " } catch(e) { " + ; " resDiv.innerHTML = 'Error: ' + e + '<br><small>Raw: ' + (typeof text !== 'undefined' ? text : 'Network Error') + '</small>'; " + ; " } " + ; "}" ) ?? THtml_GetHtml( hPage ) RETURN "" // -------------------------------------------------------------------------- // PSEUDO-CLASS THtml (Using Hash) // -------------------------------------------------------------------------- FUNCTION THtml_New() LOCAL hObj := {=>} hObj[ "title" ] := "HIX Page" hObj[ "head" ] := "" hObj[ "body" ] := "" hObj[ "script" ] := "" RETURN hObj FUNCTION THtml_SetTitle( hObj, cText ) hObj[ "title" ] := cText RETURN NIL FUNCTION THtml_CSS( hObj, cRules ) hObj[ "head" ] += "<style>" + cRules + "</style>" + Chr(13)+Chr(10) RETURN NIL FUNCTION THtml_AddContent( hObj, cHtml ) hObj[ "body" ] += cHtml + Chr(13)+Chr(10) RETURN NIL FUNCTION THtml_AddButton( hObj, cLabel, cAction, cClass ) LOCAL cCls := "" IF ValType(cClass) == "C" ; cCls := " class='" + cClass + "'" ; ENDIF hObj[ "body" ] += '<button' + cCls + ' onclick="' + cAction + '">' + cLabel + '</button>' + Chr(13)+Chr(10) RETURN NIL FUNCTION THtml_AddScript( hObj, cJs ) hObj[ "script" ] += cJs + Chr(13)+Chr(10) RETURN NIL FUNCTION THtml_GetHtml( hObj ) LOCAL cHtml := "" cHtml += "<!DOCTYPE html>" + Chr(13)+Chr(10) cHtml += "<html>" + Chr(13)+Chr(10) cHtml += "<head>" + Chr(13)+Chr(10) cHtml += " <meta charset='UTF-8'>" + Chr(13)+Chr(10) cHtml += hObj["head"] cHtml += " <title>" + hObj["title"] + "</title>" + Chr(13)+Chr(10) cHtml += "</head>" + Chr(13)+Chr(10) cHtml += "<body>" + Chr(13)+Chr(10) cHtml += hObj["body"] cHtml += " <script>" + Chr(13)+Chr(10) cHtml += hObj["script"] cHtml += " </script>" + Chr(13)+Chr(10) cHtml += "</body>" + Chr(13)+Chr(10) cHtml += "</html>" RETURN cHtml

You can have multi-threads, instead of separate .exe files, make your code for a persistent database, so you dont have to wait 1 minute for it to load,,,, Harbour is very powerful...

I'm not challenging your approach either,,,, but multiple .exe, is a problem,,,, which one is compiled?, which one is not?,,, instead of a single point of source.... Apache is a single .exe serving billions of microservices,,,, Harbour is as good, or we will soon find out...


Re: Hix - Funciones

Posted: Thu Jan 08, 2026 12:11 am
by Otto

Thanks Bayron for sharing the example and for your continued support of Hix and FiveWin.
I think we actually agree on most fundamentals. The difference is mainly how we look at the workflow and responsibilities, not at Harbour’s capabilities.

To make this clearer, I’d like to put the two approaches side by side.

Hix-internal workflow (as in your example)
Browser
→ HTTP request
→ Hix executes PRG
→ optional file-based state (JSON)
→ immediate response to UI

In this model:

logic runs inside the web request
persistence is simulated via files
there is no job lifecycle beyond the request
the UI always drives execution

This works well as your code shows and clearly shows what Hix can do.

Our workflow (Hix + Harbour desktop program)
Browser / UI
→ Request to Hix
→ Hix triggers Harbour desktop EXE (ShellExecute + unique job id)
→ Harbour program runs independently
→ writes result/status (JSON or file)
→ UI fetches or polls the result when it is ready

Here:

Hix stays lightweight and reactive
long or blocking work runs outside the web process
state belongs to the job, not to the request
lifecycle, logging, recovery and cleanup are explicit

This is not about adding layers, but about separating roles early.

About Node.js
The only reason I mentioned Node.js earlier is that it is optional and portable, not because it is required.
A setup like:
Harbour (worker)
↔ WebSocket
↔ Node.js (SQL adapter)
↔ SQL database

is simply one interesting option, especially for SQL access:
no SQL libraries inside Harbour
no additional DLL complexity
clean isolation and well-maintained drivers

But to be very clear:
Node.js is not mandatory at all.

Hix can directly trigger and communicate with an existing Harbour desktop program.
No PHP, no additional framework, no extra runtime is required.

The core concern

What worries me from a product and long-term maintenance perspective is that once we start adding:

SQL libraries
threading
more dependencies
directly into the Hix process, we slowly turn a clean web layer into a hard-to-maintain monolith.

My intention is not to limit Hix, but to protect it from becoming overloaded with responsibilities.

Best regards,
Otto


Re: Hix - Funciones

Posted: Mon Jan 19, 2026 11:27 am
by hmpaquito
Antonio Linares wrote: Wed Jan 07, 2026 3:43 pm

Tienes WAPI_SHELLEXECUTE() :wink:

Sólo quería decir que he estado usando wapi_ShellExecute() hasta hace poco y me ha dado muchos quebradores de cabeza en forma de cuelgues inexplicables. Desde que uso hb_ProcessRun() todo va bien. Así que desaconsejo el uso de aquella.


Re: Hix - Funciones

Posted: Tue Jan 20, 2026 12:55 am
by russimicro

Buena noche

Solo para analizar...

<!DOCTYPE html>
<html>
<head>
<title>Cliente + Servidor JSON</title>
</head>
<body>
<h2>Datos sincronizados</h2>
<ul id="lista"></ul>

<form onsubmit="agregarDato(); return false;">
<input type="text" id="nuevoDato" placeholder="Escribe un dato">
<button type="submit">Agregar</button>
</form>

<script>
async function cargarDatos() {
let res = await fetch("http://localhost/cgi-bin/miscript.prg");
let datos = await res.json();
localStorage.setItem("misDatos", JSON.stringify(datos));
mostrarDatos(datos);
}

Code: Select all | Expand

function mostrarDatos(datos) {
  let lista = document.getElementById("lista");
  lista.innerHTML = "";
  datos.forEach(d => {
    let li = document.createElement("li");
    li.textContent = d;
    lista.appendChild(li);
  });
}

async function agregarDato() {
  let dato = document.getElementById("nuevoDato").value;
  if(dato) {
    let datosLocales = JSON.parse(localStorage.getItem("misDatos")) || [];
    datosLocales.push(dato);
    localStorage.setItem("misDatos", JSON.stringify(datosLocales));

    // Enviar al servidor
    await fetch("http://localhost/cgi-bin/miscript.prg", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(datosLocales)
    });

    document.getElementById("nuevoDato").value = "";
    cargarDatos();
  }
}

// Cargar datos iniciales
cargarDatos();

</script>
</body>
</html>

#include "hbjson.ch"

CLASS MiClase
DATA aDatos INIT {}
METHOD Init()
METHOD GuardarLocal()
METHOD CargarLocal()
ENDCLASS

METHOD Init() CLASS MiClase
::aDatos := {}
RETURN Self

METHOD GuardarLocal() CLASS MiClase
LOCAL cJson := hb_jsonEncode( ::aDatos )
MemoWrit( "localstore.json", cJson )
RETURN NIL

METHOD CargarLocal() CLASS MiClase
LOCAL cJson := MemoRead( "localstore.json" )
IF !Empty( cJson )
::aDatos := hb_jsonDecode( cJson )
ENDIF
RETURN NIL

// http://localhost/cgi-bin/miscript.pr

#include "hbjson.ch"

PROCEDURE Main()
LOCAL oObj := MiClase():New()
LOCAL cNewData := GetEnv( "POSTDATA" )
LOCAL cJson

oObj:CargarLocal()

// Si el cliente envió datos desde su localStorage
IF !Empty( cNewData )
cJson := hb_jsonDecode( cNewData )
oObj:aDatos := cJson
oObj:GuardarLocal()
ENDIF

cJson := hb_jsonEncode( oObj:aDatos )

// Responder solo con JSON (sin HTML)
? "Content-Type: application/json"
? ""
? cJson
RETURN