Powerbasic Museum 2020-B

IT-Consultant: Charles Pegge => OxygenBasic => Topic started by: Eduardo Jorge on June 28, 2019, 06:48:22 PM

Title: web navigation O2
Post by: Eduardo Jorge on June 28, 2019, 06:48:22 PM
where I could find examples of O2 code for Msxml2.XMLHTTP.6.0


example

#import "msxml6.dll" 
using namespace MSXML2; 
 
void XMLHttpRequestSample() 

   IXMLHTTPRequestPtr pIXMLHTTPRequest = NULL; 
   BSTR bstrString = NULL; 
   HRESULT hr; 
 
   try { 
      hr=pIXMLHTTPRequest.CreateInstance("Msxml2.XMLHTTP.6.0"); 
      SUCCEEDED(hr) ? 0 : throw hr; 
 
      hr=pIXMLHTTPRequest->open("GET", "http://localhost/books.xml ", false); 
      SUCCEEDED(hr) ? 0 : throw hr; 
 
      hr=pIXMLHTTPRequest->send(); 
      SUCCEEDED(hr) ? 0 : throw hr; 
 
      bstrString=pIXMLHTTPRequest->responseText; 
 
      MessageBox(NULL, _bstr_t(bstrString), _T("Results"), MB_OK); 
 
      if(bstrString) 
      { 
         ::SysFreeString(bstrString); 
         bstrString = NULL; 
      } 
 
   } catch (...) { 
      MessageBox(NULL, _T("Exception occurred"), _T("Error"), MB_OK); 
      if(bstrString) 
         ::SysFreeString(bstrString); 
   } 
 





"VBA code"

  Set Site = CreateObject("MSXML2.XMLHTTP.6.0")
         
          Site.Open "GET", strUrl, False
          Site.send
          tjoson = Site.responseText


Title: Re: web navigation O2
Post by: Charles Pegge on June 30, 2019, 04:22:27 AM
What language is that?  Is it .net code?
Title: Re: web navigation O2
Post by: Eduardo Jorge on June 30, 2019, 08:10:48 AM
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms759148(v%3Dvs.85)

c, but I just want some example for O2, and being able to have a base, I could not find anything related
Title: Re: web navigation O2
Post by: Zlatko Vid on June 30, 2019, 07:49:22 PM
If you look into Oxygen basic forum you may found IUP
example for o2 ,i think that John posted about it.
And my small example for ATL..very trivial.
Also look here on Jose Examples for web(ATL browser..i think) and similar.
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 01, 2019, 07:33:56 PM
 Zlatko Vid
Thank you, I'll take a look,
  I just need to get a json and pass it to an array
Title: Re: web navigation O2
Post by: Zlatko Vid on July 02, 2019, 12:19:28 PM
json is as far as i know javaScript ..right?
so you need html control to produce something with js
and of course control which support java script.
Title: Re: web navigation O2
Post by: Zlatko Vid on July 02, 2019, 12:33:46 PM
Eduardo
I just looking into open source html control called mCtrl
which have great things.it is 32 and 64 bit in a form of .dll
written in C ,so you can connect it with any windows app
i must invesigate this more...
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 02, 2019, 03:48:05 PM
Zlatko Vid
json is just a text file
in the case here, it is only to use a handful of if within a for loop.
an example of json
http://data.ny.gov/resource/d6yy-54nr.json
with Msxml2.XMLHTTP, the text file can be obtained directly, and just work the file directly
Title: Re: web navigation O2
Post by: Zlatko Vid on July 02, 2019, 06:03:06 PM
ok
i see but still you need protocol to xml.control
i don't think that someting similar is in any example of o2 but
because i am not very much interested for that I might be wrong.
you must wait for Charles respond...
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 04, 2019, 01:58:22 AM
I think there is no way to do it easily in O2,
so I read the O2 has no implementation use COM
I do not even know where to start
is not quite an important demand, what I did in vba works well, I just wanted to try something on O2 without depending on excel and vba
Title: Re: web navigation O2
Post by: Charles Pegge on July 06, 2019, 10:23:57 AM
We need some expertise in scripting-com, but o2 now has the infrastructure to support variants.
Title: Re: web navigation O2
Post by: James C. Fuller on July 06, 2019, 12:03:34 PM
From the dregs of my poor memory I believe Excel is notorious for not following the COM norm making it a bear to code outside of the vba environment.

James
Title: Re: web navigation O2
Post by: José Roca on July 06, 2019, 02:43:33 PM
WebBrowser, Excel, scripting-COM... OMG

All you need is an interface declaration (something like)


'--------------------
class IXMLHttpRequest
'====================

   public

   extends IDispatch

   HRESULT open(BSTR bstrMethod,BSTR bstrUrl,VARIANT varAsync,VARIANT bstrUser,VARIANT bstrPassword)
   HRESULT setRequestHeader(BSTR bstrHeader,BSTR bstrValue)
   HRESULT getResponseHeader(BSTR bstrHeader,BSTR *pbstrValue)
   HRESULT getAllResponseHeaders(BSTR *pbstrHeaders)
   HRESULT send(VARIANT varBody)
   HRESULT abort(void)
   HRESULT get_status(LONG *plStatus)
   HRESULT get_statusText(BSTR *pbstrStatus)
   HRESULT get_responseXML(IDispatch **ppBody)
   HRESULT get_responseText(BSTR *pbstrBody)
   HRESULT get_responseBody(VARIANT *pvarBody)
   HRESULT get_responseStream(VARIANT *pvarBody)
   HRESULT get_readyState(LONG *plState)
   HRESULT put_onreadystatechange(IDispatch *pReadyStateSink)

end class

guidval CLSID_XMLHTTP60, "88D96A0A-F192-11D4-A65F-0040963251E5"
guidval IID_IXMLHTTPRequest, "ED8C108D-4349-11D2-91A4-00C04F7969E8"


And then the usual way of using low-level COM:

CoInitialize NULL
CoCreateInstance(...)
Call the appropriate methods
CoUninitialize
Title: Re: web navigation O2
Post by: Charles Pegge on July 07, 2019, 10:36:11 AM
Thanks José,

I am puzzled why variants are often passed byval though.
Title: Re: web navigation O2
Post by: Zlatko Vid on July 07, 2019, 12:39:03 PM
QuoteI am puzzled why variants are often passed byval though.

Charles

I think they are just another name for integer pointers.

- Aurel
Title: Re: web navigation O2
Post by: José Roca on July 07, 2019, 02:08:43 PM
No, they aren't another name for integer pointers. They're variants passed by value.
Title: Re: web navigation O2
Post by: Charles Pegge on July 07, 2019, 04:32:43 PM
They are 16 byte structures (24 bytes in x64) so its strange to see them loaded straight onto the stack. UDTs are rarely passed directly.
Title: Re: web navigation O2
Post by: José Roca on July 07, 2019, 04:53:11 PM
In the beginning of COM programming, variants and guids (both 16-byte structures) were always passed by reference. Later, they decided that it was more convenient to pass them by value. Variants and guids can also be returned as the result of a method, although different languages do it well... differently, because it's never too late to create incompatibilities. I think that Microsoft C++ compilers return them in the stack. Delphi and GCC, I don't know.

So you can find old rechnologies, like the Dictionary Object, whose methods are byref variants (guess that it was because VB Script was not able to deal by byval variants at that time), and more recent technologies and the .Net Framework, that, in general, only uses byref variants and guids for out parameters and byval for in parameters.

Title: Re: web navigation O2
Post by: Charles Pegge on July 07, 2019, 11:04:43 PM
It gets messy with MS64.

Variants inflate to 24 bytes due to their non-optimal structure, which gets padded out according to the standard C type-alignment rules.

Then the MS64 calling convention requires the 1st 4 (non-float) params to be passed in RCX,RDX,R8,R9 (8 bytes each). The remainder of the params must be stored within a stack frame before making the call.

The base of the stack frame (value in RSP) must be kept 16-byte aligned.

So we have to struggle with some very poor design decisions in the system.

Title: Re: web navigation O2
Post by: Zlatko Vid on July 08, 2019, 11:19:02 AM
Jose
I don't want to argue with you because you have lot more experience than me in such a things
BUT
i was not completely in wrong
from wiki-diki
In Visual Basic (and Visual Basic for Applications) the Variant data type is a tagged union 

so ...if is union then is UDT, if is UDT then is some sort of pointer
so .. if i understand it each time we create variant we also create some sort of union structure.

again ...i am not very smart in that stuff ..so i just follow the logic.   ;D
i think ..

all best ...Aurel
Title: Re: web navigation O2
Post by: José Roca on July 08, 2019, 02:58:07 PM
An UDT is not a pointer, but a composite data type. A Variant is an structure which has a member that is an Union.

When the parameter is byref variant, you pass a pointer to that structure, but when it is byval, you have to push all the members of that structure into the stack. As Charles has pointed, it is not difficult to do with 32 bit, but it is messy with 64-bit.

Besides, the methods get_responseBody and get_responseStream return a Variant as the result, not a pointer to a Variant.
Title: Re: web navigation O2
Post by: Charles Pegge on July 08, 2019, 05:44:15 PM
I see this is how variants are returned in C/C++

The first param (after the invisible this) is a variant reference. The caller must create a variant to receive the return value.

I have already adopted a similar scheme for all direct UDT returns, with invisible returns variables..

Quote
Visual Basic Syntax

strValue = oServerXMLHTTPRequest.responseBody 

C/C++ Syntax

HRESULT get_responseBody(VARIANT* pvarVal); 

https://msdn.microsoft.com/en-us/windows/ms753682(v=vs.71)
Title: Re: web navigation O2
Post by: José Roca on July 08, 2019, 06:10:51 PM
> The first param (after the invisible this) is a variant reference. The caller must create a variant to receive the return value.

This applies when using low-level COM, that almost always returns an HRESULT value as the result of a method, but not when using automation languages. Anyway, O2 does not support COM Automation, so O2 users must learn that they can't use something like bstrString=pIXMLHTTPRequest->responseText;
Title: Re: web navigation O2
Post by: Zlatko Vid on July 09, 2019, 08:54:24 AM
QuoteWhen the parameter is byref variant, you pass a pointer to that structure, but when it is byval, you have to push all the members of that structure into the stack. As Charles has pointed, it is not difficult to do with 32 bit, but it is messy with 64-bit.

Hi Jose

Thank you , i hope that i understand it now..
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 10, 2019, 09:46:07 PM
if I understand, it is not possible to use with O2
So is there an interface for getting files, or reading, working the html of a web page?
Title: Re: web navigation O2
Post by: Charles Pegge on July 11, 2019, 02:35:47 PM
There is an o2 folder: examples\system\winsock containing 2 examples of low-level internet access.
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 11, 2019, 04:52:01 PM
thank you Charles
I looked at Dict_Send_Receive.o2bas but it seems to be very advanced for me
Title: Re: web navigation O2
Post by: Charles Pegge on July 12, 2019, 01:27:11 PM
I found Wininet to be be quite friendly. This is how to get a web page, and file it:


extern lib "wininet.dll"

! InternetOpenA
! InternetOpenUrlA
! InternetCloseHandle
! InternetReadFile

end extern

string buf=nuls 100000
string url="https://www.oxygenbasic.org/index.html"
int cbytes
sys hInternet
sys hFile
hInternet = InternetOpenA( "o2demo",0,0,0,0 )
hFile = InternetOpenUrlA( hInternet,url,0,0,0,0 )
InternetReadFile( hFile,buf,len(buf),@cbytes )
InternetCloseHandle( hFile )
InternetCloseHandle( hInternet )
print left( buf,500 )
putfile( "t.txt",left(buf,cbytes) )



NOTES:
======

'https://docs.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena
'https://docs.microsoft.com/en-us/cpp/mfc/wininet-basics?view=vs-2019#_core_create_a_very_simple_browser


/*
% INTERNET_OPEN_TYPE_DIRECT 1
% INTERNET_FLAG_ASYNC 0x10000000
*/

/*
extern lib "wininet.dll"

sys InternetOpenA(
  LPCSTR lpszAgent,
  DWORD  dwAccessType,
  LPCSTR lpszProxy,
  LPCSTR lpszProxyBypass,
  DWORD  dwFlags
);

BOOLAPI InternetCloseHandle(
  HINTERNET hInternet
);

BOOLAPI InternetCanonicalizeUrlA(
  LPCSTR  lpszUrl,
  LPSTR   lpszBuffer,
  LPDWORD lpdwBufferLength,
  DWORD   dwFlags
);
sys InternetOpenUrlA(
  HINTERNET hInternet,
  LPCSTR    lpszUrl,
  LPCSTR    lpszHeaders,
  DWORD     dwHeadersLength,
  DWORD     dwFlags,
  DWORD_PTR dwContext
);

BOOLAPI InternetReadFile(
  HINTERNET hFile,
  LPVOID    lpBuffer,
  DWORD     dwNumberOfBytesToRead,
  LPDWORD   lpdwNumberOfBytesRead
);

BOOLAPI InternetFindNextFileA(
  HINTERNET hFind,
  LPVOID    lpvFindData
);

*/

'#include <afxinet.h>

/*
void DisplayPage(LPCTSTR pszURL)
{
   CInternetSession session(_T("My Session"));
   CStdioFile* pFile = NULL;
   CHAR szBuff[1024];
   //use a URL and print a Web page to the console
   pFile = session.OpenURL(pszURL);
   while (pFile->Read(szBuff, 1024) > 0)
   {
      printf_s("%1023s", szBuff);
   }
   delete pFile;
   session.Close();
}
*/
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 12, 2019, 10:10:13 PM
Thank you, Charles.
is basically what I need, I just do not understand why it does not grab all the content.
for most Json I'm going to use is 100% because they are small but some are of indefinite size
I tested this
http://data.ny.gov/resource/d6yy-54nr.json
and does not take all content
Title: Re: web navigation O2
Post by: José Roca on July 12, 2019, 11:09:08 PM
> is basically what I need, I just do not understand why it does not grab all the content.

This is because the buffer is too small.
Title: Re: web navigation O2
Post by: Charles Pegge on July 12, 2019, 11:09:35 PM
There are likely to be limits on the internal read-buffer. So it may take a few ReadFile calls to get the complete web page/file. Perhaps I'm being over-cautious :)

No buffer limits:

extern lib "wininet.dll"

! InternetOpenA
! InternetOpenUrlA
! InternetCloseHandle
! InternetReadFile

string buf=nuls 0x20000 '128k
string tbuf
string url="https://www.oxygenbasic.org/index.html"
int cbytes
sys hInternet
sys hFile
int c
hInternet = InternetOpenA( "o2demo",0,0,0,0 )
hFile = InternetOpenUrlA( hInternet,url,0,0,0,0 )
do
  cbytes=0
  InternetReadFile( hFile,buf,len(buf),@cbytes )
  if cbytes
    tbuf+=left(buf,cbytes)
    c++
  else
    exit do
  endif
loop
InternetCloseHandle( hFile )
InternetCloseHandle( hInternet )
'print tbuf
putfile( "t.txt",tbuf )
'print c 'readfile loops


improved loop!
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 12, 2019, 11:34:18 PM
Yes, it worked perfectly
Is it advisable to use the other for those of limited size or can this be used for everyone without problems?
It's amazing how there are so many different tools and ways of doing the same task
only years of dedication and a mind capable of assimilating all this

Many thanks Charles
Title: Re: web navigation O2
Post by: Charles Pegge on July 12, 2019, 11:47:41 PM
It will work for all sizes, and it is optimizable.

I've also improved the loop.
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 13, 2019, 12:20:34 AM
cool
can I use the same method to download zip files?
may be interesting a ".inc" for use on the web, after all today everything is captured and sent to the big network
"The internet here is horrible today"
Title: Re: web navigation O2
Post by: Charles Pegge on July 13, 2019, 04:48:03 AM
It should work. Both http and ftp protocols are supported, (ftp files could be of any type).
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 13, 2019, 11:08:24 PM
Thanks, Charles.
I can probably do things by myself, I'm off here looking for examples and doing tests.
most changes little of how I do in vba
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 13, 2019, 11:58:48 PM
Charles, it might be a good idea to put a separate folder in github to put new examples and .inc files, so you could organize better, besides having a range of examples located without having to change the zip of O2
Title: Re: web navigation O2
Post by: Chris Chancellor on July 14, 2019, 07:04:10 PM
Hello Charles , Jose, Eduardo

i found the below code from PB about cursor browser

https://forum.powerbasic.com/forum/jose-s-corner/discussion/763266-big-browser-cursor (https://forum.powerbasic.com/forum/jose-s-corner/discussion/763266-big-browser-cursor)

can this be converted to O2 ?


#Compile Exe
#Dim All
%Unicode = 1
%UseWebBrowser = 1            ' // Use the WebBrowser control
#Include Once "CWindow.inc"   ' // CWindow class
%IDC_WebBrowser = 1001
Global hDlg, hBrowser, hCursor As Dword, OldProc&amp;, pWindow As IWindow

Function PBMain
   Dialog New Pixels, 0, "WebBrowser", , , 800, 600, %WS_OverlappedWindow To hDlg
   pWindow = Class "CWindow"
   hBrowser = pWindow.AddWebBrowserControl(hDlg, %IDC_WEBBROWSER, "http://www.powerbasic.com",Nothing, 0, 0, 600,400)
   Dialog Show Modal hDlg, Call DlgProc
End Function

CallBack Function DlgProc() As Long
   Select Case CbMsg
      Case %WM_InitDialog
         hCursor = LoadImage (ByVal 0, "c:\windows\cursors\larrow.cur", %IMAGE_ICON, 125, 125, %LR_LOADFROMFILE)
         OldProc&amp; = SetWindowLong(hBrowser, %GWL_WndProc, CodePtr(NewProc))  'subclass
      Case %WM_SetCursor
         SetCursor hCursor
         Function = 1
      Case %WM_Destroy
         SetWindowLong hBrowser, %GWL_WNDPROC, OldProc&amp;   'un-subclass
  End Select
End Function

Function NewProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Select Case Msg
      Case %WM_SetCursor
         SetCursor hCursor
         Function = 1
         Exit Function
   End Select
   Function = CallWindowProc(OldProc&amp;, hWnd, Msg, wParam, lParam)
End Function




Title: Re: web navigation O2
Post by: Zlatko Vid on July 15, 2019, 01:30:03 PM
Yes it could be if you have
CWindow.inc from powerBasic translated to o2 inc.
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 15, 2019, 11:14:33 PM
I consider that, more than adapting lines of code of the PB, it has to determine direct examples with the own O2
start with simple and commented examples
o2 is very versatile in its syntax, but it also seems to be its weakest link
passing from the vba to him
ReDim Arrayindice (100) the string, and was giving errors within parts of the code
ReDim string Arrayindice (100), and it worked
ReDim string Arrayindice (C), I do not understand why it is necessary to define string of a variable that had already been defined,
the biggest failure for me is wanting to lean on other platforms, O2 is already consistent to follow with his own legs, and define a proper authority

I also noticed that simple codigo that works perfectly in 32bit hangs in 64bit
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 16, 2019, 01:48:39 AM
ainda apanhando para escrever algo



extern lib "wininet.dll"

! InternetOpenA
! InternetOpenUrlA
! InternetCloseHandle
! InternetReadFile

string buf=nuls 0x20000 '128k
string tbuf
string url="http://data.ny.gov/resource/d6yy-54nr.json"
int cbytes
sys hInternet
sys hFile
int c
hInternet = InternetOpenA( "o2demo",0,0,0,0 )
hFile = InternetOpenUrlA( hInternet,url,0,0,0,0 )
do
  cbytes=0
  InternetReadFile( hFile,buf,len(buf),@cbytes )
  if cbytes
    tbuf+=left(buf,cbytes)
    c++
  else
    exit do
  endif
loop
InternetCloseHandle( hFile )
InternetCloseHandle( hInternet )

string Saida
  Dim  Arraydados(4) as string
    Dim L As int, C As int, cc As int, tt As int, s as char,s2 as string
dim ch,ch2 as int
     tt = Len(tbuf)
     C = 1: L = 1
     For cc = 1 To tt
          s = Mid tbuf, cc, 1
          If s = chr(34) Then 'para as aspas (")
                If ch2 = 0 Then ch2 = 1 Else ch2 = 0
                GoTo PULA
          End If
          If ch2 = 0 Then
                If s = "," Then  C = C + 1: L = 1: GoTo PULA
                If s = ":" Then  L = 2:  GoTo PULA
       'If s = "{" Or s = "}" Then  GoTo PULA
         End If

If s = "{"  Then GoTo PULA
        'If s = chr(13) Then 'Enter
If  s = "}" Then
        s = Mid tbuf, cc+1, 1
saida=saida & left(Arraydados(1),10) & " ; " & Arraydados(2) & " ; " & Arraydados(3) & s
Arraydados(1)="" : Arraydados(2)="" : Arraydados(3)=""
c=0: GoTo PULA
end if
If s = "[" or s = "]" Then  GoTo PULA
If L = 2 Then
Arraydados(C) =  Arraydados(C) & s
        End If
PULA:
     Next

putfile( "t2.txt",saida )
putfile( "t1.txt",tbuf )

Title: Re: web navigation O2
Post by: Zlatko Vid on July 23, 2019, 07:11:40 PM
ainda apanhando para escrever algo

he he ...i don't get it..
EDuardo you must learn o2 code
there is no just copy from other dialect...
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 24, 2019, 03:34:36 PM
but what is the default of O2?
is the basic C standard?
As I said, O2's strongest point is its virtually free syntax, and it's also its weakest point.
In the case of "REDIM", note that it is accepted to declare variables with "DIM x AS LONG", not that I prefer to use this mode, but I hope that accepting a mode using dim is also suitable for REDIM, and the error appeared in another line. took longer to know where it was
I had commented before that I would prefer syntax blocks, to force the chosen syntax avoiding typos
to me, C's bad point is his "symbolism" {}; && ++! = ... I couldn't get used to it, I don't miss Gosub so much despite having certain uses,
but for me End if, Next .., is paramount to locate me in the logic of what I'm doing
Having so many ways to declare variables as I see it is only useful for reusing code, because writing something from scratch is the most important thing.
Title: Re: web navigation O2
Post by: Zlatko Vid on July 25, 2019, 06:41:28 PM
The simpliest way to declare variables in 02 is
INT a,s,d,f,g,h
STRING q,w,e,r,t,z
FLOAT x,y,c,v,b

INT arr1[100] : STRING s[200] : FLOAT x[300]

as you can see there is no need to use DIM
Title: Re: web navigation O2
Post by: Eduardo Jorge on July 27, 2019, 03:35:07 PM
Yes I know,
as I said the possibility of so many methods is only useful for reusing lines of code without having to rewrite
but this feat has to be consistent, or at least show syntax error on the right line and not elsewhere
I wouldn't mind if O2 had only one method of declaring variables that would just force manually declaring without being able to paste ready-made codes
would even be good because it would make O2 independent of other languages and make it easier for Charles
Title: Re: web navigation O2
Post by: James C. Fuller on July 28, 2019, 12:11:08 PM
Quote from: Eduardo Jorge on July 27, 2019, 03:35:07 PM
I wouldn't mind if O2 had only one method of declaring variables that would just force manually declaring without being able to paste ready-made codes
would even be good because it would make O2 independent of other languages and make it easier for Charles

Maybe a #SYNTAX=[O2] statement ??

James
Title: Re: web navigation O2
Post by: Eduardo Jorge on August 07, 2019, 08:23:03 PM
James C. Fuller
Yes, it would be interesting and something less permissive


I noticed that the values are explicit in the generated code
I think it would be interesting to code to prevent others from exchanging these texts so easily
like a link, someone malicious could link to a malicious page very easily
I am trying to add the encrypted values and a function that will decrypt for use, of course I can only do this simply and inefficiently for those who know the subject
Title: Re: web navigation O2
Post by: Eduardo Jorge on August 08, 2019, 01:41:22 AM
I want to build some simple programs but that has a certain requirement
so I thought of putting a link to the O2 page as an advertisement,
Is there a way to insert a link and open it through their default browser?