Skip to content

Commit

Permalink
feat: release 2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
blurfx committed Aug 22, 2023
1 parent 4b502a5 commit 27a51b9
Show file tree
Hide file tree
Showing 14 changed files with 362 additions and 73 deletions.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.DS_Store
.idea
.DS_Store
.idea
*.syso
*.exe
26 changes: 11 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
# KakaoTalkAdBlock

AdBlocker for KakaoTalk Windows client. (native, alpha)

## Update History

- Go [Releases](https://github.com/blurfx/KakaoTalkAdBlock/releases) page

## At a glance

![](https://raw.githubusercontent.com/blurfx/KakaoTalkAdBlock/master/kakaotalk.png)

This program runs in the tray.

![](https://raw.githubusercontent.com/blurfx/KakaoTalkAdBlock/master/tray.png)
# KakaoTalkAdBlock

AdBlocker for KakaoTalk Windows client.

## At a glance

![](https://raw.githubusercontent.com/blurfx/KakaoTalkAdBlock/main/kakaotalk.png)

This program runs in the tray. To exit, double-click the tray icon.

![](https://raw.githubusercontent.com/blurfx/KakaoTalkAdBlock/main/tray.png)
9 changes: 9 additions & 0 deletions build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@echo off

pushd winres

go-winres simply -icon=icon.ico

popd

go build -o KakaoTalkAdBlock.exe -ldflags "-H windowsgui -s -w" .\cmd\main.go
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package main

import "kakaotalkadblock/internal"
import _ "kakaotalkadblock/winres"

func main() {
internal.Run()
Expand Down
30 changes: 15 additions & 15 deletions internal/ad.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"golang.org/x/sys/windows"

"kakaotalkadblock/internal/win"
"kakaotalkadblock/internal/win/winapi"
)

const (
Expand All @@ -16,51 +16,51 @@ const (
func HidePopupAd() {
var popupHandle windows.HWND
for {
popupHandle = win.FindWindowEx(0, popupHandle, "", "")
popupHandle = winapi.FindWindowEx(0, popupHandle, "", "")
if popupHandle == 0 {
break
}
if win.GetParent(popupHandle) != 0 {
if winapi.GetParent(popupHandle) != 0 {
continue
}
className := win.GetClassName(popupHandle)
className := winapi.GetClassName(popupHandle)
if !strings.Contains(className, "RichPopWnd") {
continue
}
rect := new(win.Rect)
_ = win.GetWindowRect(popupHandle, rect)
rect := new(winapi.Rect)
_ = winapi.GetWindowRect(popupHandle, rect)
width := rect.Right - rect.Left
height := rect.Bottom - rect.Top
if width == 300 && height == 150 {
win.SendMessage(popupHandle, win.WM_CLOSE, 0, 0)
winapi.SendMessage(popupHandle, winapi.WmClose, 0, 0)
}
}
}

func HideMainWindowAd(windowClass string, handle windows.HWND) {
if windowClass == "BannerAdWnd" {
win.ShowWindow(handle, 0)
win.SetWindowPos(handle, 0, 0, 0, 0, 0, win.SWP_NOMOVE)
winapi.ShowWindow(handle, 0)
winapi.SetWindowPos(handle, 0, 0, 0, 0, 0, winapi.SwpNomove)
}
}

func HideLockScreenAdArea(windowText string, rect *win.Rect, handle windows.HWND) {
func HideLockScreenAdArea(windowText string, rect *winapi.Rect, handle windows.HWND) {
if strings.HasPrefix(windowText, "LockModeView") {
width := rect.Right - rect.Left - LayoutShadowPadding
height := rect.Bottom - rect.Top
win.UpdateWindow(handle)
win.SetWindowPos(handle, 0, 0, 0, width, height, win.SWP_NOMOVE)
winapi.UpdateWindow(handle)
winapi.SetWindowPos(handle, 0, 0, 0, width, height, winapi.SwpNomove)
}
}

func HideMainViewAdArea(windowText string, rect *win.Rect, handle windows.HWND) {
func HideMainViewAdArea(windowText string, rect *winapi.Rect, handle windows.HWND) {
if strings.HasPrefix(windowText, "OnlineMainView") {
width := rect.Right - rect.Left - LayoutShadowPadding
height := rect.Bottom - rect.Top - MainViewPadding
if height < 1 {
return
}
win.UpdateWindow(handle)
win.SetWindowPos(handle, 0, 0, 0, width, height, win.SWP_NOMOVE)
winapi.UpdateWindow(handle)
winapi.SetWindowPos(handle, 0, 0, 0, width, height, winapi.SwpNomove)
}
}
32 changes: 20 additions & 12 deletions internal/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"unsafe"

"kakaotalkadblock/internal/win"
"kakaotalkadblock/internal/win/winapi"

"golang.org/x/sys/windows"
)
Expand All @@ -27,15 +28,15 @@ func uint8ToStr(arr []uint8) string {
func watch() {
const executeable = "kakaotalk.exe"
var (
pe32 win.ProcessEntry32
pe32 winapi.ProcessEntry32
szExeFile string
)

snapshot := win.CreateToolhelp32Snapshot(win.TH32CS_SNAPPROCESS, 0)
snapshot := winapi.CreateToolhelp32Snapshot(winapi.Th32csSnapprocess, 0)
pe32.DwSize = uint32(unsafe.Sizeof(pe32))

var enumWindow = syscall.NewCallback(func(handle windows.HWND, processId uintptr) uintptr {
win.GetWindowThreadProcessId(handle, &pe32.Th32ProcessID)
winapi.GetWindowThreadProcessId(handle, &pe32.Th32ProcessID)

if processId == uintptr(pe32.Th32ProcessID) {
handles = append(handles, handle)
Expand All @@ -47,16 +48,16 @@ func watch() {
mutex.Lock()
handles = handles[:0]

if win.Process32First(uintptr(snapshot), &pe32) {
if winapi.Process32First(uintptr(snapshot), &pe32) {
for {
szExeFile = uint8ToStr(pe32.SzExeFile[:])

if strings.ToLower(szExeFile) == executeable {
win.EnumWindows(enumWindow, uintptr(pe32.Th32ProcessID))
winapi.EnumWindows(enumWindow, uintptr(pe32.Th32ProcessID))
break
}

if !win.Process32Next(uintptr(snapshot), &pe32) {
if !winapi.Process32Next(uintptr(snapshot), &pe32) {
break
}
}
Expand All @@ -81,13 +82,13 @@ func removeAd() {
}
childHandles = childHandles[:0]
var handle windows.HWND
win.EnumChildWindows(wnd, enumWindow, uintptr(unsafe.Pointer(&handle)))
winapi.EnumChildWindows(wnd, enumWindow, uintptr(unsafe.Pointer(&handle)))

rect := new(win.Rect)
win.GetWindowRect(wnd, rect)
rect := new(winapi.Rect)
winapi.GetWindowRect(wnd, rect)
for _, childHandle := range childHandles {
className := win.GetClassName(childHandle)
windowText := win.GetWindowText(childHandle)
className := winapi.GetClassName(childHandle)
windowText := winapi.GetWindowText(childHandle)
HideMainWindowAd(className, childHandle)
HideMainViewAdArea(windowText, rect, childHandle)
HideLockScreenAdArea(windowText, rect, childHandle)
Expand All @@ -100,8 +101,15 @@ func removeAd() {
}

func Run() {
var quit = make(chan struct{})
trayIcon := win.NewTrayIcon(&quit)
trayIcon.Show()
defer trayIcon.Hide()
go watch()
go removeAd()

select {}
select {
case <-quit:
return
}
}
109 changes: 109 additions & 0 deletions internal/win/tray_icon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package win

import (
"unsafe"

"golang.org/x/sys/windows"

"kakaotalkadblock/internal/win/winapi"
)

var quit *chan struct{}

func wndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case winapi.WmTrayicon:
switch uint16(lParam) {
case winapi.WmLbuttondblclk:
close(*quit)
}
case winapi.WmDestroy:
winapi.PostQuitMessage(0)
default:
return winapi.DefWindowProc(hWnd, msg, wParam, lParam)
}
return 0
}

func createMainWindow() (uintptr, error) {
hInstance, err := winapi.GetModuleHandle(nil)
if err != nil {
return 0, err
}

wndClass, _ := windows.UTF16PtrFromString("KakaoTalkAdBlock")

var windowClass winapi.WindowClassEx

windowClass.CbSize = uint32(unsafe.Sizeof(windowClass))
windowClass.LpfnWndProc = windows.NewCallback(wndProc)
windowClass.HInstance = hInstance
windowClass.LpszClassName = wndClass
if _, err := winapi.RegisterClassEx(&windowClass); err != nil {
return 0, err
}

handle, err := winapi.CreateWindowEx(
0,
wndClass,
windows.StringToUTF16Ptr("KakaoTalkAdBlock"),
winapi.WsOverlappedwindow,
winapi.CwUsedefault,
winapi.CwUsedefault,
1,
1,
0,
0,
hInstance,
nil)
if err != nil {
return 0, err
}

return handle, nil
}

type TrayIcon struct {
notifyIconData winapi.NotifyIconData
}

func NewTrayIcon(quitChan *chan struct{}) *TrayIcon {
var data winapi.NotifyIconData
data.CbSize = uint32(unsafe.Sizeof(data))
data.UFlags = winapi.NifIcon | winapi.NifMessage | winapi.NifInfo
data.UCallbackMessage = winapi.WmTrayicon

hInst, err := winapi.GetModuleHandle(nil)
if err != nil {
panic(err)
}
icon, err := winapi.LoadIcon(hInst, winapi.MakeIntResource(1))
if err != nil {
panic(err)
}
data.HIcon = icon

quit = quitChan
return &TrayIcon{
notifyIconData: data,
}
}

func (t *TrayIcon) Show() {
if t.notifyIconData.HWnd == 0 {
handle, err := createMainWindow()
if err != nil {
panic(err)
}
t.notifyIconData.HWnd = handle
}
if err := winapi.ShellNotifyIcon(winapi.NimAdd, &t.notifyIconData); err != nil {
panic(err)
}
}

func (t *TrayIcon) Hide() {
if err := winapi.ShellNotifyIcon(winapi.NimDelete, &t.notifyIconData); err != nil {
panic(err)
}
}
31 changes: 31 additions & 0 deletions internal/win/winapi/constant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package winapi

const (
Th32csSnapprocess = 0x2
MaxPath = 260

NimAdd = 0x00000000
NimDelete = 0x00000002

NifMessage = 0x00000001
NifIcon = 0x00000002
NifInfo = 0x00000010

CwUsedefault = ^0x7fffffff

WsCaption = 0x00c00000
WsMaximizebox = 0x00010000
WsMinimizebox = 0x00020000
WsOverlapped = 0x00000000
WsSysmenu = 0x00080000
WsThickframe = 0x00040000
WsOverlappedwindow = WsOverlapped | WsCaption | WsSysmenu | WsThickframe | WsMinimizebox | WsMaximizebox

WmDestroy = 0x0002
WmClose = 0x10
WmLbuttondblclk = 0x0203
WmApp = 0x8000
WmTrayicon = WmApp + 1

SwpNomove = 0x0002
)
Loading

0 comments on commit 27a51b9

Please sign in to comment.