local obs = obslua
local ffi = require("ffi")
local winhttp = ffi.load("winhttp")
local kernel32 = ffi.load("kernel32")
ffi.cdef[[
typedef void* HINTERNET;
typedef unsigned int INTERNET_PORT;
typedef const wchar_t* LPCWSTR;
typedef unsigned long DWORD;
typedef unsigned long DWORD_PTR;
typedef DWORD* LPDWORD;
typedef void* LPVOID;
typedef int BOOL;
static const int INTERNET_DEFAULT_PORT = 0;
static const int INTERNET_DEFAULT_HTTP_PORT = 80;
static const int INTERNET_DEFAULT_HTTPS_PORT = 443;
/* flags for WinHttpOpenRequest */
static const int WINHTTP_FLAG_SECURE = 0x00800000;
HINTERNET WinHttpOpen(LPCWSTR pwszUserAgent, DWORD dwAccessType, LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass, DWORD dwFlags);
HINTERNET WinHttpConnect(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved);
HINTERNET WinHttpOpenRequest(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags);
BOOL WinHttpSendRequest(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext);
BOOL WinHttpReceiveResponse(HINTERNET hRequest, LPVOID lpReserved);
BOOL WinHttpQueryDataAvailable(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable);
BOOL WinHttpCloseHandle(HINTERNET hInternet);
DWORD GetLastError(void);
typedef unsigned int UINT;
typedef const char* LPCSTR;
typedef wchar_t* LPWSTR;
typedef char* LPSTR;
typedef int* LPBOOL;
int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
/* Code Page Default Values */
static const int CP_ACP = 0; // default to ANSI code page
static const int CP_OEMCP = 1; // default to OEM code page
static const int CP_MACCP = 2; // default to MAC code page
static const int CP_THREAD_ACP = 3; // current thread's ANSI code page
static const int CP_SYMBOL = 42; // SYMBOL translations
static const int CP_UTF7 = 65000; // UTF-7 translation
static const int CP_UTF8 = 65001; // UTF-8 translation
]]
-- Options for WinHttpSendRequest
WINHTTP_NO_ADDITIONAL_HEADERS = nil
WINHTTP_NO_REQUEST_DATA = nil
-- This will become wide (L"GET" or 2 bytes per character) later in the code, now just simple string
local GET_wstr = "GET"
local UserAgent_wstr = "A WinHTTP from Lua OBS example/1.0"
-- IP and port (PC address in local network)
local ServerName_wstr = [[192.168.0.2]]
local ServerPort = 8080
---------------------------------------------
--
-- Your Command (target object), MODIFY IT!!!
--
local ObjectName_wstr = [[/ExecuteMacro=7f86b4a0-6edd-4415-89c7-199b2854a307/363edea7-ccad-4c40-a877-3c493d37aeed]]
function AnsiToUnicode16L(in_Src, nsrcBytes)
nsrcBytes = nsrcBytes or #in_Src
print("nsrcBytes: " .. nsrcBytes)
-- Find out how many characters needed
local charsneeded = kernel32.MultiByteToWideChar(kernel32.CP_ACP, 0, in_Src, nsrcBytes, nil, 0);
print("charsneeded: " .. charsneeded)
if charsneeded < 0 then
return nil;
end
local buff = ffi.new("uint16_t[?]", charsneeded + 1)
local charswritten = kernel32.MultiByteToWideChar(kernel32.CP_ACP, 0, in_Src, nsrcBytes, buff, charsneeded)
-- Wide Null terminator
buff[charswritten] = 0
print("charswritten: " .. charswritten)
return buff;
end
function Unicode16ToAnsi(in_Src)
local srcShorts = ffi.cast("const uint16_t *", in_Src)
-- Find out how many characters needed
local bytesneeded = kernel32.WideCharToMultiByte(kernel32.CP_ACP, 0, srcShorts, -1, nil, 0, nil, nil);
print("bytesneeded: " .. bytesneeded);
if bytesneeded <= 0 then
return nil;
end
local buff = ffi.new("uint8_t[?]", bytesneeded + 1)
local byteswritten = kernel32.WideCharToMultiByte(kernel32.CP_ACP, 0, srcShorts, -1, buff, bytesneeded, nil, nil);
-- Null terminator
buff[byteswritten] = 0
print("charswritten: " .. byteswritten)
return ffi.string(buff, byteswritten - 1);
end
-- Update variables with wide values
UserAgent_wstr = AnsiToUnicode16L(UserAgent_wstr)
ServerName_wstr = AnsiToUnicode16L(ServerName_wstr)
GET_wstr = AnsiToUnicode16L(GET_wstr)
ObjectName_wstr = AnsiToUnicode16L(ObjectName_wstr)
-- This function will send a HTTP Get request
function send_winhttp_request()
-- No proxy, performed synchronously, no TLS
local hSession = winhttp.WinHttpOpen(UserAgent_wstr, 1, nil, nil, 0)
print(hSession)
if not hSession then
print("Error. Could not create session " .. ffi.C.GetLastError())
--return
end
-- Specify an HTTP server and port
local hConnect = winhttp.WinHttpConnect(hSession, ServerName_wstr, ServerPort, 0)
print(hConnect)
if not hConnect then
print("Error. Could not connect to " .. ServerName_wstr .. ", " .. ffi.C.GetLastError())
--return
end
-- Create an HTTP Request handle (GET, target resource, HTTP/1.1, no referring, default accept types, not secure transaction)
local hRequest = winhttp.WinHttpOpenRequest(hConnect, GET_wstr, ObjectName_wstr, nil, nil, nil, 0)
print(hRequest)
if not hRequest then
print("Error. Could not create request " .. ffi.C.GetLastError())
--return
end
-- Send a request
local bResults = winhttp.WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)
-- Report errors
if not bResults then
print("Error. Error has occurred " .. ffi.C.GetLastError())
end
--[[ Response
local response = winhttp.WinHttpReceiveResponse(request, nil)
print(response)
if not tonumber(response) then
print("Error. Could not receive response " .. ffi.C.GetLastError())
return
end
local size = ffi.new("LPDWORD")
winhttp.WinHttpQueryDataAvailable(request, size)
print(size)
if not tonumber(size) or not tonumber(size[0]) then
print("Error. No data available " .. ffi.C.GetLastError())
return
end
]]
-- Close open handles
if hRequest then winhttp.WinHttpCloseHandle(hRequest) end
if hConnect then winhttp.WinHttpCloseHandle(hConnect) end
if hSession then winhttp.WinHttpCloseHandle(hSession) end
print("Ended")
end
-- Call the send_winhttp_request on event
function on_event(event)
if event == obs.OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED then
send_winhttp_request()
end
end
function script_description()
return "Example!\n\nSend a HTTP Get request:\n" ..
Unicode16ToAnsi(ObjectName_wstr) .. " on REPLAY_BUFFER_STARTED"
end
function script_load(settings)
obs.obs_frontend_add_event_callback(on_event)
end