diff --git a/App.config b/App.config index 5e99a3d..9d231d6 100644 --- a/App.config +++ b/App.config @@ -7,7 +7,6 @@ - diff --git a/KanHQ-open.sln b/KanHQ-open.sln index d79b071..23dd057 100644 --- a/KanHQ-open.sln +++ b/KanHQ-open.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "KanHQ", "KanHQ.fsproj", "{8987BD19-CC77-4959-A4E3-203714C613D5}" EndProject @@ -32,4 +32,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5A45B70B-07ED-4A65-9E47-E9B741022595} + EndGlobalSection EndGlobal diff --git a/KanHQ.fs b/KanHQ.fs index 2c02391..3df2bb3 100644 --- a/KanHQ.fs +++ b/KanHQ.fs @@ -21,15 +21,17 @@ open Sayuri.FSharp.Local open Sayuri.JsonSerializer open Sayuri.Windows.Forms -[] +[] #if LIGHT [] #else -[] +[] #endif do let values = [| + "FEATURE_BROWSER_EMULATION", 11001 "FEATURE_GPU_RENDERING", 1 + "FEATURE_NINPUT_LEGACYMODE", 0 "FEATURE_SCRIPTURL_MITIGATION", 1 // "FEATURE_AJAX_CONNECTIONEVENTS", 1 @@ -47,7 +49,6 @@ do // "FEATURE_IVIEWOBJECTDRAW_DMLT9_WITH_GDI", 0 // "FEATURE_LOCALMACHINE_LOCKDOWN", 1 // "FEATURE_MIME_HANDLING", 1 - // "FEATURE_NINPUT_LEGACYMODE", 0 // "FEATURE_RESTRICT_ABOUT_PROTOCOL_IE7", 1 // "FEATURE_RESTRICT_ACTIVEXINSTALL", 1 // "FEATURE_SECURITYBAND", 1 @@ -65,23 +66,18 @@ do |] let name = Path.GetFileName Application.ExecutablePath use key = Registry.CurrentUser.CreateSubKey @"Software\Microsoft\Internet Explorer\Main\FeatureControl" - do - use key = key.CreateSubKey "FEATURE_BROWSER_EMULATION" - let version = Version(Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer", "Version", "8.0.0.0") |> string) - key.SetValue(name, (if version.Major = 9 && version.Minor > 9 then version.Minor else version.Major) * 1000) for subkey, value in values do use key = key.CreateSubKey subkey key.SetValue(name, value) let dump (e : obj) = let path = Path.Combine(Environment.GetFolderPath Environment.SpecialFolder.DesktopDirectory, "KanHQ.txt") let name = Assembly.GetExecutingAssembly().GetName() - let text = sprintf "----\r\n%O\r\n%s: %O\r\nWin: %O\r\n.NET: %O, %dbit\r\nIE: %O\r\nflash: %O\r\n%O\r\n" + let text = sprintf "----\r\n%O\r\n%s: %O\r\nWin: %O\r\n.NET: %O, %dbit\r\nIE: %O\r\n%O\r\n" DateTime.Now name.Name name.Version Environment.OSVersion.Version Environment.Version (IntPtr.Size * 8) (Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer", "Version", "unknown")) - (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Macromedia\FlashPlayer", "CurrentVersion", "unknown")) e File.AppendAllText(path, text) AppDomain.CurrentDomain.UnhandledException.Add(fun e -> dump e.ExceptionObject) @@ -98,7 +94,7 @@ type OnResponse = delegate of path : string * [] extern nativeint private LoadLibrary(string lpFileName); [] -extern void private SetCallback(OnRequest onRequest, OnResponse onResponse); +extern void private ZzzSetCallback(OnRequest onRequest, OnResponse onResponse); do let modules = [| for m in Process.GetCurrentProcess().Modules -> m |] @@ -262,15 +258,12 @@ let tweetWindow (parent : Form) image = let getCapture (webBrowser : WebBrowser2) = WebBrowser2.GetElementById(webBrowser.DomDocument, "game_frame") - |> Option.bind (fun iframe -> WebBrowser2.GetElementById(WebBrowser2.GetFrameDocument iframe, "externalswf")) + |> Option.bind (fun iframe -> WebBrowser2.GetElementById(WebBrowser2.GetFrameDocument iframe, "htmlWrap")) + |> Option.bind (fun iframe -> WebBrowser2.GetElementsByTagName(WebBrowser2.GetFrameDocument iframe, "canvas") |> Array.tryHead) |> Option.map WebBrowser2.GetCapture let getImage webBrowser = - getCapture webBrowser |> Option.map (fun (size, capture) -> let bitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format24bppRgb) - use graphics = Graphics.FromImage bitmap - graphics.GetHdc() |> capture - graphics.ReleaseHdc() - bitmap) + getCapture webBrowser |> Option.map (fun bitmap -> new MemoryStream(bitmap) |> Bitmap.FromStream) let saveImage webBrowser = getImage webBrowser |> Option.iter (fun bitmap -> @@ -521,7 +514,7 @@ type Mission (index : int, name : string, duration : int, flagshipLevel : int, t get "api_fuel_max" ship |> getNumber, getNumber ship.["api_bull_max"], getNumber ship.["api_stype"] |> int) deck |> Array.unzip3 let drum, daihatsu = let shipSlots = Array.map (get "api_slot" >> getArray) deck lock slotitems (fun () -> Array.map (Array.choose (getNumber >> function -1.0 -> None | id -> Some slotitems.[id])) shipSlots) - |> Array.map (fun slots -> Array.sumBy (fun (id, _, _) -> if id = 75.0 then 1 else 0) slots, Array.sumBy (fun (id, _, _) -> if id = 68.0 then 0.05 else 0.00) slots) + |> Array.map (fun slots -> Array.sumBy (fun (id, _) -> if id = 75.0 then 1 else 0) slots, Array.sumBy (fun (id, _) -> if id = 68.0 then 0.05 else 0.00) slots) |> Array.unzip let daihatsu = 1.00 + (Array.sum daihatsu |> min 0.20) missions |> Array.iter (fun mission -> mission.Update(useFuels, useBullets, stypes, drum, daihatsu)) @@ -628,7 +621,7 @@ type Ship private (id : float) = |> Array.map getNumber let ids = Dictionary() bindingList |> Seq.iteri (fun i item -> ids.Add(item.Index, i) |> ignore) - let repairitems = lock slotitems (fun () -> Seq.choose (fun (KeyValue(id, (itemid, _, _))) -> if itemid = 86.0 then Some id else None) slotitems |> Array.ofSeq) + let repairitems = lock slotitems (fun () -> Seq.choose (fun (KeyValue(id, (itemid, _))) -> if itemid = 86.0 then Some id else None) slotitems |> Array.ofSeq) lock ships (fun () -> repairShips <- decks |> Array.map (fun deck -> getArray deck.["api_ship"] |> Array.map getNumber) @@ -751,7 +744,7 @@ type Slotitem (masterid, count, shipNames) = getArray ship.["api_slot"] |> Array.iter (fun itemid -> let itemid = getNumber itemid if 0.0 < itemid then itemShip.Add(itemid, name)))) lock slotitems (fun () -> - Seq.groupBy (fun (KeyValue(_, (masterid, _, _))) -> masterid) slotitems + Seq.groupBy (fun (KeyValue(_, (masterid, _))) -> masterid) slotitems |> Seq.iter (fun (masterid, group) -> let count = Seq.length group let shipNames = Seq.choose (fun (KeyValue(id, _)) -> match itemShip.TryGetValue id with true, name -> Some name | false, _ -> None) group |> Seq.distinct @@ -945,12 +938,12 @@ let mutable missionTimes = Array.empty let mutable dockTimes = Array.empty let mutable kousyouTimes = Array.empty let mutable maxCount = 0, 0 -let mutable hqLevel = 0.0 +let mutable hqLevel = 0 [] extern bool FlashWindow(nativeint hWnd, bool bInvert); -let browserWidth = 1040 +let browserWidth = 1280 let mainWindow () = createForm (browserWidth + 181) 668 "艦これ 司令部室" (fun form -> form.Name <- "Main" @@ -985,63 +978,44 @@ let mainWindow () = createForm (browserWidth + 181) 668 "艦これ 司令部室" if !deckIndex < decks.Length && 0 < masterShips.Count then let deck = decks.[!deckIndex] let ships = lock ships (fun () -> getArray deck.["api_ship"] |> Array.choose (getNumber >> fun shipid -> match ships.TryGetValue shipid with true, value -> Some (shipid, value) | _ -> None)) - let calcSakuteki type_ level saku = - let itemScale, levelScale = match type_ with - | 6.0 -> 0.6, 0.00 // 艦上戦闘機 - | 7.0 -> 0.6, 0.00 // 艦上爆撃機 - | 8.0 -> 0.8, 0.00 // 艦上攻撃機 - | 9.0 -> 1.0, 0.00 // 艦上偵察機 - | 10.0 -> 1.2, 1.20 // 水上偵察機 - | 11.0 -> 1.1, 0.00 // 水上爆撃機 - | 12.0 -> 0.6, 1.25 // 小型電探 - | 13.0 -> 0.6, 1.25 // 大型電探 - | 14.0 -> 0.6, 0.00 // ソナー - | 26.0 -> 0.6, 0.00 // 三式指揮連絡機(対潜) - | 29.0 -> 0.6, 0.00 // 探照灯 - | 34.0 -> 0.6, 0.00 // 艦隊司令部施設 - | 35.0 -> 0.6, 0.00 // 熟練艦載機整備員 - | 39.0 -> 0.6, 0.00 // 熟練見張員 - | 41.0 -> 0.6, 0.00 // 大型飛行艇 - | 42.0 -> 0.6, 0.00 // 大型探照灯 - | 45.0 -> 0.6, 0.00 // 多用途水上機/水上戦闘機 - | _ -> 0.0, 0.00 - itemScale * (saku + levelScale * sqrt level) - let calcSeikuu type_ alv tyku onslot = - let bonusTable = match alv with - // 内部熟練度 - // | 6 艦上戦闘機ボーナス - // | | 7 艦上爆撃機ボーナス、なし - // | | | 8 艦上攻撃機ボーナス、なし - // | | | | 11 水上爆撃機ボーナス - // | | | | | 45 多用途水上機/水上戦闘機ボーナス - // | | | | | | - | Some 1.0 -> 17.5, 0.0, 0.0, 0.0, 0.0, 0.0 - | Some 2.0 -> 32.5, 2.0, 0.0, 0.0, 1.0, 2.0 - | Some 3.0 -> 47.5, 5.0, 0.0, 0.0, 1.0, 5.0 - | Some 4.0 -> 62.5, 9.0, 0.0, 0.0, 1.0, 9.0 - | Some 5.0 -> 77.5, 14.0, 0.0, 0.0, 3.0, 14.0 - | Some 6.0 -> 92.5, 14.0, 0.0, 0.0, 3.0, 14.0 - | Some 7.0 -> 120.0, 22.0, 0.0, 0.0, 6.0, 22.0 - | _ -> 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - match type_, bonusTable with - | 6.0, (alv, b, _, _, _, _) // 艦上戦闘機 - | 7.0, (alv, _, b, _, _, _) // 艦上爆撃機 - | 8.0, (alv, _, _, b, _, _) // 艦上攻撃機 - | 11.0, (alv, _, _, _, b, _) // 水上爆撃機 - | 45.0, (alv, _, _, _, _, b) // 多用途水上機/水上戦闘機 - -> tyku * sqrt (getNumber onslot) + sqrt (alv / 10.0) + b |> int - | _ -> 0 let sakuteki, seikuu = lock slotitems (fun () -> - ships |> Array.map (fun (_, ship) -> let itemSakuteki, seikuu = (getArray ship.["api_slot"], getArray ship.["api_onslot"]) - ||> Array.map2 (fun slot onslot -> match getNumber slot |> slotitems.TryGetValue with - | true, (masterid, alv, level) -> let type_, saku, tyku = masterSakuteki.[masterid] - calcSakuteki type_ level saku, calcSeikuu type_ alv tyku onslot - | false, _ -> 0.0, 0) - |> Array.unzip - let shipSakuteki = getNumber (getArray ship.["api_sakuteki"]).[0] - Array.sum itemSakuteki + sqrt shipSakuteki, Array.sum seikuu)) - |> Array.unzip - let sakuteki, seikuu = Array.sum sakuteki - ceil (hqLevel * 0.4) + float (6 - ships.Length) * 2.0, Array.sum seikuu + ships |> Array.map (fun (_, ship) -> let sakuteki, scaled, taiku = (getArray ship.["api_slot"], getArray ship.["api_onslot"]) + ||> Array.map2 (fun slot onslot -> match getNumber slot |> slotitems.TryGetValue with + | true, (masterid, alv) -> let type_, sakuteki, taiku = masterSakuteki.[masterid] + let scale = match type_ with + | 7.0 -> 1.04 // 艦上爆撃機 + | 8.0 -> 1.37 // 艦上攻撃機 + | 9.0 -> 1.66 // 艦上偵察機 + | 10.0 -> 2.00 // 水上偵察機 + | 11.0 -> 1.78 // 水上爆撃機 + | 12.0 -> 1.00 // 小型電探 + | 13.0 -> 0.99 // 大型電探 + | 29.0 -> 0.91 // 探照灯 + | _ -> 0.00 + let taiku = match type_ with + | 6.0 // 艦上戦闘機 + | 7.0 // 艦上爆撃機 + | 8.0 // 艦上攻撃機 + | 11.0 // 水上爆撃機 + -> taiku * sqrt (getNumber onslot) |> int + | _ -> 0 + // 艦載機熟練度 + let taiku = if alv <> Some 7.0 then taiku else + taiku + match type_ with + | 6.0 -> 25 // 艦上戦闘機 + | 7.0 -> 3 // 艦上爆撃機 + | 8.0 -> 3 // 艦上攻撃機 + | 11.0 -> 9 // 水上爆撃機 + | _ -> 0 + sakuteki, sakuteki * scale, taiku + | false, _ -> 0.0, 0.0, 0) + |> Array.unzip3 + let sakuteki = getNumber (getArray ship.["api_sakuteki"]).[0] - Array.sum sakuteki + let sakuteki = Array.sum scaled + sqrt sakuteki * 1.69 + let seikuu = Array.sum taiku + sakuteki, seikuu) + |> Array.unzip) + let sakuteki, seikuu = Array.sum sakuteki - 0.61 * float ((hqLevel + 4) / 5 * 5), Array.sum seikuu let deckName = getString deck.["api_name"] deckLabel.Text <- sprintf "%s (索 %0.1f, 制 %d)" deckName sakuteki seikuu shipLabels |> Array.iteri (fun i l -> @@ -1064,7 +1038,7 @@ let mainWindow () = createForm (browserWidth + 181) 668 "艦これ 司令部室" let webBrowser = new WebBrowser2(Location = Point(0, 0), Size = Size(browserWidth, 668), Anchor = (AnchorStyles.Top|||AnchorStyles.Bottom|||AnchorStyles.Left|||AnchorStyles.Right), ScriptErrorsSuppressed = true, Url = Uri "http://www.dmm.com/netgame/social/-/gadgets/=/app_id=854854/") - let mute = new MuteCheckBox(Location = Point(browserWidth + 10, 524), Anchor = anchorTR, Text = "消音", UseVisualStyleBackColor = true) + let mute = new CheckBox(Location = Point(browserWidth + 10, 524), Anchor = anchorTR, Text = "消音", UseVisualStyleBackColor = true, Enabled = false) let screenShot = new Button(Location = Point(browserWidth + 10, 548), Anchor = anchorTR, Text = "画像保存") let resize _ = 100 * webBrowser.Width / browserWidth |> zoom webBrowser @@ -1081,7 +1055,8 @@ let mainWindow () = createForm (browserWidth + 181) 668 "艦これ 司令部室" let tweet = new Button(Location = Point(browserWidth + 91, 548), Anchor = anchorTR, Text = "呟く") tweet.Click.Add(fun _ -> tweetImage webBrowser form) - let capture = new Button(Location = Point(browserWidth + 10, 576), Anchor = anchorTR, Text = "動画保存", Enabled = Capture.supported ()) + let capture = new Button(Location = Point(browserWidth + 10, 576), Anchor = anchorTR, Text = "動画保存", Enabled = false) +#if false capture.Click.Add(let state = ref None in fun _ -> match !state with | None -> @@ -1108,6 +1083,7 @@ let mainWindow () = createForm (browserWidth + 181) 668 "艦これ 司令部室" state := None } |> Async.StartImmediate ) +#endif let clear = new Button(Location = Point(browserWidth + 91, 576), Anchor = anchorTR, Text = "クリア") clear.Click.Add(fun _ -> @@ -1181,10 +1157,7 @@ let action path = Slotitem.UpdateItems() Mission.UpdateDecks() let addSlotitem (item : IDictionary<_, _>) = - let slotitem_id = getNumber item.["api_slotitem_id"] - let alv = match item.TryGetValue "api_alv" with true, JsonNumber alv -> Some alv | _ -> None - let level = getNumber item.["api_level"] - slotitems.Add(getNumber item.["api_id"], (slotitem_id, alv, level)) + slotitems.Add(getNumber item.["api_id"], (getNumber item.["api_slotitem_id"], match item.TryGetValue "api_alv" with true, JsonNumber alv -> Some alv | _, _ -> None)) let mission key json = decks <- get key json |> getArray @@ -1198,7 +1171,7 @@ let action path = let basic key data = let data = get key data |> getObject maxCount <- getNumber data.["api_max_chara"] |> int, (getNumber data.["api_max_slotitem"] |> int) + 3 - hqLevel <- getNumber data.["api_level"] + hqLevel <- getNumber data.["api_level"] |> int let slot_item key data = let items = get key data |> getArray |> Array.map getObject lock slotitems (fun () -> slotitems.Clear() @@ -1229,7 +1202,7 @@ let action path = Slotitem.UpdateItems() match path with - | "/kcsapi/api_start2" -> + | "/kcsapi/api_start2/getData" -> Some(fun req res -> let data = parseJson res |> get "api_data" |> getObject let update (master : Dictionary<_, _>) key = @@ -1437,7 +1410,7 @@ let main argv = let onResponse = OnResponse(fun path req reqlen res reslen -> agent.Post (path, req, res)) let onRequestHandle = GCHandle.Alloc onRequest let onResponseHandle = GCHandle.Alloc onResponse - SetCallback(onRequest, onResponse) + ZzzSetCallback(onRequest, onResponse) #endif mainWindow () |> Application.Run diff --git a/KanHQ.fsproj b/KanHQ.fsproj index aca80b2..03534ab 100644 --- a/KanHQ.fsproj +++ b/KanHQ.fsproj @@ -9,9 +9,8 @@ WinExe KanHQ KanHQ - v2.0 + v4.7.2 true - 2.3.0.0 KanHQ KanHQ.res 3 @@ -25,6 +24,7 @@ false TRACE;DEBUG bin\Debug\ + false pdbonly @@ -32,6 +32,7 @@ true TRACE bin\Release\ + false KanHQLight @@ -40,6 +41,7 @@ true TRACE;LIGHT bin\LightRelease\ + false 11 @@ -98,12 +100,13 @@ + - - - True + + packages\FSharp.Core.4.5.2\lib\net45\FSharp.Core.dll + diff --git a/Readme.txt b/Readme.txt index 54c0c6f..10ec0eb 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,13 +1,16 @@ 艦これ 司令部室 -Version 1.1.0.0 -2016/09/25 +Version 2.0.0.0 +2018/08/25 このソフトは艦これ専用ブラウザーです。 -.NET Framework 2.0以降を使用しています。 -IEコンポーネントを使用しています。そのため、IE向けFlash Playerをインストールする必要があります。 -エラーが発生した場合、デスクトップにKanHQ.txtというファイル名で情報を書き出します。この内容を -教えてもらえると原因究明がはかどります。 +Windows 7以降で動作します。Windows Updateで提供されている次のコンポーネントを事 +前にインストールしてください。 + .NET Framework 4.7.2 + Internet Explorer 11(Windows 7の場合) +本バージョンでは動画保存、消音機能は未実装となります。 +エラーが発生した場合、デスクトップにKanHQ.txtというファイル名で情報を書き出しま +す。この内容を教えてもらえると原因究明がはかどります。 欲しい物リストを公開しています。応援してもらえるといろいろはかどります。 diff --git a/WININET/WININET.cpp b/WININET/WININET.cpp index 3a80a9e..b0b4166 100644 --- a/WININET/WININET.cpp +++ b/WININET/WININET.cpp @@ -1,43 +1,55 @@ -#define _USING_V110_SDK71_ // for xp #define _WINX32_ // don't import WinInet.h and Winineti.h #define WIN32_LEAN_AND_MEAN // avoid Winsock +#define NOMINMAX // for std::min #define _HAS_EXCEPTIONS 0 -#include // for std::copy_n -#include // for std::make_unique, std::unique_ptr +#include // for std::copy_n, std::equal +#include // for std::ofstream +#include // for std::map #include // for std::lock_guard, std::mutex +#include // for std::optional +#include // for std::wregex, std::wsmatch, std::regex_search #include // for std::wstring -#include // for std::unordered_map +#include // for ""sv #include // for std::vector #include // for _ASSERTE, _RPTW0, _RPTWN #include #include // for SOCKET #include #include +using namespace std::literals; #define DLLNAME "WININET.dll" #include "../callproc.h" +template +static constexpr auto size_as(Data const& data) { + return static_cast(std::size(data)); +} + static inline void append(std::vector& buffer, const void* src, std::size_t count) { buffer.resize(size(buffer) + count); std::copy_n(reinterpret_cast(src), count, begin(buffer) + size(buffer) - count); } -class char2wchar { - std::unique_ptr buffer; -public: - char2wchar(const char* src) { - if (!src) - return; - auto length = MultiByteToWideChar(CP_THREAD_ACP, 0, src, -1, nullptr, 0); - buffer = std::make_unique(length); - auto result = MultiByteToWideChar(CP_THREAD_ACP, 0, src, -1, buffer.get(), length); - _ASSERTE(result == length); - } - operator const wchar_t*() const { - return buffer ? buffer.get() : nullptr; +struct LastError { + DWORD value = GetLastError(); + ~LastError() { + SetLastError(value); } }; +static auto to_wstring(const char* str) { + std::wstring wstr; + if (str) { + auto len = static_cast(strlen(str)); + auto wlen1 = MultiByteToWideChar(CP_THREAD_ACP, 0, str, len, nullptr, 0); + wstr.resize(wlen1); + auto wlen2 = MultiByteToWideChar(CP_THREAD_ACP, 0, str, len, data(wstr), wlen1); + _ASSERTE(wlen1 == wlen2); + } + return wstr; +} + static bool (CALLBACK* OnRequest)(const wchar_t* path) = nullptr; static void (CALLBACK* OnResponse)(const wchar_t* path, const unsigned char* request, unsigned requestSize, const unsigned char* response, unsigned responseSize) = nullptr; @@ -46,21 +58,27 @@ struct session { std::wstring path; std::vector request; std::vector response; - session(const wchar_t* path) : path(path) {} + session(std::wstring const& path) : path(path) {} }; -static std::unordered_map sessions; +static std::map sessions; +static std::optional>> injectTarget; -void STDAPICALLTYPE SetCallback(decltype(OnRequest) onRequest, decltype(OnResponse) onResponse) { +void STDAPICALLTYPE ZzzSetCallback(decltype(OnRequest) onRequest, decltype(OnResponse) onResponse) { DLLEXPORT; OnRequest = onRequest; OnResponse = onResponse; } -static void addSession(HINTERNET file, const wchar_t* path) { - if (file && OnRequest && OnRequest(path)) { - std::lock_guard lock(mutex); - sessions.emplace(file, path); - _RPTWN(_CRT_WARN, L"WININET: active sessions = %d\n", sessions.size()); +static void addSession(HINTERNET file, std::wstring const& path) { + if (file) { + if (OnRequest && OnRequest(path.c_str())) { + std::lock_guard lock(mutex); + sessions.emplace(file, path); + _RPTWN(_CRT_WARN, L"WININET: active sessions = %d\n", sessions.size()); + } + static auto target = L"/kcs2/index.php"s; + if (size(target) < size(path) && std::equal(begin(target), end(target), begin(path))) + injectTarget = { file, {} }; } } @@ -76,6 +94,17 @@ static void addRequest(BOOL result, HINTERNET hRequest, LPVOID lpOptional, DWORD } static void callOnResponse(const decltype(sessions)::iterator& itor) { +#if 0 + static std::wregex re{ LR"(^/(?:[^/?]+/)*([^/?]+))" }; + static int index = 0; + { + std::wsmatch m; + std::regex_search(itor->second.path, m, re); + auto filename = m[1].str() + L'-' + std::to_wstring(index++); + _RPTWN(_CRT_WARN, L"WININET: write %s => %s\n", itor->second.path.c_str(), filename.c_str()); + std::ofstream{ filename }.write(reinterpret_cast(data(itor->second.response)), size(itor->second.response)); + } +#endif if (OnResponse) { auto& request = itor->second.request; auto& response = itor->second.response; @@ -92,7 +121,7 @@ INTERNETAPI_(HINTERNET) HttpOpenRequestA(_In_ HINTERNET hConnect, _In_opt_ LPCST _RPTWN(_CRT_WARN, L"WININET: HttpOpenRequestA(%S %S)\n", lpszVerb, lpszObjectName); auto file = CALLFUNC(HttpOpenRequestA, hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext); auto lastError = GetLastError(); - addSession(file, char2wchar(lpszObjectName)); + addSession(file, to_wstring(lpszObjectName)); SetLastError(lastError); return file; } @@ -100,9 +129,9 @@ INTERNETAPI_(HINTERNET) HttpOpenRequestA(_In_ HINTERNET hConnect, _In_opt_ LPCST INTERNETAPI_(HINTERNET) HttpOpenRequestW(_In_ HINTERNET hConnect, _In_opt_ LPCWSTR lpszVerb, _In_opt_ LPCWSTR lpszObjectName, _In_opt_ LPCWSTR lpszVersion, _In_opt_ LPCWSTR lpszReferrer, _In_opt_z_ LPCWSTR FAR * lplpszAcceptTypes, _In_ DWORD dwFlags, _In_opt_ DWORD_PTR dwContext) { DLLEXPORT; - _RPTWN(_CRT_WARN, L"WININET: HttpOpenRequestW(%s %s)\n", lpszVerb, lpszObjectName); auto file = CALLFUNC(HttpOpenRequestW, hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext); auto lastError = GetLastError(); + _RPTWN(_CRT_WARN, L"WININET: HttpOpenRequestW(%s %s) => 0x%08x\n", lpszVerb, lpszObjectName, file); addSession(file, lpszObjectName); SetLastError(lastError); return file; @@ -120,67 +149,114 @@ BOOLAPI HttpSendRequestA(_In_ HINTERNET hRequest, _In_reads_opt_(dwHeadersLength BOOLAPI HttpSendRequestW(_In_ HINTERNET hRequest, _In_reads_opt_(dwHeadersLength) LPCWSTR lpszHeaders, _In_ DWORD dwHeadersLength, _In_reads_bytes_opt_(dwOptionalLength) LPVOID lpOptional, _In_ DWORD dwOptionalLength) { DLLEXPORT; - _RPTWN(_CRT_WARN, L"WININET: HttpSendRequestW(opt=%d)\n", dwOptionalLength); + _RPTWN(_CRT_WARN, L"WININET: HttpSendRequestW(0x%08x, opt=%d)\n", hRequest, dwOptionalLength); auto result = CALLFUNC(HttpSendRequestW, hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength); addRequest(result, hRequest, lpOptional, dwOptionalLength); return result; } +BOOLAPI InternetSetOptionA(_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength) { + DLLEXPORT; + + _RPTWN(_CRT_WARN, L"WININET: InternetSetOptionA(0x%08x, %d) called\n", hInternet, dwOption); + return CALLFUNC(InternetSetOptionA, hInternet, dwOption, lpBuffer, dwBufferLength); +} + +BOOLAPI InternetSetOptionW(_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength) { + DLLEXPORT; + + _RPTWN(_CRT_WARN, L"WININET: InternetSetOptionW(0x%08x, %d) called\n", hInternet, dwOption); + return CALLFUNC(InternetSetOptionW, hInternet, dwOption, lpBuffer, dwBufferLength); +} + BOOLAPI InternetReadFile(_In_ HINTERNET hFile, _Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer, _In_ DWORD dwNumberOfBytesToRead, _Out_ LPDWORD lpdwNumberOfBytesRead) { DLLEXPORT; + if (injectTarget) + if (auto& [injectHandle, rest] = *injectTarget; injectHandle == hFile) { + _RPTWN(_CRT_WARN, L"WININET: InternetReadFile(0x%08x) injected\n", hFile); + _ASSERTE(rest && lpBuffer && 0 < dwNumberOfBytesToRead && lpdwNumberOfBytesRead); + dwNumberOfBytesToRead = std::min(dwNumberOfBytesToRead, size_as(*rest)); + std::copy_n(rest->begin(), dwNumberOfBytesToRead, reinterpret_cast(lpBuffer)); + *lpdwNumberOfBytesRead = dwNumberOfBytesToRead; + rest->erase(0, dwNumberOfBytesToRead); + SetLastError(0); + return true; + } + auto result = CALLFUNC(InternetReadFile, hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead); - auto lastError = GetLastError(); - { - std::lock_guard lock(mutex); - auto itor = sessions.find(hFile); - if (itor != sessions.end()) { - _RPTWN(_CRT_WARN, L"WININET: InternetReadFile(%d => %d, %s, %d) => %d, %d\n", dwNumberOfBytesToRead, *lpdwNumberOfBytesRead, itor->second.path.c_str(), itor->second.response.size(), result, lastError); - if (result) { - auto read = *lpdwNumberOfBytesRead; - if (0 < read) - append(itor->second.response, lpBuffer, read); - else - callOnResponse(itor); - } else - sessions.erase(itor); - } else - _RPTWN(_CRT_WARN, L"WININET: InternetReadFile(%d => %d) %d, %d\n", dwNumberOfBytesToRead, *lpdwNumberOfBytesRead, result, lastError); + LastError err; + std::lock_guard lock{ mutex }; + _RPTWN(_CRT_WARN, L"WININET: InternetReadFile(0x%08x, %d) %d, %d, %d\n", hFile, dwNumberOfBytesToRead, result, err.value, lpdwNumberOfBytesRead ? *lpdwNumberOfBytesRead : -1); + if (auto itor = sessions.find(hFile); itor != sessions.end()) { + if (!result) + sessions.erase(itor); + else if (0 < *lpdwNumberOfBytesRead) + append(itor->second.response, lpBuffer, *lpdwNumberOfBytesRead); + else + callOnResponse(itor); } - SetLastError(lastError); return result; } BOOLAPI InternetQueryDataAvailable(_In_ HINTERNET hFile, _Out_opt_ __out_data_source(NETWORK) LPDWORD lpdwNumberOfBytesAvailable, _In_ DWORD dwFlags, _In_opt_ DWORD_PTR dwContext) { DLLEXPORT; - auto result = CALLFUNC(InternetQueryDataAvailable, hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext); - auto lastError = GetLastError(); - if (result && *lpdwNumberOfBytesAvailable == 0) { - std::lock_guard lock(mutex); - auto itor = sessions.find(hFile); - if (itor != sessions.end()) { - _RPTWN(_CRT_WARN, L"WININET: InternetQueryDataAvailable(%d, %s) => %d, %d\n", *lpdwNumberOfBytesAvailable, itor->second.path.c_str(), result, lastError); + if (injectTarget) + if (auto& [injectHandle, rest] = *injectTarget; injectHandle == hFile) { + if (!rest) { + rest = ""s; + for (DWORD available, read;;) { + auto result = CALLFUNC(InternetQueryDataAvailable, hFile, &available, dwFlags, dwContext); + _ASSERTE(result); + if (available == 0) + break; + rest->resize(rest->size() + available); + result = CALLFUNC(InternetReadFile, hFile, rest->data() + rest->size() - available, available, &read); + _ASSERTE(result && read == available); + } + auto original = size_as(*rest); + // https://github.com/axios/axios/blob/master/UPGRADE_GUIDE.md#05x---060 + // "the polyfill has been removed, and you will need to supply it yourself if your environment needs it." + *rest = std::regex_replace(*rest, std::regex{ R"()" }, + R"($&)"); + // WebOC on Win7 has PointerEvent exists, but navigator.msPointerEnabled is false. + // enable preserveDrawingBuffer for capturing. + *rest = std::regex_replace(*rest, std::regex{ R"()" }, + R"($&)"); + _RPTWN(_CRT_WARN, L"WININET: InternetQueryDataAvailable(0x%08x) injected %d to %d\n", hFile, original, size_as(*rest)); + } + if (lpdwNumberOfBytesAvailable) + *lpdwNumberOfBytesAvailable = size_as(*rest); + SetLastError(0); + return true; + } + + DWORD available; + auto result = CALLFUNC(InternetQueryDataAvailable, hFile, &available, dwFlags, dwContext); + if (lpdwNumberOfBytesAvailable) + *lpdwNumberOfBytesAvailable = available; + LastError err; + _RPTWN(_CRT_WARN, L"WININET: InternetQueryDataAvailable(0x%08x) => %d, %d, %d\n", hFile, result, err.value, available); + if (result && available == 0) { + std::lock_guard lock{ mutex }; + if (auto itor = sessions.find(hFile); itor != sessions.end()) callOnResponse(itor); - } else - _RPTWN(_CRT_WARN, L"WININET: InternetQueryDataAvailable(%d) => %d, %d\n", *lpdwNumberOfBytesAvailable, result, lastError); } - SetLastError(lastError); return result; } BOOLAPI InternetCloseHandle(_In_ HINTERNET hInternet) { DLLEXPORT; + _RPTWN(_CRT_WARN, L"WININET: InternetCloseHandle(0x%08x)\n", hInternet); { - std::lock_guard lock(mutex); - auto itor = sessions.find(hInternet); - if (itor != sessions.end()) { - _RPTWN(_CRT_WARN, L"WININET: InternetCloseHandle(%s)\n", itor->second.path.c_str()); + std::lock_guard lock{ mutex }; + if (auto itor = sessions.find(hInternet); itor != sessions.end()) callOnResponse(itor); - } else - _RPTW0(_CRT_WARN, L"WININET: InternetCloseHandle()\n"); } + if (injectTarget && std::get<0>(*injectTarget) == hInternet) + injectTarget.reset(); return CALLFUNC(InternetCloseHandle, hInternet); } @@ -227,7 +303,7 @@ FUNCTION_NAME(BOOLAPI, DetectAutoProxyUrl, (_Out_writes_(cchAutoProxyUrl) PSTR p FUNCTION_NAME_ORDINAL(106, void CALLBACK, DispatchAPICall, (HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow), hwnd, hinst, lpszCmdLine, nCmdShow) FUNCTION_NAME(STDAPI, DllCanUnloadNow, (void), ) FUNCTION_NAME(STDAPI, DllGetClassObject, (_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv), rclsid, riid, ppv) -FUNCTION_NAME(STDAPI, DllInstall, (BOOL bInstall, _In_opt_ PCWSTR pszCmdLine), bInstall, pszCmdLine) +FUNCTION_UNKNOWN_NAME(STDAPI, DllInstall, (BOOL bInstall, _In_opt_ PCWSTR pszCmdLine), bInstall, pszCmdLine) FUNCTION_NAME(STDAPI, DllRegisterServer, (void), ) FUNCTION_NAME(STDAPI, DllUnregisterServer, (void), ) FUNCTION_NAME(BOOLAPI, FindCloseUrlCache, (_In_ HANDLE hEnumHandle), hEnumHandle) @@ -305,6 +381,7 @@ FUNCTION_NAME(BOOLAPI, HttpEndRequestA, (_In_ HINTERNET hRequest, _Out_opt_ LPIN FUNCTION_NAME(BOOLAPI, HttpEndRequestW, (_In_ HINTERNET hRequest, _Out_opt_ LPINTERNET_BUFFERSW lpBuffersOut, _In_ DWORD dwFlags, _In_opt_ DWORD_PTR dwContext), hRequest, lpBuffersOut, dwFlags, dwContext) FUNCTION_NAME(INTERNETAPI_(DWORD), HttpGetServerCredentials, (_In_ PWSTR pwszUrl, _Outptr_result_z_ PWSTR *ppwszUserName, _Outptr_result_z_ PWSTR *ppwszPassword), pwszUrl, ppwszUserName, ppwszPassword) FUNCTION_NAME(INTERNETAPI_(DWORD), HttpGetTunnelSocket, (_In_ HINTERNET hRequest, _Out_ SOCKET *pSocket, _Outptr_result_buffer_all_maybenull_(*pdwDataLength) PBYTE *ppbData, _Out_ PDWORD pdwDataLength), hRequest, pSocket, ppbData, pdwDataLength) +FUNCTION_NAME(INTERNETAPI_(DWORD), HttpIndicatePageLoadComplete, (_In_ HTTP_DEPENDENCY_HANDLE hDependencyHandle), hDependencyHandle) FUNCTION_UNKNOWN_NAME(INTERNETAPI_(DWORD), HttpIsHostHstsEnabled, (_In_z_ PCWSTR pcwszUrl, _Out_ PBOOL pfIsHsts), pcwszUrl, pfIsHsts) FUNCTION_NAME(INTERNETAPI_(DWORD), HttpOpenDependencyHandle, (_In_ HINTERNET hRequestHandle, _In_ BOOL fBackground, _Outptr_ HTTP_DEPENDENCY_HANDLE *phDependencyHandle), hRequestHandle, fBackground, phDependencyHandle) //HttpOpenRequestA @@ -345,6 +422,7 @@ FUNCTION_NAME(INTERNETAPI_(DWORD), InternetConfirmZoneCrossingA, (_In_ HWND hWnd FUNCTION_NAME(INTERNETAPI_(DWORD), InternetConfirmZoneCrossingW, (_In_ HWND hWnd, _In_ LPWSTR szUrlPrev, _In_ LPWSTR szUrlNew, _In_ BOOL bPost), hWnd, szUrlPrev, szUrlNew, bPost) FUNCTION_NAME(INTERNETAPI_(HINTERNET), InternetConnectA, (_In_ HINTERNET hInternet, _In_ LPCSTR lpszServerName, _In_ INTERNET_PORT nServerPort, _In_opt_ LPCSTR lpszUserName, _In_opt_ LPCSTR lpszPassword, _In_ DWORD dwService, _In_ DWORD dwFlags, _In_opt_ DWORD_PTR dwContext), hInternet, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwService, dwFlags, dwContext) FUNCTION_NAME(INTERNETAPI_(HINTERNET), InternetConnectW, (_In_ HINTERNET hInternet, _In_ LPCWSTR lpszServerName, _In_ INTERNET_PORT nServerPort, _In_opt_ LPCWSTR lpszUserName, _In_opt_ LPCWSTR lpszPassword, _In_ DWORD dwService, _In_ DWORD dwFlags, _In_opt_ DWORD_PTR dwContext), hInternet, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwService, dwFlags, dwContext) +FUNCTION_NAME(STDAPI_(DWORD), InternetConvertUrlFromWireToWideChar, (_In_reads_(cchUrl) PCSTR pcszUrl, _In_ DWORD cchUrl, _In_ PCWSTR pcwszBaseUrl, _In_ DWORD dwCodePageHost, _In_ DWORD dwCodePagePath, _In_ BOOL fEncodePathExtra, _In_ DWORD dwCodePageExtra, _Outptr_result_z_ PWSTR *ppwszConvertedUrl), pcszUrl, cchUrl, pcwszBaseUrl, dwCodePageHost, dwCodePagePath, fEncodePathExtra, dwCodePageExtra, ppwszConvertedUrl) FUNCTION_NAME(BOOLAPI, InternetCrackUrlA, (_In_reads_(dwUrlLength) LPCSTR lpszUrl, _In_ DWORD dwUrlLength, _In_ DWORD dwFlags, _Inout_ LPURL_COMPONENTSA lpUrlComponents), lpszUrl, dwUrlLength, dwFlags, lpUrlComponents) FUNCTION_NAME(BOOLAPI, InternetCrackUrlW, (_In_reads_(dwUrlLength) LPCWSTR lpszUrl, _In_ DWORD dwUrlLength, _In_ DWORD dwFlags, _Inout_ LPURL_COMPONENTSW lpUrlComponents), lpszUrl, dwUrlLength, dwFlags, lpUrlComponents) FUNCTION_NAME(BOOLAPI, InternetCreateUrlA, (_In_ LPURL_COMPONENTSA lpUrlComponents, _In_ DWORD dwFlags, _Out_writes_opt_(*lpdwUrlLength) LPSTR lpszUrl, _Inout_ LPDWORD lpdwUrlLength), lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength) @@ -412,10 +490,10 @@ FUNCTION_NAME(BOOLAPI, InternetSetDialState, (_In_opt_ LPCSTR lpszConnectoid, _I FUNCTION_NAME(BOOLAPI, InternetSetDialStateA, (_In_opt_ LPCSTR lpszConnectoid, _In_ DWORD dwState, _Reserved_ DWORD dwReserved), lpszConnectoid, dwState, dwReserved) FUNCTION_NAME(BOOLAPI, InternetSetDialStateW, (_In_opt_ LPCWSTR lpszConnectoid, _In_ DWORD dwState, _Reserved_ DWORD dwReserved), lpszConnectoid, dwState, dwReserved) FUNCTION_NAME(INTERNETAPI_(DWORD), InternetSetFilePointer, (_In_ HINTERNET hFile, _In_ LONG lDistanceToMove, _Inout_opt_ PLONG lpDistanceToMoveHigh, _In_ DWORD dwMoveMethod, _Reserved_ DWORD_PTR dwContext), hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod, dwContext) -FUNCTION_NAME(BOOLAPI, InternetSetOptionA, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength), hInternet, dwOption, lpBuffer, dwBufferLength) +//FUNCTION_NAME(BOOLAPI, InternetSetOptionA, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength), hInternet, dwOption, lpBuffer, dwBufferLength) FUNCTION_NAME(BOOLAPI, InternetSetOptionExA, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength, _In_ DWORD dwFlags), hInternet, dwOption, lpBuffer, dwBufferLength, dwFlags) FUNCTION_NAME(BOOLAPI, InternetSetOptionExW, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength, _In_ DWORD dwFlags), hInternet, dwOption, lpBuffer, dwBufferLength, dwFlags) -FUNCTION_NAME(BOOLAPI, InternetSetOptionW, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength), hInternet, dwOption, lpBuffer, dwBufferLength) +//FUNCTION_NAME(BOOLAPI, InternetSetOptionW, (_In_opt_ HINTERNET hInternet, _In_ DWORD dwOption, _In_opt_ LPVOID lpBuffer, _In_ DWORD dwBufferLength), hInternet, dwOption, lpBuffer, dwBufferLength) FUNCTION_NAME(BOOLAPI, InternetSetPerSiteCookieDecisionA, (_In_ LPCSTR pchHostName, _In_ DWORD dwDecision), pchHostName, dwDecision) FUNCTION_NAME(BOOLAPI, InternetSetPerSiteCookieDecisionW, (_In_ LPCWSTR pchHostName, _In_ DWORD dwDecision), pchHostName, dwDecision) #undef InternetSetStatusCallback @@ -465,7 +543,7 @@ FUNCTION_NAME(BOOLAPI, SetUrlCacheEntryInfoW, (_In_ LPCWSTR lpszUrlName, _In_ LP FUNCTION_NAME(BOOLAPI, SetUrlCacheGroupAttributeA, (_In_ GROUPID gid, _Reserved_ DWORD dwFlags, _In_ DWORD dwAttributes, _In_ LPINTERNET_CACHE_GROUP_INFOA lpGroupInfo, _Reserved_ LPVOID lpReserved), gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved) FUNCTION_NAME(BOOLAPI, SetUrlCacheGroupAttributeW, (_In_ GROUPID gid, _Reserved_ DWORD dwFlags, _In_ DWORD dwAttributes, _In_ LPINTERNET_CACHE_GROUP_INFOW lpGroupInfo, _Reserved_ LPVOID lpReserved), gid, dwFlags, dwAttributes, lpGroupInfo, lpReserved) FUNCTION_NAME(BOOLAPI, SetUrlCacheHeaderData, (_In_ DWORD nIdx, _In_ DWORD dwData), nIdx, dwData) -FUNCTION_UNKNOWN_NAME(INTERNETAPI_(void), ShowCertificate, (void), ) +FUNCTION_UNKNOWN_NAME(INTERNETAPI_(DWORD), ShowCertificate, (DWORD arg0, DWORD arg1), arg0, arg1) FUNCTION_NAME(INTERNETAPI_(DWORD), ShowClientAuthCerts, (_In_ HWND hWndParent), hWndParent) FUNCTION_NAME(INTERNETAPI_(DWORD), ShowSecurityInfo, (_In_ HWND hWndParent, _In_ LPINTERNET_SECURITY_INFO pSecurityInfo), hWndParent, pSecurityInfo) FUNCTION_NAME(INTERNETAPI_(DWORD), ShowX509EncodedCertificate, (_In_ HWND hWndParent, _In_reads_bytes_(cbCert) LPBYTE lpCert, _In_ DWORD cbCert), hWndParent, lpCert, cbCert) @@ -495,10 +573,13 @@ FUNCTION_UNKNOWN_NAME(INTERNETAPI_(DWORD), UrlCacheServer, (void), ) FUNCTION_NAME(URLCACHEAPI, UrlCacheSetGlobalLimit, (_In_ URL_CACHE_LIMIT_TYPE limitType, _In_ ULONGLONG ullLimit), limitType, ullLimit) FUNCTION_NAME(URLCACHEAPI, UrlCacheUpdateEntryExtraData, (_In_opt_ APP_CACHE_HANDLE hAppCache, _In_ PCWSTR pcwszUrl, _In_reads_bytes_(cbExtraData) const BYTE *pbExtraData, _In_ DWORD cbExtraData), hAppCache, pcwszUrl, pbExtraData, cbExtraData) FUNCTION_UNKNOWN_NAME(INTERNETAPI_(DWORD), UrlZonesDetach, (void), ) -#ifdef _M_IX86 /* at x86, first '_' is removed. so add extra '_'. */ -#define _GetFileExtensionFromUrl __GetFileExtensionFromUrl +#ifdef _M_IX86 +#define PREFIX "_" +#else +#define PREFIX "" #endif -FUNCTION_NAME(INTERNETAPI_(DWORD), _GetFileExtensionFromUrl, (_In_ LPSTR lpszUrl, _In_ DWORD dwFlags, _Inout_updates_bytes_(*pcchExt) LPSTR lpszExt, _Inout_ DWORD *pcchExt), lpszUrl, dwFlags, lpszExt, pcchExt) +FUNCTION(PREFIX __FUNCTION__ "=" __FUNCDNAME__, __FUNCTION__, INTERNETAPI_(DWORD), _GetFileExtensionFromUrl, (_In_ LPSTR lpszUrl, _In_ DWORD dwFlags, _Inout_updates_bytes_(*pcchExt) LPSTR lpszExt, _Inout_ DWORD *pcchExt), lpszUrl, dwFlags, lpszExt, pcchExt) +#undef PREFIX FUNCTION_NONAME(101, BOOL, DoConnectoidsExist, (void), ) FUNCTION_NONAME(102, BOOLAPI, GetDiskInfoA, (_In_ PCSTR pszPath, _Out_opt_ PDWORD pdwClusterSize, _Out_opt_ PDWORDLONG pdlAvail, _Out_opt_ PDWORDLONG pdlTotal), pszPath, pdwClusterSize, pdlAvail, pdlTotal) FUNCTION_NONAME(103, BOOL, PerformOperationOverUrlCacheA, (_In_opt_ PCSTR pszUrlSearchPattern, _In_ DWORD dwFlags, _In_ DWORD dwFilter, _In_ GROUPID GroupId, _Reserved_ PVOID pReserved1, _Reserved_ PDWORD pdwReserved2, _Reserved_ PVOID pReserved3, _In_ CACHE_OPERATOR op, _Inout_ PVOID pOperatorData), pszUrlSearchPattern, dwFlags, dwFilter, GroupId, pReserved1, pdwReserved2, pReserved3, op, pOperatorData) @@ -512,19 +593,19 @@ FUNCTION_UNKNOWN_NONAME(112, INTERNETAPI_(int), CHttp2Stream_ConnLimitExempted, FUNCTION_NONAME(116, BOOLAPI, IsDomainLegalCookieDomainA, (_In_ LPCSTR pchDomain, _In_ LPCSTR pchFullDomain), pchDomain, pchFullDomain) FUNCTION_NONAME(117, BOOLAPI, IsDomainLegalCookieDomainW, (_In_ LPCWSTR pchDomain, _In_ LPCWSTR pchFullDomain), pchDomain, pchFullDomain) FUNCTION_NONAME(118, INTERNETAPI_(int), FindP3PPolicySymbol, (_In_ const char *pszSymbol), pszSymbol) -FUNCTION_UNKNOWN_NONAME(120, INTERNETAPI_(void), MapResourceToPolicy, (void), ) -FUNCTION_UNKNOWN_NONAME(121, INTERNETAPI_(void), GetP3PPolicy, (void), ) -FUNCTION_UNKNOWN_NONAME(122, INTERNETAPI_(void), FreeP3PObject, (void), ) -FUNCTION_UNKNOWN_NONAME(123, INTERNETAPI_(void), GetP3PRequestStatus, (void), ) +FUNCTION_UNKNOWN_NONAME(120, INTERNETAPI_(void), GetP3PPolicy1, (DWORD arg0, DWORD arg1, DWORD arg2, DWORD arg3), arg0, arg1, arg2, arg3) +FUNCTION_UNKNOWN_NONAME(121, INTERNETAPI_(void), GetP3PPolicy2, (DWORD arg0, DWORD arg1, DWORD arg2, DWORD arg3), arg0, arg1, arg2, arg3) +FUNCTION_UNKNOWN_NONAME(122, INTERNETAPI_(void), FreeP3PObject1, (DWORD arg0), arg0) +FUNCTION_UNKNOWN_NONAME(123, INTERNETAPI_(void), FreeP3PObject2, (DWORD arg0), arg0) FUNCTION_NONAME(346, INTERNETAPI_(DWORD), InternalInternetGetCookie, (_In_ LPCSTR lpszUrl, _Out_writes_(*lpdwDataSize) LPSTR lpszCookieData, _Inout_ DWORD *lpdwDataSize), lpszUrl, lpszCookieData, lpdwDataSize) FUNCTION_NONAME(401, BOOLAPI, ReadGuidsForConnectedNetworks, (_Out_opt_ DWORD *pcNetworks, _Out_opt_ PWSTR **pppwszNetworkGuids, _Out_opt_ BSTR **pppbstrNetworkNames, _Out_opt_ PWSTR **pppwszGWMacs, _Out_opt_ DWORD *pcGatewayMacs, _Out_opt_ DWORD *pdwFlags), pcNetworks, pppwszNetworkGuids, pppbstrNetworkNames, pppwszGWMacs, pcGatewayMacs, pdwFlags) -FUNCTION_UNKNOWN_NONAME(402, INTERNETAPI_(DWORD), InternetAutoProxyGetProxyForUrl, (void), ) -FUNCTION_UNKNOWN_NONAME(403, INTERNETAPI_(DWORD), InternetAutoProxyOnSendRequestComplete, (void), ) -FUNCTION_UNKNOWN_NONAME(410, INTERNETAPI_(DWORD), GetCacheServerConnection, (void), ) -FUNCTION_UNKNOWN_NONAME(411, INTERNETAPI_(DWORD), CreateCacheServerRpcBinding, (void), ) +FUNCTION_UNKNOWN_NONAME(402, INTERNETAPI_(DWORD), InternetAutoProxyGetProxyForUrl, (DWORD arg0, DWORD arg1), arg0, arg1) +FUNCTION_UNKNOWN_NONAME(403, INTERNETAPI_(DWORD), InternetAutoProxyOnSendRequestComplete, (DWORD arg0, DWORD arg1, DWORD arg2), arg0, arg1, arg2) +FUNCTION_UNKNOWN_NONAME(410, INTERNETAPI_(DWORD), GetCacheServerConnection, (DWORD arg0), arg0) +FUNCTION_UNKNOWN_NONAME(411, INTERNETAPI_(DWORD), CreateCacheServerRpcBinding, (DWORD arg0, DWORD arg1), arg0, arg1) FUNCTION_UNKNOWN_NONAME(413, INTERNETAPI_(DWORD), SetGlobalJetParameters, (void), ) FUNCTION_NONAME(420, INTERNETAPI_(DWORD), IsLanConnection, (DWORD arg0), arg0) -FUNCTION_UNKNOWN_NONAME(421, INTERNETAPI_(DWORD), IsDialUpConnection, (void), ) -FUNCTION_UNKNOWN_NONAME(422, INTERNETAPI_(DWORD), RegisterForNetworkChangeNotification, (void), ) -FUNCTION_UNKNOWN_NONAME(423, INTERNETAPI_(DWORD), UnRegisterNetworkChangeNotification, (void), ) +FUNCTION_UNKNOWN_NONAME(421, INTERNETAPI_(DWORD), IsDialUpConnection, (DWORD arg0), arg0) +FUNCTION_UNKNOWN_NONAME(422, INTERNETAPI_(DWORD), RegisterForNetworkChangeNotification, (DWORD arg0, DWORD arg1, DWORD arg2), arg0, arg1, arg2) +FUNCTION_UNKNOWN_NONAME(423, INTERNETAPI_(DWORD), UnRegisterNetworkChangeNotification, (DWORD arg0), arg0) #pragma endregion diff --git a/WININET/WININET.rc b/WININET/WININET.rc index 2e933c4..60477a1 100644 Binary files a/WININET/WININET.rc and b/WININET/WININET.rc differ diff --git a/WININET/WININET.vcxproj b/WININET/WININET.vcxproj index cc4c180..5718076 100644 --- a/WININET/WININET.vcxproj +++ b/WININET/WININET.vcxproj @@ -22,32 +22,32 @@ {B6C56786-EDAB-4E2A-8570-C3C17DACEA75} Win32Proj WININET - 10.0.14393.0 + 10.0.17134.0 DynamicLibrary true - v140 + v141 Unicode DynamicLibrary true - v140 + v141 Unicode DynamicLibrary false - v140 + v141 true Unicode DynamicLibrary false - v140 + v141 true Unicode @@ -93,6 +93,9 @@ false ProgramDatabase /Zc:threadSafeInit- %(AdditionalOptions) + true + stdcpp17 + StdCall true @@ -112,6 +115,9 @@ false ProgramDatabase /Zc:threadSafeInit- %(AdditionalOptions) + true + stdcpp17 + StdCall true @@ -131,6 +137,9 @@ false /Zc:threadSafeInit- %(AdditionalOptions) true + true + stdcpp17 + StdCall true @@ -152,6 +161,9 @@ false /Zc:threadSafeInit- %(AdditionalOptions) true + true + stdcpp17 + StdCall true diff --git a/WebBrowser2.fs b/WebBrowser2.fs index 7d58695..ccc4b66 100644 --- a/WebBrowser2.fs +++ b/WebBrowser2.fs @@ -1,13 +1,9 @@ namespace Sayuri.Windows.Forms open System -open System.Drawing -open System.Drawing.Imaging open System.Reflection open System.Runtime.InteropServices open System.Windows.Forms -#nowarn "9" - [] type private IServiceProvider = abstract member QueryService : [] guidService : Guid * [] riid : Guid * [] ppvObject : obj byref -> unit @@ -89,13 +85,24 @@ type private IHTMLStyleSheet = [] type private IHTMLDocument2 = + [] + abstract member body : IHTMLElement [] abstract member parentWindow : IHTMLWindow2 [] abstract member createStyleSheet : bstrHref : string * lIndex : int -> IHTMLStyleSheet +[] +type private IHTMLElementCollection = + [] + abstract member item : name : obj * index : obj -> [] obj + [] + abstract member length : int with get, set + [] type private IHTMLDocument3 = + [] + abstract member getElementsByTagName : v : string -> IHTMLElementCollection [] abstract member getElementById : v : string -> obj @@ -104,29 +111,15 @@ type private IHTMLFrameBase2 = [] abstract member contentWindow : IHTMLWindow2 -[] -type private IHTMLEmbedElement = - interface - end - -[] -type private IHTMLObjectElement = - [] - abstract member ``object`` : [] obj +[] +type private IHTMLCanvasElement = + [] + abstract member toDataURL : ``type`` : string * jpegquality : obj -> string [] type private DWebBrowserEvents2 = [] abstract member NewWindow3 : [] ppDisp : obj byref * [] Cancel : bool byref * dwFlags : uint32 * bstrUrlContext : string * bstrUrl : string -> unit -[] -type DVTARGETDEVICE = - val tdSize : int - val tdDriverNameOffset : uint16 - val tdDeviceNameOffset : uint16 - val tdPortNameOffset : uint16 - val tdExtDevmodeOffset : uint16 - new () = { tdSize = Marshal.SizeOf typeof; tdDriverNameOffset = 0us; tdDeviceNameOffset = 0us; tdPortNameOffset = 0us; tdExtDevmodeOffset = 0us; } - [] type RECT = val left : int @@ -135,17 +128,6 @@ type RECT = val height : int new (left, top, width, height) = { left = left; top = top; width = width; height = height } -[] -type IViewObject = - abstract member Draw : [] dwDrawAspect : int * lindex : int * pvAspect : nativeint * [] ptd : DVTARGETDEVICE * hdcTargetDev : nativeint * hdcDraw : nativeint * [] lprcBounds : RECT * [] lprcWBounds : RECT * pfnContinue : nativeint * [] dwContinue : nativeint -> unit - abstract member GetColorSet : [] dwDrawAspect : int * lindex : int * pvAspect : nativeint * [] ptd : obj * hicTargetDev : nativeint * [] ppColorSet : obj -> unit - abstract member Freeze : [] dwDrawAspect : int * lindex : int * pvAspect : nativeint * [] pdwFreeze : nativeint -> unit - abstract member Unfreeze : [] dwFreeze : int -> unit - [] - abstract member SetAdvise : [] aspects : int * [] advf : int * [] pAdvSink : obj -> unit - [] - abstract member GetAdvise : [] paspects : int[] * [] advf : int[] * [] pAdvSink : obj[] -> unit - [] type private POINT = val mutable x : int @@ -277,20 +259,16 @@ type WebBrowser2 () as self = wb.RegisterAsBrowser <- true wb.Application static member GetCapture(element : obj) = - let element = element :?> IHTMLElement - let size = Size(element.offsetWidth, element.offsetHeight) - let view = match element with - | :? IHTMLObjectElement as objectElement -> objectElement.``object`` :?> IViewObject - | :? IHTMLEmbedElement -> element :?> IViewObject - | _ -> failwith "unknown element" - let ptd = DVTARGETDEVICE() - let bounds = RECT(0, 0, size.Width, size.Height) - let capture hdc = - view.Draw((*DVASPECT_CONTENT*)1, 0, 0n, ptd, 0n, hdc, bounds, null, 0n, 0n) - size, capture + let canvas = element :?> IHTMLCanvasElement + let dataUrl = canvas.toDataURL("image/png", 1) + if dataUrl.StartsWith "data:image/png;base64," |> not then failwith "invalid data url" + dataUrl.Substring 22 |> Convert.FromBase64String static member GetElementById((document : obj), id) = let element = (document :?> IHTMLDocument3).getElementById id if element = null then None else Some element + static member GetElementsByTagName((document : obj), name) = + let elements = (document :?> IHTMLDocument3).getElementsByTagName name + [| for i in 0 .. elements.length -> elements.item(null, i) |] static member GetFrameDocument(iframe : obj) = (((iframe :?> IHTMLFrameBase2).contentWindow :?> IServiceProvider).QueryService(typeof.GUID, typeof.GUID) :?> IWebBrowser2).Document member this.Zoom(percent : int) = diff --git a/d3d9/d3d9.vcxproj b/d3d9/d3d9.vcxproj index 29a3922..de0546c 100644 --- a/d3d9/d3d9.vcxproj +++ b/d3d9/d3d9.vcxproj @@ -22,34 +22,34 @@ {B805E2F6-08A9-4985-9626-65D812C6E52A} Win32Proj d3d9 - 10.0.14393.0 + 10.0.17134.0 DynamicLibrary true Unicode - v140 + v141 DynamicLibrary true Unicode - v140 + v141 DynamicLibrary false true Unicode - v140 + v141 DynamicLibrary false true Unicode - v140 + v141 diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..dc51217 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file