mirror of
https://github.com/UzixLS/KernelEx.git
synced 2025-07-18 23:11:19 +03:00
import KernelEx-4.5-Beta2
This commit is contained in:
@ -1,3 +1,23 @@
|
|||||||
|
KernelEx v4.5 Beta 2 by Xeno86
|
||||||
|
2010-02-14
|
||||||
|
|
||||||
|
fixed incompatibility with Japanese WinME
|
||||||
|
implemented USP font cache
|
||||||
|
fix: kexFlushAppSettings didn't clear wildcard app settings
|
||||||
|
fix: EnumFontFamiliesEx should only fill TEXTMETRIC structure if font is not TrueType
|
||||||
|
FONTSIGNATURE sub-structure doesn't seem to contain valid information, accessing it could trigger a crash
|
||||||
|
changed AddFontMemResourceEx and RemoveFontMemResourceEx stubs for Opera 10.50 beta compatibility
|
||||||
|
implemented shell32.SHParseDisplayName [xp and above]
|
||||||
|
implemented winspool.EnumPrintersW
|
||||||
|
added advapi32.CreateProcessWithLogonW, InitiateSystemShutdownEx stubs
|
||||||
|
replaced thread-pool implementation with custom code
|
||||||
|
added timer-queue functions
|
||||||
|
updated jemalloc to version from FF3.6
|
||||||
|
added checks to alloc/realloc/free to make jemalloc more fault tolerant - better match Windows 9x behaviour
|
||||||
|
kexCOM: LoadLibrary(self) trick to prevent premature unload in buggy programs
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
KernelEx v4.5 Beta 1 by Xeno86
|
KernelEx v4.5 Beta 1 by Xeno86
|
||||||
2010-01-18
|
2010-01-18
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
!define _VERSION '4.5 Beta 1'
|
!define _VERSION '4.5 Beta 2'
|
||||||
|
|
||||||
!ifndef _DEBUG
|
!ifndef _DEBUG
|
||||||
!define FLAVOUR 'Release'
|
!define FLAVOUR 'Release'
|
||||||
|
19
NEWS.txt
19
NEWS.txt
@ -1,3 +1,22 @@
|
|||||||
|
KernelEx v4.5 Beta 2 by Xeno86
|
||||||
|
2010-02-14
|
||||||
|
|
||||||
|
What's new:
|
||||||
|
----------------------------------
|
||||||
|
* Implemented Uniscribe font caching (improves Firefox 3 performance).
|
||||||
|
* New thread pool implementation (fixes IE6 problems).
|
||||||
|
* Fixed rare font related Firefox 3 crash.
|
||||||
|
* Implemted timer queue APIs.
|
||||||
|
* Implemented SHParseDisplayName and restricted to XP+ configs to fix Firefox mailto issues.
|
||||||
|
* Fixed premature kexCOM unloading crashing Photoshop 5 and other buggy apps.
|
||||||
|
* Updated jemalloc to version from FF3.6.
|
||||||
|
* Fixed jemalloc sensitiveness to invalid pointers. Fixes vmwareuser, cvtaplog crashing.
|
||||||
|
* Implemented EnumPrintersW (Foxit 3.1 Unicode printing support).
|
||||||
|
* Fixed Opera 10.50 Beta Acid3 crash.
|
||||||
|
* Other small fixes / stubs.
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
|
||||||
KernelEx v4.5 Beta 1 by Xeno86
|
KernelEx v4.5 Beta 1 by Xeno86
|
||||||
2010-01-18
|
2010-01-18
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ GDI32.SetMapMode=std
|
|||||||
KERNEL32.VerSetConditionMask=none
|
KERNEL32.VerSetConditionMask=none
|
||||||
KERNEL32.VerifyVersionInfoA=none
|
KERNEL32.VerifyVersionInfoA=none
|
||||||
KERNEL32.VerifyVersionInfoW=none
|
KERNEL32.VerifyVersionInfoW=none
|
||||||
|
SHELL32.SHParseDisplayName=none
|
||||||
|
|
||||||
[DCFG1.names.Me]
|
[DCFG1.names.Me]
|
||||||
KERNEL32.GetVersion=std
|
KERNEL32.GetVersion=std
|
||||||
@ -43,6 +44,7 @@ KERNEL32.VerifyVersionInfoW=none
|
|||||||
USER32.AllowSetForegroundWindow=std
|
USER32.AllowSetForegroundWindow=std
|
||||||
USER32.LockSetForegroundWindow=std
|
USER32.LockSetForegroundWindow=std
|
||||||
USER32.GetMouseMovePointsEx=std
|
USER32.GetMouseMovePointsEx=std
|
||||||
|
SHELL32.SHParseDisplayName=none
|
||||||
|
|
||||||
[WIN95]
|
[WIN95]
|
||||||
inherit=DCFG1
|
inherit=DCFG1
|
||||||
@ -109,6 +111,7 @@ KERNEL32.GetVersionExA=kexbases.6
|
|||||||
KERNEL32.GetVersionExW=kexbases.6
|
KERNEL32.GetVersionExW=kexbases.6
|
||||||
KERNEL32.VerifyVersionInfoA=kexbases.1
|
KERNEL32.VerifyVersionInfoA=kexbases.1
|
||||||
KERNEL32.VerifyVersionInfoW=kexbases.1
|
KERNEL32.VerifyVersionInfoW=kexbases.1
|
||||||
|
SHELL32.SHParseDisplayName=kexbasen.0
|
||||||
|
|
||||||
[WIN2K3]
|
[WIN2K3]
|
||||||
inherit=WINXP
|
inherit=WINXP
|
||||||
|
100
apilibs/kexbasen/gdi32/ScriptCache.cpp
Executable file
100
apilibs/kexbasen/gdi32/ScriptCache.cpp
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* KernelEx
|
||||||
|
* Copyright (C) 2010, Tihiy, Xeno86
|
||||||
|
*
|
||||||
|
* This file is part of KernelEx source code.
|
||||||
|
*
|
||||||
|
* KernelEx is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* KernelEx is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Make; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptCache.h"
|
||||||
|
|
||||||
|
ScriptCache ScriptCache::instance;
|
||||||
|
|
||||||
|
ScriptCache::ScriptCache()
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(&cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptCache::~ScriptCache()
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCRIPT_CACHE ScriptCache::GetCache(HFONT hFont)
|
||||||
|
{
|
||||||
|
list<FONTCACHE>::const_iterator it;
|
||||||
|
for (it = cache.begin(); it != cache.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->hFont == hFont)
|
||||||
|
return it->cache;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptCache::SetCache(HFONT hFont,SCRIPT_CACHE newcache)
|
||||||
|
{
|
||||||
|
list<FONTCACHE>::iterator it;
|
||||||
|
for (it = cache.begin(); it != cache.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->hFont == hFont)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (it == cache.end())
|
||||||
|
{
|
||||||
|
FONTCACHE fc;
|
||||||
|
fc.hFont = hFont;
|
||||||
|
fc.cache = newcache;
|
||||||
|
cache.push_front(fc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it->cache = newcache;
|
||||||
|
cache.splice(cache.begin(), cache, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache.size() > MAXSCRIPTCACHESIZE)
|
||||||
|
{
|
||||||
|
list<FONTCACHE>::reference ref = cache.back();
|
||||||
|
ScriptFreeCache(&ref.cache);
|
||||||
|
cache.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptCache::ResetCache(HFONT hFont)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
list<FONTCACHE>::iterator it;
|
||||||
|
for (it = cache.begin(); it != cache.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->hFont == hFont)
|
||||||
|
{
|
||||||
|
ScriptFreeCache(&it->cache);
|
||||||
|
cache.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptCache::Lock()
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptCache::Unlock()
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&cs);
|
||||||
|
}
|
59
apilibs/kexbasen/gdi32/ScriptCache.h
Executable file
59
apilibs/kexbasen/gdi32/ScriptCache.h
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* KernelEx
|
||||||
|
* Copyright (C) 2010, Tihiy, Xeno86
|
||||||
|
*
|
||||||
|
* This file is part of KernelEx source code.
|
||||||
|
*
|
||||||
|
* KernelEx is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* KernelEx is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Make; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SCRIPTCACHE_H
|
||||||
|
#define __SCRIPTCACHE_H
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <usp10.h>
|
||||||
|
#pragma warning(disable:4530) //we don't do exception handling
|
||||||
|
#include <list>
|
||||||
|
#pragma warning(default:4530)
|
||||||
|
|
||||||
|
#define MAXSCRIPTCACHESIZE 10
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HFONT hFont;
|
||||||
|
SCRIPT_CACHE cache;
|
||||||
|
} FONTCACHE, *PFONTCACHE;
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class ScriptCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ScriptCache instance;
|
||||||
|
~ScriptCache();
|
||||||
|
SCRIPT_CACHE GetCache(HFONT hFont);
|
||||||
|
void SetCache(HFONT hFont, SCRIPT_CACHE newcache);
|
||||||
|
void ResetCache(HFONT hFont);
|
||||||
|
void Lock();
|
||||||
|
void Unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
list<FONTCACHE> cache;
|
||||||
|
CRITICAL_SECTION cs;
|
||||||
|
|
||||||
|
ScriptCache();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,14 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* KernelEx
|
* KernelEx
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2008, 2010, Tihiy
|
||||||
|
* This file is part of KernelEx source code.
|
||||||
|
*
|
||||||
* Copyright 1993 Alexandre Julliard
|
* Copyright 1993 Alexandre Julliard
|
||||||
* 1997 Alex Korobka
|
* 1997 Alex Korobka
|
||||||
* Copyright 2002,2003 Shachar Shemesh
|
* Copyright 2002,2003 Shachar Shemesh
|
||||||
* Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla)
|
* Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla)
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008, Tihiy
|
|
||||||
* This file is part of KernelEx source code.
|
|
||||||
*
|
|
||||||
* KernelEx is free software; you can redistribute it and/or modify
|
* KernelEx is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published
|
* it under the terms of the GNU General Public License as published
|
||||||
* by the Free Software Foundation; version 2 of the License.
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
@ -28,6 +28,17 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include <usp10.h>
|
#include <usp10.h>
|
||||||
|
#include "ScriptCache.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
__declspec(dllexport)
|
||||||
|
void DeleteUSPFontCache(HFONT hFont)
|
||||||
|
{
|
||||||
|
ScriptCache::instance.ResetCache(hFont);
|
||||||
|
}
|
||||||
|
|
||||||
/* MAKE_EXPORT GetGlyphIndicesW_new=GetGlyphIndicesW */
|
/* MAKE_EXPORT GetGlyphIndicesW_new=GetGlyphIndicesW */
|
||||||
int WINAPI GetGlyphIndicesW_new(
|
int WINAPI GetGlyphIndicesW_new(
|
||||||
@ -39,10 +50,16 @@ int WINAPI GetGlyphIndicesW_new(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
SCRIPT_CACHE cache = 0;
|
|
||||||
if (!hdc || !pgi || (UINT)lpstr<0xFFFFu || !c) return GDI_ERROR;
|
if (!hdc || !pgi || (UINT)lpstr<0xFFFFu || !c) return GDI_ERROR;
|
||||||
|
ScriptCache::instance.Lock();
|
||||||
|
HFONT hFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
|
||||||
|
SCRIPT_CACHE cache = ScriptCache::instance.GetCache(hFont);
|
||||||
result = ScriptGetCMap(hdc,&cache,lpstr,c,0,pgi);
|
result = ScriptGetCMap(hdc,&cache,lpstr,c,0,pgi);
|
||||||
if ( !( result == S_OK || result == S_FALSE ) ) return GDI_ERROR;
|
if ( !( result == S_OK || result == S_FALSE ) )
|
||||||
|
{
|
||||||
|
ScriptCache::instance.Unlock();
|
||||||
|
return GDI_ERROR;
|
||||||
|
}
|
||||||
if ( fl && result == S_FALSE)
|
if ( fl && result == S_FALSE)
|
||||||
{
|
{
|
||||||
WORD* checkglyph = pgi;
|
WORD* checkglyph = pgi;
|
||||||
@ -56,7 +73,8 @@ int WINAPI GetGlyphIndicesW_new(
|
|||||||
checkglyph++;
|
checkglyph++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ScriptFreeCache(&cache);
|
ScriptCache::instance.SetCache(hFont,cache); \
|
||||||
|
ScriptCache::instance.Unlock();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +133,6 @@ BOOL WINAPI GetTextExtentExPointI_new(
|
|||||||
LPSIZE lpSize // string dimensions
|
LPSIZE lpSize // string dimensions
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SCRIPT_CACHE cache = 0;
|
|
||||||
ABC abc;
|
ABC abc;
|
||||||
WORD* glyph = pgiIn;
|
WORD* glyph = pgiIn;
|
||||||
int* dxs = alpDx;
|
int* dxs = alpDx;
|
||||||
@ -129,6 +146,11 @@ BOOL WINAPI GetTextExtentExPointI_new(
|
|||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptCache::instance.Lock();
|
||||||
|
HFONT hFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
|
||||||
|
SCRIPT_CACHE cache = ScriptCache::instance.GetCache(hFont);
|
||||||
|
|
||||||
//in UberKern, ScriptPlace was used. However, it's too costly...
|
//in UberKern, ScriptPlace was used. However, it's too costly...
|
||||||
//so let's compute the info ourselves
|
//so let's compute the info ourselves
|
||||||
for (i = 0; i < cgi; i++)
|
for (i = 0; i < cgi; i++)
|
||||||
@ -145,8 +167,11 @@ BOOL WINAPI GetTextExtentExPointI_new(
|
|||||||
glyph++;
|
glyph++;
|
||||||
}
|
}
|
||||||
lpSize->cx = sum;
|
lpSize->cx = sum;
|
||||||
|
|
||||||
ScriptCacheGetHeight(hdc,&cache,&lpSize->cy);
|
ScriptCacheGetHeight(hdc,&cache,&lpSize->cy);
|
||||||
ScriptFreeCache(&cache);
|
ScriptCache::instance.SetCache(hFont,cache);
|
||||||
|
ScriptCache::instance.Unlock();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +195,6 @@ BOOL WINAPI GetCharWidthI_new(
|
|||||||
INT* lpBuffer // buffer for widths
|
INT* lpBuffer // buffer for widths
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SCRIPT_CACHE cache = 0;
|
|
||||||
ABC abc;
|
ABC abc;
|
||||||
WORD glyph;
|
WORD glyph;
|
||||||
|
|
||||||
@ -179,6 +203,11 @@ BOOL WINAPI GetCharWidthI_new(
|
|||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptCache::instance.Lock();
|
||||||
|
HFONT hFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
|
||||||
|
SCRIPT_CACHE cache = ScriptCache::instance.GetCache(hFont);
|
||||||
|
|
||||||
if ( !pgi ) //cgi glyphs starting giFirst
|
if ( !pgi ) //cgi glyphs starting giFirst
|
||||||
{
|
{
|
||||||
for ( glyph = giFirst; glyph < giFirst+cgi; glyph++)
|
for ( glyph = giFirst; glyph < giFirst+cgi; glyph++)
|
||||||
@ -198,7 +227,9 @@ BOOL WINAPI GetCharWidthI_new(
|
|||||||
lpBuffer++;
|
lpBuffer++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ScriptFreeCache(&cache);
|
|
||||||
|
ScriptCache::instance.SetCache(hFont,cache); \
|
||||||
|
ScriptCache::instance.Unlock();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,14 +244,17 @@ BOOL WINAPI GetCharABCWidthsI_new(
|
|||||||
LPABC lpabc // array of character widths
|
LPABC lpabc // array of character widths
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SCRIPT_CACHE cache = 0;
|
WORD glyph;
|
||||||
WORD glyph;
|
|
||||||
|
|
||||||
if ( !hdc || !lpabc || cgi<=0)
|
if ( !hdc || !lpabc || cgi<=0)
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptCache::instance.Lock();
|
||||||
|
HFONT hFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
|
||||||
|
SCRIPT_CACHE cache = ScriptCache::instance.GetCache(hFont);
|
||||||
|
|
||||||
if ( !pgi ) //cgi glyphs starting giFirst
|
if ( !pgi ) //cgi glyphs starting giFirst
|
||||||
{
|
{
|
||||||
for ( glyph = giFirst; glyph < giFirst+cgi; glyph++)
|
for ( glyph = giFirst; glyph < giFirst+cgi; glyph++)
|
||||||
@ -238,7 +272,8 @@ BOOL WINAPI GetCharABCWidthsI_new(
|
|||||||
lpabc++;
|
lpabc++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ScriptFreeCache(&cache);
|
ScriptCache::instance.SetCache(hFont,cache); \
|
||||||
|
ScriptCache::instance.Unlock();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* KernelEx
|
* KernelEx
|
||||||
* Copyright (C) 2009, Tihiy
|
* Copyright (C) 2009-2010, Tihiy
|
||||||
* Copyright (c) 2006 Robert Shearman (WINE Project)
|
|
||||||
*
|
*
|
||||||
* This file is part of KernelEx source code.
|
* This file is part of KernelEx source code.
|
||||||
*
|
*
|
||||||
@ -21,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <malloc.h>
|
||||||
#include "shlord.h"
|
#include "shlord.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -30,13 +30,21 @@
|
|||||||
* RegisterWaitForSingleObjectEx
|
* RegisterWaitForSingleObjectEx
|
||||||
* UnregisterWait
|
* UnregisterWait
|
||||||
* UnregisterWaitEx
|
* UnregisterWaitEx
|
||||||
|
* CreateTimerQueue
|
||||||
|
* CreateTimerQueueTimer
|
||||||
|
* DeleteTimerQueue
|
||||||
|
* DeleteTimerQueueEx
|
||||||
|
* DeleteTimerQueueTimer
|
||||||
* all functions could be implemented with shlwapi,
|
* all functions could be implemented with shlwapi,
|
||||||
* but they don't support async de-registration and most flags
|
* but they don't support async de-registration and most flags.
|
||||||
* Also, Wine functions can cause problems in cases like
|
* Wine code was completely purged outta here - it's no good.
|
||||||
* when second unregister is called, or handle is reused...
|
|
||||||
* But Windows XP also fails hard in such cases.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* RegisterWait/TimerQueues are implemented using waitable timers,
|
||||||
|
* unlike wine/shlwapi/whatever implementations exist.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define TPS_EXECUTEIO 0x00000001
|
#define TPS_EXECUTEIO 0x00000001
|
||||||
#define TPS_LONGEXECTIME 0x00000008
|
#define TPS_LONGEXECTIME 0x00000008
|
||||||
|
|
||||||
@ -64,107 +72,379 @@ BOOL WINAPI QueueUserWorkItem_new( LPTHREAD_START_ROUTINE Function, PVOID Contex
|
|||||||
return SHQueueUserWorkItem( Function, Context, 0, NULL, NULL, NULL, dwFlags );
|
return SHQueueUserWorkItem( Function, Context, 0, NULL, NULL, NULL, dwFlags );
|
||||||
}
|
}
|
||||||
|
|
||||||
//registerwait routines
|
//256h should be enough for everyone
|
||||||
|
#define MAX_WAIT_ITEMS (MAXIMUM_WAIT_OBJECTS / 2)
|
||||||
|
#define MAX_WAIT_THREADS 8
|
||||||
|
|
||||||
|
#define WAIT_STATE_ACTIVE 0 //item is in wait thread
|
||||||
|
#define WAIT_STATE_UNREGISTERED 1 //item is unregistered and queued to be removed from wait thread
|
||||||
|
#define WAIT_STATE_REMOVED 2 //item is removed from wait thread
|
||||||
|
#define WAIT_STATE_DELETESYNC 3 //item will be destroyed with removal
|
||||||
|
#define WAIT_STATE_GAMEOVER 4 //item is destroyed
|
||||||
|
#define WAIT_STATE_ABANDONED 5 //item expired and removed from wait thread but not yet unregistered
|
||||||
|
|
||||||
|
#define NONSENSE 10000
|
||||||
|
|
||||||
|
// RegisterWaitForSingleObject routines.
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
HANDLE Object;
|
HANDLE Object;
|
||||||
HANDLE CancelEvent;
|
HANDLE TimerObject;
|
||||||
WAITORTIMERCALLBACK Callback;
|
WAITORTIMERCALLBACK Callback;
|
||||||
PVOID Context;
|
PVOID Context;
|
||||||
ULONG Milliseconds;
|
ULONG Milliseconds;
|
||||||
ULONG Flags;
|
ULONG Flags;
|
||||||
HANDLE CompletionEvent;
|
PVOID waitThread;
|
||||||
LONG DeleteCount;
|
LONG State;
|
||||||
BOOLEAN CallbackInProgress;
|
LONG CallbacksPending;
|
||||||
} wait_work_item_struct, *wait_work_item_ptr;
|
HANDLE CompletionEvent;
|
||||||
|
HANDLE CallbackEvent;
|
||||||
|
} WAIT_WORK_ITEM, *PWAIT_WORK_ITEM;
|
||||||
|
|
||||||
static void delete_wait_work_item(wait_work_item_ptr wait_work_item)
|
typedef struct
|
||||||
{
|
{
|
||||||
CloseHandle( wait_work_item->CancelEvent );
|
HANDLE hThread;
|
||||||
wait_work_item->CancelEvent = 0; //in case someone tries to work on deleted handle
|
HANDLE WaitEvent;
|
||||||
HeapFree( GetProcessHeap(), 0, wait_work_item );
|
BOOL InSyncCallback;
|
||||||
|
LONG nItems;
|
||||||
|
PWAIT_WORK_ITEM waitItems[MAX_WAIT_ITEMS];
|
||||||
|
} WAIT_THREAD, *PWAIT_THREAD;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PWAIT_WORK_ITEM item;
|
||||||
|
BOOLEAN TimerOrWaitFired;
|
||||||
|
} ASYNC_CALL, *PASYNC_CALL;
|
||||||
|
|
||||||
|
static PWAIT_THREAD waitthreads[MAX_WAIT_THREADS] = {0};
|
||||||
|
static CRITICAL_SECTION wait_cs;
|
||||||
|
|
||||||
|
BOOL init_threadpool()
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(&wait_cs);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
|
static VOID ActivateTimer(PWAIT_WORK_ITEM workItem)
|
||||||
{
|
{
|
||||||
wait_work_item_ptr wait_work_item = (wait_work_item_ptr)Arg;
|
if (workItem->Milliseconds != INFINITE)
|
||||||
BOOL alertable = (wait_work_item->Flags & WT_EXECUTEINIOTHREAD) ? TRUE : FALSE;
|
{
|
||||||
HANDLE handles[2] = { wait_work_item->Object, wait_work_item->CancelEvent };
|
LARGE_INTEGER timeout;
|
||||||
HANDLE completion_event;
|
timeout.QuadPart = workItem->Milliseconds*(LONGLONG)-10000;
|
||||||
DWORD status;
|
SetWaitableTimer(workItem->TimerObject,&timeout,0,NULL,NULL,FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID DestroyWaitItem(PWAIT_WORK_ITEM workItem)
|
||||||
|
{
|
||||||
|
CloseHandle(workItem->CallbackEvent);
|
||||||
|
CloseHandle(workItem->TimerObject);
|
||||||
|
HeapFree(GetProcessHeap(),0,workItem);
|
||||||
|
}
|
||||||
|
|
||||||
while (TRUE)
|
static VOID CALLBACK AddWaitItem(ULONG_PTR Arg)
|
||||||
{
|
{
|
||||||
status = WaitForMultipleObjectsEx( 2, handles, FALSE, wait_work_item->Milliseconds, alertable );
|
PWAIT_WORK_ITEM workItem = (PWAIT_WORK_ITEM)Arg;
|
||||||
if (status == STATUS_WAIT_0 || status == STATUS_TIMEOUT)
|
PWAIT_THREAD waitThread = (PWAIT_THREAD)workItem->waitThread;
|
||||||
{
|
int i;
|
||||||
BOOL TimerOrWaitFired = (status == STATUS_WAIT_0) ? FALSE : TRUE;
|
for (i=0;i<waitThread->nItems;i++)
|
||||||
|
{
|
||||||
|
//we can't have one handle several times
|
||||||
|
if (waitThread->waitItems[i]->Object == workItem->Object)
|
||||||
|
{
|
||||||
|
workItem->waitThread = NULL;
|
||||||
|
SetEvent(workItem->CompletionEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waitThread->waitItems[waitThread->nItems] = workItem;
|
||||||
|
waitThread->nItems++;
|
||||||
|
SetEvent(workItem->CompletionEvent);
|
||||||
|
//what if callback will fire before RegisterWait... returns?
|
||||||
|
ActivateTimer(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
wait_work_item->CallbackInProgress = TRUE;
|
static VOID CALLBACK RemoveWaitItem(ULONG_PTR Arg)
|
||||||
wait_work_item->Callback( wait_work_item->Context, TimerOrWaitFired );
|
{
|
||||||
wait_work_item->CallbackInProgress = FALSE;
|
PWAIT_WORK_ITEM workItem = (PWAIT_WORK_ITEM)Arg;
|
||||||
|
PWAIT_THREAD waitThread = (PWAIT_THREAD)workItem->waitThread;
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<MAX_WAIT_ITEMS;i++)
|
||||||
|
if (waitThread->waitItems[i] == workItem)
|
||||||
|
break;
|
||||||
|
if (i<MAX_WAIT_ITEMS)
|
||||||
|
{
|
||||||
|
for (j=i;j<waitThread->nItems-1;j++)
|
||||||
|
{
|
||||||
|
waitThread->waitItems[j]=waitThread->waitItems[j+1];
|
||||||
|
waitThread->waitItems[j+1]=NULL;
|
||||||
|
}
|
||||||
|
waitThread->nItems--;
|
||||||
|
}
|
||||||
|
//if unregister marked it for delete, kill it here
|
||||||
|
if (InterlockedCompareExchange(&workItem->State,WAIT_STATE_GAMEOVER,WAIT_STATE_DELETESYNC) == WAIT_STATE_DELETESYNC)
|
||||||
|
{
|
||||||
|
if (workItem->CompletionEvent) SetEvent(workItem->CompletionEvent);
|
||||||
|
DestroyWaitItem(workItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InterlockedCompareExchange(&workItem->State,WAIT_STATE_ABANDONED,WAIT_STATE_ACTIVE);
|
||||||
|
InterlockedCompareExchange(&workItem->State,WAIT_STATE_REMOVED,WAIT_STATE_UNREGISTERED); //mark it removed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wait_work_item->Flags & WT_EXECUTEONLYONCE)
|
static DWORD CALLBACK AsyncWaiterCall(LPVOID Arg)
|
||||||
break;
|
{
|
||||||
}
|
PASYNC_CALL waiter = (PASYNC_CALL)Arg;
|
||||||
else
|
PWAIT_WORK_ITEM workItem = waiter->item;
|
||||||
break; //CancelEvent signalled
|
if (workItem->State == WAIT_STATE_ACTIVE || workItem->State == WAIT_STATE_ABANDONED)
|
||||||
}
|
workItem->Callback(workItem->Context,waiter->TimerOrWaitFired);
|
||||||
|
LONG CallbacksPending = InterlockedDecrement(&workItem->CallbacksPending);
|
||||||
|
SetEvent(workItem->CallbackEvent);
|
||||||
|
if (CallbacksPending == 0 && workItem->State != WAIT_STATE_ACTIVE)
|
||||||
|
{
|
||||||
|
//if it's removed, all fine, destroy it here
|
||||||
|
if (InterlockedCompareExchange(&workItem->State,WAIT_STATE_GAMEOVER,WAIT_STATE_REMOVED) == WAIT_STATE_REMOVED)
|
||||||
|
{
|
||||||
|
if (workItem->CompletionEvent) SetEvent(workItem->CompletionEvent);
|
||||||
|
DestroyWaitItem(workItem);
|
||||||
|
}
|
||||||
|
else //destroy it with removal
|
||||||
|
InterlockedCompareExchange(&workItem->State,WAIT_STATE_DELETESYNC,WAIT_STATE_UNREGISTERED);
|
||||||
|
}
|
||||||
|
|
||||||
completion_event = wait_work_item->CompletionEvent;
|
HeapFree(GetProcessHeap(),0,Arg);
|
||||||
if (completion_event)
|
return 0;
|
||||||
SetEvent( completion_event );
|
}
|
||||||
|
|
||||||
if ( InterlockedIncrement( &wait_work_item->DeleteCount ) == 2 )
|
static VOID TerminateWaitThread(PWAIT_THREAD threadinfo)
|
||||||
delete_wait_work_item( wait_work_item );
|
{
|
||||||
|
int i;
|
||||||
|
EnterCriticalSection(&wait_cs);
|
||||||
|
for (i=0;i<MAX_WAIT_THREADS;i++)
|
||||||
|
{
|
||||||
|
if (waitthreads[i] == threadinfo)
|
||||||
|
{
|
||||||
|
waitthreads[i] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&wait_cs);
|
||||||
|
//if thread died of failure, mark all wait items abandoned
|
||||||
|
for (i=0;i<threadinfo->nItems;i++)
|
||||||
|
InterlockedCompareExchange(&threadinfo->waitItems[i]->State,WAIT_STATE_ABANDONED,WAIT_STATE_ACTIVE);
|
||||||
|
//make sure there aren't any outstanding APCs
|
||||||
|
SleepEx(0,TRUE);
|
||||||
|
CloseHandle(threadinfo->hThread);
|
||||||
|
CloseHandle(threadinfo->WaitEvent);
|
||||||
|
HeapFree(GetProcessHeap(),0,threadinfo);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
static DWORD WaitThreadWait(PWAIT_THREAD threadinfo)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int nCount = threadinfo->nItems * 2;
|
||||||
|
HANDLE* handles = (HANDLE*)alloca(sizeof(HANDLE)*nCount);
|
||||||
|
for (i=0;i<threadinfo->nItems;i++)
|
||||||
|
{
|
||||||
|
handles[i*2] = threadinfo->waitItems[i]->Object;
|
||||||
|
handles[(i*2)+1] = threadinfo->waitItems[i]->TimerObject;
|
||||||
|
}
|
||||||
|
return WaitForMultipleObjectsEx(nCount,handles,FALSE,INFINITE,TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK WaitThreadProc(LPVOID Arg)
|
||||||
|
{
|
||||||
|
PWAIT_THREAD threadinfo = (PWAIT_THREAD)Arg;
|
||||||
|
//wait for first APC to come
|
||||||
|
SleepEx(INFINITE,TRUE);
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
SetEvent(threadinfo->WaitEvent);
|
||||||
|
if (!threadinfo->nItems) //no things to do, wait 3 seconds and leave
|
||||||
|
{
|
||||||
|
if (SleepEx(3000,TRUE)!=WAIT_IO_COMPLETION)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DWORD status = WaitThreadWait(threadinfo);
|
||||||
|
ResetEvent(threadinfo->WaitEvent);
|
||||||
|
if (status == WAIT_FAILED) break; //FFFFFUUUU
|
||||||
|
if (status >= WAIT_OBJECT_0 && status <= WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS )
|
||||||
|
{
|
||||||
|
status -= WAIT_OBJECT_0;
|
||||||
|
PWAIT_WORK_ITEM workItem = threadinfo->waitItems[status/2];
|
||||||
|
BOOL TimerFired = (status & 1);
|
||||||
|
if (workItem->State != WAIT_STATE_ACTIVE) continue; //don't run if removed
|
||||||
|
if (workItem->CallbackEvent == NULL) //sync callback
|
||||||
|
{
|
||||||
|
SetEvent(threadinfo->WaitEvent);
|
||||||
|
threadinfo->InSyncCallback = TRUE;
|
||||||
|
workItem->Callback(workItem->Context,TimerFired);
|
||||||
|
threadinfo->InSyncCallback = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PASYNC_CALL waiter = (PASYNC_CALL)HeapAlloc(GetProcessHeap(),0,sizeof(*waiter));
|
||||||
|
if (waiter)
|
||||||
|
{
|
||||||
|
waiter->item = workItem;
|
||||||
|
waiter->TimerOrWaitFired = TimerFired;
|
||||||
|
InterlockedIncrement(&workItem->CallbacksPending);
|
||||||
|
QueueUserWorkItem_new(AsyncWaiterCall,waiter,workItem->Flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (workItem->Flags & WT_EXECUTEONLYONCE || workItem->Milliseconds == 0)
|
||||||
|
RemoveWaitItem((ULONG_PTR)workItem);
|
||||||
|
else
|
||||||
|
ActivateTimer(workItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TerminateWaitThread(threadinfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL RegisterWaitItem(PWAIT_WORK_ITEM workItem)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&wait_cs);
|
||||||
|
BOOL success = FALSE;
|
||||||
|
int i;
|
||||||
|
for (i=0;i<MAX_WAIT_THREADS;i++)
|
||||||
|
{
|
||||||
|
if (waitthreads[i] == NULL)
|
||||||
|
{
|
||||||
|
DWORD dummy;
|
||||||
|
waitthreads[i] = (PWAIT_THREAD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*waitthreads[i]));
|
||||||
|
if (waitthreads[i] != NULL)
|
||||||
|
waitthreads[i]->hThread = CreateThread(NULL, 0, WaitThreadProc, waitthreads[i], 0, &dummy);
|
||||||
|
if (waitthreads[i]->hThread == NULL)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(),0,waitthreads[i]);
|
||||||
|
waitthreads[i]=NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
waitthreads[i]->WaitEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
|
||||||
|
}
|
||||||
|
if (waitthreads[i]->nItems == MAX_WAIT_ITEMS || waitthreads[i]->InSyncCallback) //full or busy, gtfo
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//try adding it
|
||||||
|
workItem->waitThread = waitthreads[i];
|
||||||
|
workItem->CompletionEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
if ( QueueUserAPC(AddWaitItem,waitthreads[i]->hThread,(ULONG_PTR)workItem) )
|
||||||
|
{
|
||||||
|
//wait until item is added
|
||||||
|
WaitForSingleObject(workItem->CompletionEvent,INFINITE);
|
||||||
|
success = (workItem->waitThread != NULL);
|
||||||
|
}
|
||||||
|
CloseHandle(workItem->CompletionEvent);
|
||||||
|
workItem->CompletionEvent = NULL;
|
||||||
|
if (success) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&wait_cs);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL IsValidHandle( HANDLE hObject )
|
||||||
|
{
|
||||||
|
HANDLE newobject = NULL;
|
||||||
|
BOOL success = DuplicateHandle(GetCurrentProcess(),hObject,GetCurrentProcess(),&newobject,0,0,DUPLICATE_SAME_ACCESS);
|
||||||
|
if (success) CloseHandle(newobject);
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAKE_EXPORT RegisterWaitForSingleObject_new=RegisterWaitForSingleObject */
|
/* MAKE_EXPORT RegisterWaitForSingleObject_new=RegisterWaitForSingleObject */
|
||||||
BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback,
|
BOOL WINAPI RegisterWaitForSingleObject_new(
|
||||||
PVOID Context, ULONG dwMilliseconds, ULONG dwFlags)
|
PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback,
|
||||||
|
PVOID Context, ULONG dwMilliseconds, ULONG dwFlags)
|
||||||
{
|
{
|
||||||
//validate stuff first. we aren't Wine.
|
if (!phNewWaitObject || IsBadCodePtr((FARPROC)Callback) || !IsValidHandle(hObject))
|
||||||
if (!phNewWaitObject || IsBadCodePtr((FARPROC)Callback) || WaitForSingleObject(hObject,0) == WAIT_FAILED)
|
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
wait_work_item_ptr wait_work_item;
|
PWAIT_WORK_ITEM newWorkItem = (PWAIT_WORK_ITEM)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*newWorkItem));
|
||||||
wait_work_item = (wait_work_item_ptr)HeapAlloc(GetProcessHeap(), 0, sizeof(*wait_work_item));
|
if (!newWorkItem) return FALSE;
|
||||||
|
newWorkItem->Object = hObject;
|
||||||
|
newWorkItem->Callback = Callback;
|
||||||
|
newWorkItem->Context = Context;
|
||||||
|
newWorkItem->Milliseconds = dwMilliseconds;
|
||||||
|
newWorkItem->Flags = dwFlags;
|
||||||
|
if (!(dwFlags & WT_EXECUTEINWAITTHREAD))
|
||||||
|
newWorkItem->CallbackEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
newWorkItem->State = WAIT_STATE_ACTIVE;
|
||||||
|
if (dwMilliseconds != INFINITE)
|
||||||
|
newWorkItem->TimerObject = CreateWaitableTimer(NULL,FALSE,NULL);
|
||||||
|
else
|
||||||
|
newWorkItem->TimerObject = CreateEvent(NULL,FALSE,FALSE,NULL); //dummy event which never fires
|
||||||
|
|
||||||
if (!wait_work_item)
|
if (!RegisterWaitItem(newWorkItem))
|
||||||
{
|
{
|
||||||
|
DestroyWaitItem(newWorkItem);
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
*phNewWaitObject = (HANDLE)newWorkItem;
|
||||||
if ( dwMilliseconds == 0 ) dwFlags |= WT_EXECUTEONLYONCE;
|
return TRUE;
|
||||||
wait_work_item->Object = hObject;
|
}
|
||||||
wait_work_item->Callback = Callback;
|
|
||||||
wait_work_item->Context = Context;
|
|
||||||
wait_work_item->Milliseconds = dwMilliseconds;
|
|
||||||
wait_work_item->Flags = dwFlags;
|
|
||||||
wait_work_item->CallbackInProgress = FALSE;
|
|
||||||
wait_work_item->DeleteCount = 0;
|
|
||||||
wait_work_item->CompletionEvent = NULL;
|
|
||||||
wait_work_item->CancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
||||||
if (!wait_work_item->CancelEvent)
|
|
||||||
{
|
|
||||||
HeapFree( GetProcessHeap(), 0, wait_work_item );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !QueueUserWorkItem_new(wait_thread_proc, wait_work_item, dwFlags) )
|
/* MAKE_EXPORT UnregisterWaitEx_new=UnregisterWaitEx */
|
||||||
{
|
BOOL WINAPI UnregisterWaitEx_new( HANDLE WaitHandle, HANDLE CompletionEvent)
|
||||||
delete_wait_work_item( wait_work_item );
|
{
|
||||||
return FALSE;
|
PWAIT_WORK_ITEM workItem = (PWAIT_WORK_ITEM)WaitHandle;
|
||||||
}
|
if (!workItem)
|
||||||
|
{
|
||||||
*phNewWaitObject = (HANDLE)wait_work_item;
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return TRUE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
//9x dies if we queue an apc into dead thread so avoid it at all costs
|
||||||
|
if ( InterlockedCompareExchange(&workItem->State,WAIT_STATE_UNREGISTERED,WAIT_STATE_ACTIVE)==WAIT_STATE_ACTIVE )
|
||||||
|
{
|
||||||
|
PWAIT_THREAD waitthread = (PWAIT_THREAD)workItem->waitThread;
|
||||||
|
if (!QueueUserAPC(RemoveWaitItem,waitthread->hThread,(ULONG_PTR)workItem))
|
||||||
|
return FALSE;
|
||||||
|
//make sure thread is in wait state and isn't doing sth with item we delete
|
||||||
|
WaitForSingleObject(waitthread->WaitEvent,NONSENSE);
|
||||||
|
}
|
||||||
|
InterlockedCompareExchange(&workItem->State,WAIT_STATE_REMOVED,WAIT_STATE_ABANDONED);
|
||||||
|
BOOL pending = FALSE;
|
||||||
|
if (workItem->CallbacksPending)
|
||||||
|
{
|
||||||
|
pending = TRUE;
|
||||||
|
if (CompletionEvent != NULL)
|
||||||
|
{
|
||||||
|
if (CompletionEvent == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
//wait for callbacks to finish
|
||||||
|
while (workItem->CallbacksPending)
|
||||||
|
WaitForSingleObject(workItem->CallbackEvent,INFINITE);
|
||||||
|
pending = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
InterlockedExchangePointer(&workItem->CompletionEvent, CompletionEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//all async callbacks are finished for sure?
|
||||||
|
if (!pending)
|
||||||
|
{
|
||||||
|
//yes? and the item is removed from thread?
|
||||||
|
if (InterlockedCompareExchange(&workItem->State,WAIT_STATE_GAMEOVER,WAIT_STATE_REMOVED) == WAIT_STATE_REMOVED)
|
||||||
|
DestroyWaitItem(workItem);
|
||||||
|
else //not removed? okay, it will be destroyed with removal
|
||||||
|
InterlockedCompareExchange(&workItem->State,WAIT_STATE_DELETESYNC,WAIT_STATE_UNREGISTERED);
|
||||||
|
}
|
||||||
|
//otherwise, there are still pending callbacks and item will be destroyed as soon as all callbacks end
|
||||||
|
if (pending)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_IO_PENDING);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAKE_EXPORT RegisterWaitForSingleObjectEx_new=RegisterWaitForSingleObjectEx */
|
/* MAKE_EXPORT RegisterWaitForSingleObjectEx_new=RegisterWaitForSingleObjectEx */
|
||||||
@ -179,60 +459,366 @@ HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAKE_EXPORT UnregisterWaitEx_new=UnregisterWaitEx */
|
|
||||||
BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent)
|
|
||||||
{
|
|
||||||
if (!WaitHandle)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
BOOL pending = FALSE;
|
|
||||||
wait_work_item_ptr wait_work_item = (wait_work_item_ptr)WaitHandle;
|
|
||||||
if ( !SetEvent( wait_work_item->CancelEvent ) ) //signal cancel
|
|
||||||
return FALSE;
|
|
||||||
if (wait_work_item->CallbackInProgress)
|
|
||||||
{
|
|
||||||
if (CompletionEvent != NULL)
|
|
||||||
{
|
|
||||||
if (CompletionEvent == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CompletionEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
||||||
if (!CompletionEvent)
|
|
||||||
return FALSE;
|
|
||||||
InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent );
|
|
||||||
if (wait_work_item->CallbackInProgress)
|
|
||||||
WaitForSingleObject( CompletionEvent, INFINITE );
|
|
||||||
CloseHandle( CompletionEvent );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InterlockedExchangePointer( &wait_work_item->CompletionEvent, CompletionEvent );
|
|
||||||
if (wait_work_item->CallbackInProgress)
|
|
||||||
pending = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pending = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( InterlockedIncrement(&wait_work_item->DeleteCount) == 2 )
|
|
||||||
{
|
|
||||||
pending = FALSE; //somehow callback is complete already
|
|
||||||
delete_wait_work_item( wait_work_item );
|
|
||||||
}
|
|
||||||
if ( pending )
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_IO_PENDING);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MAKE_EXPORT UnregisterWait_new=UnregisterWait */
|
/* MAKE_EXPORT UnregisterWait_new=UnregisterWait */
|
||||||
BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle)
|
BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle)
|
||||||
{
|
{
|
||||||
return UnregisterWaitEx_new(WaitHandle,NULL);
|
return UnregisterWaitEx_new(WaitHandle,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timer Queue routines
|
||||||
|
#define MAX_TIMERS MAXIMUM_WAIT_OBJECTS
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HANDLE TimerObject;
|
||||||
|
WAITORTIMERCALLBACK Callback;
|
||||||
|
PVOID Parameter;
|
||||||
|
ULONG DueTime;
|
||||||
|
DWORD Period;
|
||||||
|
ULONG Flags;
|
||||||
|
PVOID TimerQueue;
|
||||||
|
LONG State;
|
||||||
|
LONG CallbacksPending;
|
||||||
|
HANDLE CompletionEvent;
|
||||||
|
HANDLE CallbackEvent;
|
||||||
|
} TIMER_ITEM, *PTIMER_ITEM;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HANDLE hThread;
|
||||||
|
HANDLE WaitEvent;
|
||||||
|
HANDLE CompletionEvent;
|
||||||
|
LONG nItems;
|
||||||
|
PTIMER_ITEM timers[MAX_TIMERS];
|
||||||
|
} TIMER_QUEUE, *PTIMER_QUEUE;
|
||||||
|
|
||||||
|
static PTIMER_QUEUE defaultTimerQueue = NULL;
|
||||||
|
|
||||||
|
static VOID DestroyTimerItem(PTIMER_ITEM timer)
|
||||||
|
{
|
||||||
|
CloseHandle(timer->CallbackEvent);
|
||||||
|
CloseHandle(timer->TimerObject);
|
||||||
|
HeapFree(GetProcessHeap(),0,timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK ChangeTimerItem(PTIMER_ITEM timer)
|
||||||
|
{
|
||||||
|
//(re)activate waitable timer
|
||||||
|
LARGE_INTEGER timeout;
|
||||||
|
timeout.QuadPart = timer->DueTime * (LONGLONG)-10000;
|
||||||
|
SetWaitableTimer(timer->TimerObject,&timeout,(timer->Flags & WT_EXECUTEONLYONCE) ? 0 : timer->Period,NULL,NULL,FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK AddTimerItem(ULONG_PTR Arg)
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)Arg;
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)timer->TimerQueue;
|
||||||
|
if (timerqueue->nItems == MAX_TIMERS) //too much timers
|
||||||
|
{
|
||||||
|
timer->TimerQueue = NULL;
|
||||||
|
SetEvent(timer->CompletionEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timerqueue->timers[timerqueue->nItems] = timer;
|
||||||
|
timerqueue->nItems++;
|
||||||
|
SetEvent(timer->CompletionEvent);
|
||||||
|
ChangeTimerItem(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK RemoveTimerItem(ULONG_PTR Arg)
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)Arg;
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)timer->TimerQueue;
|
||||||
|
int i, j;
|
||||||
|
for (i=0;i<MAX_TIMERS;i++)
|
||||||
|
if (timerqueue->timers[i] == timer)
|
||||||
|
break;
|
||||||
|
if (i<MAX_TIMERS)
|
||||||
|
{
|
||||||
|
for (j=i;j<timerqueue->nItems-1;j++)
|
||||||
|
{
|
||||||
|
timerqueue->timers[j]=timerqueue->timers[j+1];
|
||||||
|
timerqueue->timers[j+1]=NULL;
|
||||||
|
}
|
||||||
|
timerqueue->nItems--;
|
||||||
|
}
|
||||||
|
//if unregister marked it for delete, kill it here
|
||||||
|
if (InterlockedCompareExchange(&timer->State,WAIT_STATE_GAMEOVER,WAIT_STATE_DELETESYNC) == WAIT_STATE_DELETESYNC)
|
||||||
|
{
|
||||||
|
if (timer->CompletionEvent) SetEvent(timer->CompletionEvent);
|
||||||
|
DestroyTimerItem(timer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
InterlockedCompareExchange(&timer->State,WAIT_STATE_REMOVED,WAIT_STATE_UNREGISTERED); //mark it removed
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK AsyncTimerCall(LPVOID Arg)
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = PTIMER_ITEM(Arg);
|
||||||
|
if (timer->State == WAIT_STATE_ACTIVE)
|
||||||
|
timer->Callback(timer->Parameter,TRUE);
|
||||||
|
LONG CallbacksPending = InterlockedDecrement(&timer->CallbacksPending);
|
||||||
|
SetEvent(timer->CallbackEvent);
|
||||||
|
if (CallbacksPending == 0 && timer->State != WAIT_STATE_ACTIVE)
|
||||||
|
{
|
||||||
|
//if it's removed, all fine, destroy it here
|
||||||
|
if (InterlockedCompareExchange(&timer->State,WAIT_STATE_GAMEOVER,WAIT_STATE_REMOVED) == WAIT_STATE_REMOVED)
|
||||||
|
{
|
||||||
|
if (timer->CompletionEvent) SetEvent(timer->CompletionEvent);
|
||||||
|
DestroyTimerItem(timer);
|
||||||
|
}
|
||||||
|
else //destroy it with removal
|
||||||
|
InterlockedCompareExchange(&timer->State,WAIT_STATE_DELETESYNC,WAIT_STATE_UNREGISTERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT DeleteTimerQueueTimer_new=DeleteTimerQueueTimer */
|
||||||
|
BOOL WINAPI DeleteTimerQueueTimer_new( HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
|
||||||
|
{
|
||||||
|
//absolutely equal to UnregisterWaitEx
|
||||||
|
if (!Timer)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)Timer;
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)timer->TimerQueue;
|
||||||
|
if ( InterlockedCompareExchange(&timer->State,WAIT_STATE_UNREGISTERED,WAIT_STATE_ACTIVE)==WAIT_STATE_ACTIVE )
|
||||||
|
{
|
||||||
|
if (!QueueUserAPC(RemoveTimerItem,timerqueue->hThread,(ULONG_PTR)timer))
|
||||||
|
return FALSE;
|
||||||
|
//make sure thread is in wait state and isn't doing sth with item we delete
|
||||||
|
WaitForSingleObject(timerqueue->WaitEvent,NONSENSE);
|
||||||
|
}
|
||||||
|
BOOL pending = FALSE;
|
||||||
|
if (timer->CallbacksPending)
|
||||||
|
{
|
||||||
|
pending = TRUE;
|
||||||
|
if (CompletionEvent != NULL)
|
||||||
|
{
|
||||||
|
if (CompletionEvent == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
while (timer->CallbacksPending)
|
||||||
|
WaitForSingleObject(timer->CallbackEvent,INFINITE);
|
||||||
|
pending = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
InterlockedExchangePointer(&timer->CompletionEvent, CompletionEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pending)
|
||||||
|
{
|
||||||
|
if (InterlockedCompareExchange(&timer->State,WAIT_STATE_GAMEOVER,WAIT_STATE_REMOVED) == WAIT_STATE_REMOVED)
|
||||||
|
DestroyTimerItem(timer);
|
||||||
|
else
|
||||||
|
InterlockedCompareExchange(&timer->State,WAIT_STATE_DELETESYNC,WAIT_STATE_UNREGISTERED);
|
||||||
|
}
|
||||||
|
if (pending)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_IO_PENDING);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK TerminateTimerQueue(ULONG_PTR Arg)
|
||||||
|
{
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)Arg;
|
||||||
|
CloseHandle(timerqueue->hThread);
|
||||||
|
CloseHandle(timerqueue->WaitEvent);
|
||||||
|
HeapFree(GetProcessHeap(),0,timerqueue);
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK FinishTimerQueue(ULONG_PTR Arg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)Arg;
|
||||||
|
EnterCriticalSection(&wait_cs);
|
||||||
|
if (defaultTimerQueue == timerqueue)
|
||||||
|
defaultTimerQueue = NULL;
|
||||||
|
LeaveCriticalSection(&wait_cs);
|
||||||
|
//delete all timers, waiting
|
||||||
|
for (i=timerqueue->nItems-1;i>=0;i--)
|
||||||
|
DeleteTimerQueueTimer_new( timerqueue, timerqueue->timers[i], INVALID_HANDLE_VALUE );
|
||||||
|
if (timerqueue->CompletionEvent)
|
||||||
|
SetEvent(timerqueue->CompletionEvent);
|
||||||
|
//queue object termination
|
||||||
|
QueueUserAPC(TerminateTimerQueue,GetCurrentThread(),Arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD TimerQueueWait(PTIMER_QUEUE timerqueue)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
HANDLE* handles = (HANDLE*)alloca(sizeof(HANDLE)*timerqueue->nItems);
|
||||||
|
for (i=0;i<timerqueue->nItems;i++)
|
||||||
|
handles[i] = timerqueue->timers[i]->TimerObject;
|
||||||
|
|
||||||
|
return WaitForMultipleObjectsEx(timerqueue->nItems,handles,FALSE,INFINITE,TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK TimerQueueProc(LPVOID Arg)
|
||||||
|
{
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)Arg;
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
SetEvent(timerqueue->WaitEvent);
|
||||||
|
if (!timerqueue->nItems) //wait for items
|
||||||
|
{
|
||||||
|
SleepEx(INFINITE,TRUE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DWORD status = TimerQueueWait(timerqueue);
|
||||||
|
ResetEvent(timerqueue->WaitEvent);
|
||||||
|
if (status == WAIT_FAILED) break; //uberfail
|
||||||
|
if (status >= WAIT_OBJECT_0 && status <= WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS )
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = timerqueue->timers[status-WAIT_OBJECT_0];
|
||||||
|
if (timer->State != WAIT_STATE_ACTIVE) continue;
|
||||||
|
if (timer->CallbackEvent == NULL) //sync callback
|
||||||
|
{
|
||||||
|
SetEvent(timerqueue->WaitEvent);
|
||||||
|
timer->Callback(timer->Parameter,TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&timer->CallbacksPending);
|
||||||
|
QueueUserWorkItem_new(AsyncTimerCall,timer,timer->Flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FinishTimerQueue((ULONG_PTR)timerqueue);
|
||||||
|
SleepEx(0,TRUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT CreateTimerQueue_new=CreateTimerQueue */
|
||||||
|
HANDLE WINAPI CreateTimerQueue_new(VOID)
|
||||||
|
{
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*timerqueue));
|
||||||
|
if (timerqueue != NULL)
|
||||||
|
{
|
||||||
|
DWORD dummy;
|
||||||
|
timerqueue->WaitEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
|
||||||
|
timerqueue->hThread = CreateThread(NULL,0,TimerQueueProc,timerqueue,0,&dummy);
|
||||||
|
if (!timerqueue->hThread)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(),HEAP_ZERO_MEMORY,timerqueue);
|
||||||
|
timerqueue = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (HANDLE)timerqueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT CreateTimerQueueTimer_new=CreateTimerQueueTimer */
|
||||||
|
BOOL WINAPI CreateTimerQueueTimer_new( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback,
|
||||||
|
PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
|
||||||
|
{
|
||||||
|
if (!phNewTimer || IsBadCodePtr((FARPROC)Callback))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*phNewTimer = NULL;
|
||||||
|
if (TimerQueue == NULL)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&wait_cs);
|
||||||
|
if (defaultTimerQueue == NULL)
|
||||||
|
defaultTimerQueue = (PTIMER_QUEUE)CreateTimerQueue_new();
|
||||||
|
TimerQueue = defaultTimerQueue;
|
||||||
|
LeaveCriticalSection(&wait_cs);
|
||||||
|
if (TimerQueue == NULL) return FALSE;
|
||||||
|
}
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*timer));
|
||||||
|
timer->TimerQueue = TimerQueue;
|
||||||
|
timer->Callback = Callback;
|
||||||
|
timer->Parameter = Parameter;
|
||||||
|
timer->DueTime = DueTime;
|
||||||
|
timer->Period = Period;
|
||||||
|
timer->Flags = Flags;
|
||||||
|
timer->State = WAIT_STATE_ACTIVE;
|
||||||
|
timer->TimerObject = CreateWaitableTimer(NULL,FALSE,NULL);
|
||||||
|
if (!(Flags & WT_EXECUTEINTIMERTHREAD))
|
||||||
|
timer->CallbackEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
timer->CompletionEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
BOOL success = (BOOL)QueueUserAPC(AddTimerItem,((PTIMER_QUEUE)TimerQueue)->hThread,(ULONG_PTR)timer);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(timer->CompletionEvent,INFINITE);
|
||||||
|
CloseHandle(timer->CompletionEvent);
|
||||||
|
timer->CompletionEvent = NULL;
|
||||||
|
success = (timer->TimerObject != NULL);
|
||||||
|
if (success) *phNewTimer = timer;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT DeleteTimerQueueEx_new=DeleteTimerQueueEx */
|
||||||
|
BOOL WINAPI DeleteTimerQueueEx_new( HANDLE TimerQueue, HANDLE CompletionEvent)
|
||||||
|
{
|
||||||
|
PTIMER_QUEUE timerqueue = (PTIMER_QUEUE)TimerQueue;
|
||||||
|
if (!timerqueue)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (CompletionEvent != NULL)
|
||||||
|
{
|
||||||
|
if (CompletionEvent == INVALID_HANDLE_VALUE)
|
||||||
|
timerqueue->CompletionEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
else
|
||||||
|
timerqueue->CompletionEvent = CompletionEvent;
|
||||||
|
}
|
||||||
|
QueueUserAPC(FinishTimerQueue,timerqueue->hThread,(ULONG_PTR)timerqueue);
|
||||||
|
if (CompletionEvent == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(timerqueue->CompletionEvent,INFINITE);
|
||||||
|
CloseHandle(timerqueue->CompletionEvent);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT DeleteTimerQueue_new=DeleteTimerQueue */
|
||||||
|
BOOL WINAPI DeleteTimerQueue_new( HANDLE TimerQueue)
|
||||||
|
{
|
||||||
|
return DeleteTimerQueueEx_new(TimerQueue,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT ChangeTimerQueueTimer_new=ChangeTimerQueueTimer */
|
||||||
|
BOOL WINAPI ChangeTimerQueueTimer_new( HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period)
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)Timer;
|
||||||
|
if (!timer || timer->State != WAIT_STATE_ACTIVE)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
timer->DueTime = DueTime;
|
||||||
|
timer->Period = Period;
|
||||||
|
return (BOOL)QueueUserAPC((PAPCFUNC)ChangeTimerItem,((PTIMER_QUEUE)timer->TimerQueue)->hThread,(ULONG_PTR)timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//some undocumented APIs too...
|
||||||
|
|
||||||
|
/* MAKE_EXPORT CancelTimerQueueTimer_new=CancelTimerQueueTimer */
|
||||||
|
BOOL WINAPI CancelTimerQueueTimer_new( HANDLE TimerQueue, HANDLE Timer)
|
||||||
|
{
|
||||||
|
PTIMER_ITEM timer = (PTIMER_ITEM)Timer;
|
||||||
|
if (!timer || timer->State != WAIT_STATE_ACTIVE)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return CancelWaitableTimer(timer->TimerObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT SetTimerQueueTimer_new=SetTimerQueueTimer */
|
||||||
|
HANDLE WINAPI SetTimerQueueTimer_new( HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo )
|
||||||
|
{
|
||||||
|
HANDLE newHandle = NULL;
|
||||||
|
CreateTimerQueueTimer_new(&newHandle,TimerQueue,Callback,Parameter,DueTime,Period,PreferIo ? WT_EXECUTEINIOTHREAD : WT_EXECUTEDEFAULT);
|
||||||
|
return newHandle;
|
||||||
|
}
|
||||||
|
@ -23,19 +23,18 @@
|
|||||||
#include "kexcoresdk.h"
|
#include "kexcoresdk.h"
|
||||||
#include "_kernel32_apilist.h"
|
#include "_kernel32_apilist.h"
|
||||||
|
|
||||||
|
extern BOOL init_threadpool();
|
||||||
extern BOOL init_jemalloc();
|
extern BOOL init_jemalloc();
|
||||||
extern BOOL init_exttls();
|
extern BOOL init_exttls();
|
||||||
extern void uninit_jemalloc();
|
|
||||||
extern void detach_exttls();
|
extern void detach_exttls();
|
||||||
|
|
||||||
BOOL init_kernel32()
|
BOOL init_kernel32()
|
||||||
{
|
{
|
||||||
return init_jemalloc() && init_exttls();
|
return init_jemalloc() && init_exttls() && init_threadpool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninit_kernel32()
|
void uninit_kernel32()
|
||||||
{
|
{
|
||||||
uninit_jemalloc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void detach_kernel32()
|
void detach_kernel32()
|
||||||
@ -49,6 +48,8 @@ static const apilib_named_api kernel32_named_apis[] =
|
|||||||
DECL_API("BuildCommDCBAndTimeoutsW", BuildCommDCBAndTimeoutsW_fwd),
|
DECL_API("BuildCommDCBAndTimeoutsW", BuildCommDCBAndTimeoutsW_fwd),
|
||||||
DECL_API("BuildCommDCBW", BuildCommDCBW_fwd),
|
DECL_API("BuildCommDCBW", BuildCommDCBW_fwd),
|
||||||
DECL_API("CallNamedPipeW", CallNamedPipeW_fwd),
|
DECL_API("CallNamedPipeW", CallNamedPipeW_fwd),
|
||||||
|
DECL_API("CancelTimerQueueTimer", CancelTimerQueueTimer_new),
|
||||||
|
DECL_API("ChangeTimerQueueTimer", ChangeTimerQueueTimer_new),
|
||||||
DECL_API("CommConfigDialogW", CommConfigDialogW_fwd),
|
DECL_API("CommConfigDialogW", CommConfigDialogW_fwd),
|
||||||
DECL_API("CreateEventW", CreateEventW_fwd),
|
DECL_API("CreateEventW", CreateEventW_fwd),
|
||||||
DECL_API("CreateFileMappingW", CreateFileMappingW_fwd),
|
DECL_API("CreateFileMappingW", CreateFileMappingW_fwd),
|
||||||
@ -56,8 +57,13 @@ static const apilib_named_api kernel32_named_apis[] =
|
|||||||
DECL_API("CreateMutexW", CreateMutexW_fwd),
|
DECL_API("CreateMutexW", CreateMutexW_fwd),
|
||||||
DECL_API("CreateProcessW", CreateProcessW_fwd),
|
DECL_API("CreateProcessW", CreateProcessW_fwd),
|
||||||
DECL_API("CreateSemaphoreW", CreateSemaphoreW_fwd),
|
DECL_API("CreateSemaphoreW", CreateSemaphoreW_fwd),
|
||||||
|
DECL_API("CreateTimerQueue", CreateTimerQueue_new),
|
||||||
|
DECL_API("CreateTimerQueueTimer", CreateTimerQueueTimer_new),
|
||||||
DECL_API("CreateWaitableTimerW", CreateWaitableTimerW_fwd),
|
DECL_API("CreateWaitableTimerW", CreateWaitableTimerW_fwd),
|
||||||
DECL_API("DelayLoadFailureHook", DelayLoadFailureHook_new),
|
DECL_API("DelayLoadFailureHook", DelayLoadFailureHook_new),
|
||||||
|
DECL_API("DeleteTimerQueue", DeleteTimerQueue_new),
|
||||||
|
DECL_API("DeleteTimerQueueEx", DeleteTimerQueueEx_new),
|
||||||
|
DECL_API("DeleteTimerQueueTimer", DeleteTimerQueueTimer_new),
|
||||||
DECL_API("EnumCalendarInfoExW", EnumCalendarInfoExW_fwd),
|
DECL_API("EnumCalendarInfoExW", EnumCalendarInfoExW_fwd),
|
||||||
DECL_API("EnumCalendarInfoW", EnumCalendarInfoW_fwd),
|
DECL_API("EnumCalendarInfoW", EnumCalendarInfoW_fwd),
|
||||||
DECL_API("EnumDateFormatsExW", EnumDateFormatsExW_fwd),
|
DECL_API("EnumDateFormatsExW", EnumDateFormatsExW_fwd),
|
||||||
@ -118,6 +124,7 @@ static const apilib_named_api kernel32_named_apis[] =
|
|||||||
DECL_API("SetDefaultCommConfigW", SetDefaultCommConfigW_fwd),
|
DECL_API("SetDefaultCommConfigW", SetDefaultCommConfigW_fwd),
|
||||||
DECL_API("SetEnvironmentVariableW", SetEnvironmentVariableW_fwd),
|
DECL_API("SetEnvironmentVariableW", SetEnvironmentVariableW_fwd),
|
||||||
DECL_API("SetLocaleInfoW", SetLocaleInfoW_fwd),
|
DECL_API("SetLocaleInfoW", SetLocaleInfoW_fwd),
|
||||||
|
DECL_API("SetTimerQueueTimer", SetTimerQueueTimer_new),
|
||||||
DECL_API("SetVolumeLabelW", SetVolumeLabelW_fwd),
|
DECL_API("SetVolumeLabelW", SetVolumeLabelW_fwd),
|
||||||
DECL_API("TlsAlloc", TlsAlloc_new),
|
DECL_API("TlsAlloc", TlsAlloc_new),
|
||||||
DECL_API("TlsFree", TlsFree_new),
|
DECL_API("TlsFree", TlsFree_new),
|
||||||
|
@ -33,9 +33,17 @@ extern const apilib_api_table apitable_kernel32;
|
|||||||
FARPROC WINAPI DelayLoadFailureHook_new(LPSTR pszDllName, LPSTR pszProcName);
|
FARPROC WINAPI DelayLoadFailureHook_new(LPSTR pszDllName, LPSTR pszProcName);
|
||||||
BOOL WINAPI QueueUserWorkItem_new(LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags);
|
BOOL WINAPI QueueUserWorkItem_new(LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags);
|
||||||
BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags);
|
BOOL WINAPI RegisterWaitForSingleObject_new(PHANDLE phNewWaitObject, HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags);
|
||||||
HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags);
|
|
||||||
BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent);
|
BOOL WINAPI UnregisterWaitEx_new(HANDLE WaitHandle, HANDLE CompletionEvent);
|
||||||
|
HANDLE WINAPI RegisterWaitForSingleObjectEx_new(HANDLE hObject, WAITORTIMERCALLBACK Callback, PVOID Context, ULONG dwMilliseconds, ULONG dwFlags);
|
||||||
BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle);
|
BOOL WINAPI UnregisterWait_new(HANDLE WaitHandle);
|
||||||
|
BOOL WINAPI DeleteTimerQueueTimer_new(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent);
|
||||||
|
HANDLE WINAPI CreateTimerQueue_new(VOID);
|
||||||
|
BOOL WINAPI CreateTimerQueueTimer_new(PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags);
|
||||||
|
BOOL WINAPI DeleteTimerQueueEx_new(HANDLE TimerQueue, HANDLE CompletionEvent);
|
||||||
|
BOOL WINAPI DeleteTimerQueue_new(HANDLE TimerQueue);
|
||||||
|
BOOL WINAPI ChangeTimerQueueTimer_new(HANDLE TimerQueue, HANDLE Timer, ULONG DueTime, ULONG Period);
|
||||||
|
BOOL WINAPI CancelTimerQueueTimer_new(HANDLE TimerQueue, HANDLE Timer);
|
||||||
|
HANDLE WINAPI SetTimerQueueTimer_new(HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID Parameter, DWORD DueTime, DWORD Period, BOOL PreferIo);
|
||||||
DWORD WINAPI TlsAlloc_new(void);
|
DWORD WINAPI TlsAlloc_new(void);
|
||||||
BOOL WINAPI TlsFree_new(DWORD dwTlsIndex);
|
BOOL WINAPI TlsFree_new(DWORD dwTlsIndex);
|
||||||
LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex);
|
LPVOID WINAPI TlsGetValue_new2(DWORD dwTlsIndex);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* KernelEx
|
* KernelEx
|
||||||
* Copyright (C) 2009, Xeno86
|
* Copyright (C) 2009-2010, Xeno86
|
||||||
*
|
*
|
||||||
* This file is part of KernelEx source code.
|
* This file is part of KernelEx source code.
|
||||||
*
|
*
|
||||||
@ -43,6 +43,8 @@
|
|||||||
/* M A C R O S A N D W R A P P E R S */
|
/* M A C R O S A N D W R A P P E R S */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define malloc(a) je_malloc(a)
|
#define malloc(a) je_malloc(a)
|
||||||
#define valloc(a) je_valloc(a)
|
#define valloc(a) je_valloc(a)
|
||||||
#define calloc(a, b) je_calloc(a, b)
|
#define calloc(a, b) je_calloc(a, b)
|
||||||
@ -79,11 +81,6 @@ BOOL init_jemalloc()
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninit_jemalloc()
|
|
||||||
{
|
|
||||||
malloc_print_stats();
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* T H E C O D E */
|
/* T H E C O D E */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
@ -193,8 +190,15 @@ BOOL WINAPI HeapFree_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
|
|||||||
{
|
{
|
||||||
if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP)
|
if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP)
|
||||||
{
|
{
|
||||||
free(lpMem);
|
if (lpMem && idalloc(lpMem))
|
||||||
return TRUE;
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return HeapFree(hHeap, dwFlags, lpMem);
|
return HeapFree(hHeap, dwFlags, lpMem);
|
||||||
@ -206,6 +210,8 @@ DWORD WINAPI HeapSize_new(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
|
|||||||
if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP)
|
if (hHeap == JM_HEAP_NORM || hHeap == JM_HEAP_EXCP)
|
||||||
{
|
{
|
||||||
size_t usable = malloc_usable_size(lpMem);
|
size_t usable = malloc_usable_size(lpMem);
|
||||||
|
if (usable == 0)
|
||||||
|
return (DWORD) -1;
|
||||||
int fs = footer_size_for_usable_size(usable);
|
int fs = footer_size_for_usable_size(usable);
|
||||||
|
|
||||||
return read_footer(lpMem, usable, fs);
|
return read_footer(lpMem, usable, fs);
|
||||||
@ -221,7 +227,14 @@ LPVOID WINAPI HeapReAlloc_new(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, DWORD d
|
|||||||
{
|
{
|
||||||
LPVOID ret;
|
LPVOID ret;
|
||||||
int fs = footer_size(dwBytes);
|
int fs = footer_size(dwBytes);
|
||||||
size_t usable = malloc_usable_size(lpMem);
|
size_t usable = lpMem ? malloc_usable_size(lpMem) : 0;
|
||||||
|
|
||||||
|
if (lpMem && usable == 0)
|
||||||
|
{
|
||||||
|
if (hHeap == JM_HEAP_EXCP || (dwFlags & HEAP_GENERATE_EXCEPTIONS))
|
||||||
|
RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
|
if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,177 +1,94 @@
|
|||||||
#ifndef MOZ_MEMORY_WINDOWS
|
/* -*- Mode: C; tab-width: 8; c-basic-offset: 8 -*- */
|
||||||
# include <stdbool.h>
|
/* vim:set softtabstop=8 shiftwidth=8: */
|
||||||
#else
|
/*-
|
||||||
# include <windows.h>
|
* Copyright (C) 2006-2008 Jason Evans <jasone@FreeBSD.org>.
|
||||||
# ifndef bool
|
* All rights reserved.
|
||||||
# define bool BOOL
|
*
|
||||||
# endif
|
* Redistribution and use in source and binary forms, with or without
|
||||||
#endif
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
extern const char *_malloc_options;
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice(s), this list of conditions and the following disclaimer as
|
||||||
/*
|
* the first lines of this file unmodified other than the possible
|
||||||
* jemalloc_stats() is not a stable interface. When using jemalloc_stats_t, be
|
* addition of one or more copyright notices.
|
||||||
* sure that the compiled results of jemalloc.c are in sync with this header
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* file.
|
* notice(s), this list of conditions and the following disclaimer in
|
||||||
*/
|
* the documentation and/or other materials provided with the
|
||||||
typedef struct {
|
* distribution.
|
||||||
/*
|
*
|
||||||
* Run-time configuration settings.
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||||
*/
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
bool opt_abort; /* abort(3) on error? */
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
bool opt_junk; /* Fill allocated/free memory with 0xa5/0x5a? */
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
||||||
bool opt_utrace; /* Trace all allocation events? */
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
bool opt_sysv; /* SysV semantics? */
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
bool opt_xmalloc; /* abort(3) on OOM? */
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
bool opt_zero; /* Fill allocated memory with 0x0? */
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
size_t narenas; /* Number of arenas. */
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
size_t balance_threshold; /* Arena contention rebalance threshold. */
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
size_t quantum; /* Allocation quantum. */
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
size_t small_max; /* Max quantum-spaced allocation size. */
|
*/
|
||||||
size_t large_max; /* Max sub-chunksize allocation size. */
|
|
||||||
size_t chunksize; /* Size of each virtual memory mapping. */
|
#ifndef _JEMALLOC_H_
|
||||||
size_t dirty_max; /* Max dirty pages per arena. */
|
#define _JEMALLOC_H_
|
||||||
size_t reserve_min; /* reserve_low callback threshold. */
|
|
||||||
size_t reserve_max; /* Maximum reserve size before unmapping. */
|
#include <stddef.h>
|
||||||
|
|
||||||
/*
|
#ifdef __cplusplus
|
||||||
* Current memory usage statistics.
|
extern "C" {
|
||||||
*/
|
#endif
|
||||||
size_t mapped; /* Bytes mapped (not necessarily committed). */
|
|
||||||
size_t committed; /* Bytes committed (readable/writable). */
|
typedef unsigned char jemalloc_bool;
|
||||||
size_t allocated; /* Bytes allocted (in use by application). */
|
|
||||||
size_t dirty; /* Bytes dirty (committed unused pages). */
|
extern const char *_malloc_options;
|
||||||
size_t reserve_cur; /* Current memory reserve. */
|
|
||||||
} jemalloc_stats_t;
|
/*
|
||||||
|
* jemalloc_stats() is not a stable interface. When using jemalloc_stats_t, be
|
||||||
#ifndef MOZ_MEMORY_DARWIN
|
* sure that the compiled results of jemalloc.c are in sync with this header
|
||||||
void *malloc(size_t size);
|
* file.
|
||||||
void *valloc(size_t size);
|
*/
|
||||||
void *calloc(size_t num, size_t size);
|
typedef struct {
|
||||||
void *realloc(void *ptr, size_t size);
|
/*
|
||||||
void free(void *ptr);
|
* Run-time configuration settings.
|
||||||
#endif
|
*/
|
||||||
|
jemalloc_bool opt_abort; /* abort(3) on error? */
|
||||||
int posix_memalign(void **memptr, size_t alignment, size_t size);
|
jemalloc_bool opt_junk; /* Fill allocated/free memory with 0xa5/0x5a? */
|
||||||
void *memalign(size_t alignment, size_t size);
|
jemalloc_bool opt_utrace; /* Trace all allocation events? */
|
||||||
size_t malloc_usable_size(const void *ptr);
|
jemalloc_bool opt_sysv; /* SysV semantics? */
|
||||||
void jemalloc_stats(jemalloc_stats_t *stats);
|
jemalloc_bool opt_xmalloc; /* abort(3) on OOM? */
|
||||||
|
jemalloc_bool opt_zero; /* Fill allocated memory with 0x0? */
|
||||||
/* The x*() functions never return NULL. */
|
size_t narenas; /* Number of arenas. */
|
||||||
void *xmalloc(size_t size);
|
size_t balance_threshold; /* Arena contention rebalance threshold. */
|
||||||
void *xcalloc(size_t num, size_t size);
|
size_t quantum; /* Allocation quantum. */
|
||||||
void *xrealloc(void *ptr, size_t size);
|
size_t small_max; /* Max quantum-spaced allocation size. */
|
||||||
void *xmemalign(size_t alignment, size_t size);
|
size_t large_max; /* Max sub-chunksize allocation size. */
|
||||||
|
size_t chunksize; /* Size of each virtual memory mapping. */
|
||||||
/*
|
size_t dirty_max; /* Max dirty pages per arena. */
|
||||||
* The allocator maintains a memory reserve that is used to satisfy allocation
|
|
||||||
* requests when no additional memory can be acquired from the operating
|
/*
|
||||||
* system. Under normal operating conditions, the reserve size is at least
|
* Current memory usage statistics.
|
||||||
* reserve_min bytes. If the reserve is depleted or insufficient to satisfy an
|
*/
|
||||||
* allocation request, then condition notifications are sent to one or more of
|
size_t mapped; /* Bytes mapped (not necessarily committed). */
|
||||||
* the registered callback functions:
|
size_t committed; /* Bytes committed (readable/writable). */
|
||||||
*
|
size_t allocated; /* Bytes allocted (in use by application). */
|
||||||
* RESERVE_CND_LOW: The reserve had to be used to satisfy an allocation
|
size_t dirty; /* Bytes dirty (committed unused pages). */
|
||||||
* request, which dropped the reserve size below the
|
} jemalloc_stats_t;
|
||||||
* minimum. The callee should try to free memory in order
|
|
||||||
* to restore the reserve.
|
#ifndef MOZ_MEMORY_DARWIN
|
||||||
*
|
void *malloc(size_t size);
|
||||||
* RESERVE_CND_CRIT: The reserve was not large enough to satisfy a pending
|
void *valloc(size_t size);
|
||||||
* allocation request. Some callee must free adequate
|
void *calloc(size_t num, size_t size);
|
||||||
* memory in order to prevent application failure (unless
|
void *realloc(void *ptr, size_t size);
|
||||||
* the condition spontaneously desists due to concurrent
|
void free(void *ptr);
|
||||||
* deallocation).
|
#endif
|
||||||
*
|
|
||||||
* RESERVE_CND_FAIL: An allocation request could not be satisfied, despite all
|
int posix_memalign(void **memptr, size_t alignment, size_t size);
|
||||||
* attempts. The allocator is about to terminate the
|
void *memalign(size_t alignment, size_t size);
|
||||||
* application.
|
size_t malloc_usable_size(const void *ptr);
|
||||||
*
|
void jemalloc_stats(jemalloc_stats_t *stats);
|
||||||
* The order in which the callback functions are called is only loosely
|
|
||||||
* specified: in the absence of interposing callback
|
#ifdef __cplusplus
|
||||||
* registrations/unregistrations, enabled callbacks will be called in an
|
} /* extern "C" */
|
||||||
* arbitrary round-robin order.
|
#endif
|
||||||
*
|
|
||||||
* Condition notifications are sent to callbacks only while conditions exist.
|
#endif /* _JEMALLOC_H_ */
|
||||||
* For example, just before the allocator sends a RESERVE_CND_LOW condition
|
|
||||||
* notification to a callback, the reserve is in fact depleted. However, due
|
|
||||||
* to allocator concurrency, the reserve may have been restored by the time the
|
|
||||||
* callback function executes. Furthermore, if the reserve is restored at some
|
|
||||||
* point during the delivery of condition notifications to callbacks, no
|
|
||||||
* further deliveries will occur, since the condition no longer exists.
|
|
||||||
*
|
|
||||||
* Callback functions can freely call back into the allocator (i.e. the
|
|
||||||
* allocator releases all internal resources before calling each callback
|
|
||||||
* function), though allocation is discouraged, since recursive callbacks are
|
|
||||||
* likely to result, which places extra burden on the application to avoid
|
|
||||||
* deadlock.
|
|
||||||
*
|
|
||||||
* Callback functions must be thread-safe, since it is possible that multiple
|
|
||||||
* threads will call into the same callback function concurrently.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Memory reserve condition types. */
|
|
||||||
typedef enum {
|
|
||||||
RESERVE_CND_LOW,
|
|
||||||
RESERVE_CND_CRIT,
|
|
||||||
RESERVE_CND_FAIL
|
|
||||||
} reserve_cnd_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reserve condition notification callback function type definition.
|
|
||||||
*
|
|
||||||
* Inputs:
|
|
||||||
* ctx: Opaque application data, as passed to reserve_cb_register().
|
|
||||||
* cnd: Condition type being delivered.
|
|
||||||
* size: Allocation request size for the allocation that caused the condition.
|
|
||||||
*/
|
|
||||||
typedef void reserve_cb_t(void *ctx, reserve_cnd_t cnd, size_t size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register a callback function.
|
|
||||||
*
|
|
||||||
* Inputs:
|
|
||||||
* cb: Callback function pointer.
|
|
||||||
* ctx: Opaque application data, passed to cb().
|
|
||||||
*
|
|
||||||
* Output:
|
|
||||||
* ret: If true, failure due to OOM; success otherwise.
|
|
||||||
*/
|
|
||||||
bool reserve_cb_register(reserve_cb_t *cb, void *ctx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unregister a callback function.
|
|
||||||
*
|
|
||||||
* Inputs:
|
|
||||||
* cb: Callback function pointer.
|
|
||||||
* ctx: Opaque application data, same as that passed to reserve_cb_register().
|
|
||||||
*
|
|
||||||
* Output:
|
|
||||||
* ret: False upon success, true if the {cb,ctx} registration could not be
|
|
||||||
* found.
|
|
||||||
*/
|
|
||||||
bool reserve_cb_unregister(reserve_cb_t *cb, void *ctx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the current reserve size.
|
|
||||||
*
|
|
||||||
* ret: Current reserve size.
|
|
||||||
*/
|
|
||||||
size_t reserve_cur_get(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the minimum acceptable reserve size. If the reserve drops below this
|
|
||||||
* value, the RESERVE_CND_LOW condition notification is sent to the callbacks.
|
|
||||||
*
|
|
||||||
* ret: Minimum acceptable reserve size.
|
|
||||||
*/
|
|
||||||
size_t reserve_min_get(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the minimum acceptable reserve size.
|
|
||||||
*
|
|
||||||
* min: Reserve threshold. This value may be internally rounded up.
|
|
||||||
* ret: False if the reserve was successfully resized; true otherwise. Note
|
|
||||||
* that failure to resize the reserve also results in a RESERVE_CND_LOW
|
|
||||||
* condition.
|
|
||||||
*/
|
|
||||||
bool reserve_min_set(size_t min);
|
|
||||||
|
@ -1,114 +1,114 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 Jason Evans <jasone@canonware.com>.
|
* Copyright (C) 2002 Jason Evans <jasone@canonware.com>.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
* notice(s), this list of conditions and the following disclaimer
|
* notice(s), this list of conditions and the following disclaimer
|
||||||
* unmodified other than the allowable addition of one or more
|
* unmodified other than the allowable addition of one or more
|
||||||
* copyright notices.
|
* copyright notices.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice(s), this list of conditions and the following disclaimer in
|
* notice(s), this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* distribution.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List definitions.
|
* List definitions.
|
||||||
*/
|
*/
|
||||||
#define ql_head(a_type) \
|
#define ql_head(a_type) \
|
||||||
struct { \
|
struct { \
|
||||||
a_type *qlh_first; \
|
a_type *qlh_first; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ql_head_initializer(a_head) {NULL}
|
#define ql_head_initializer(a_head) {NULL}
|
||||||
|
|
||||||
#define ql_elm(a_type) qr(a_type)
|
#define ql_elm(a_type) qr(a_type)
|
||||||
|
|
||||||
/* List functions. */
|
/* List functions. */
|
||||||
#define ql_new(a_head) do { \
|
#define ql_new(a_head) do { \
|
||||||
(a_head)->qlh_first = NULL; \
|
(a_head)->qlh_first = NULL; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field)
|
#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field)
|
||||||
|
|
||||||
#define ql_first(a_head) ((a_head)->qlh_first)
|
#define ql_first(a_head) ((a_head)->qlh_first)
|
||||||
|
|
||||||
#define ql_last(a_head, a_field) \
|
#define ql_last(a_head, a_field) \
|
||||||
((ql_first(a_head) != NULL) \
|
((ql_first(a_head) != NULL) \
|
||||||
? qr_prev(ql_first(a_head), a_field) : NULL)
|
? qr_prev(ql_first(a_head), a_field) : NULL)
|
||||||
|
|
||||||
#define ql_next(a_head, a_elm, a_field) \
|
#define ql_next(a_head, a_elm, a_field) \
|
||||||
((ql_last(a_head, a_field) != (a_elm)) \
|
((ql_last(a_head, a_field) != (a_elm)) \
|
||||||
? qr_next((a_elm), a_field) : NULL)
|
? qr_next((a_elm), a_field) : NULL)
|
||||||
|
|
||||||
#define ql_prev(a_head, a_elm, a_field) \
|
#define ql_prev(a_head, a_elm, a_field) \
|
||||||
((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \
|
((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \
|
||||||
: NULL)
|
: NULL)
|
||||||
|
|
||||||
#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \
|
#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \
|
||||||
qr_before_insert((a_qlelm), (a_elm), a_field); \
|
qr_before_insert((a_qlelm), (a_elm), a_field); \
|
||||||
if (ql_first(a_head) == (a_qlelm)) { \
|
if (ql_first(a_head) == (a_qlelm)) { \
|
||||||
ql_first(a_head) = (a_elm); \
|
ql_first(a_head) = (a_elm); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_after_insert(a_qlelm, a_elm, a_field) \
|
#define ql_after_insert(a_qlelm, a_elm, a_field) \
|
||||||
qr_after_insert((a_qlelm), (a_elm), a_field)
|
qr_after_insert((a_qlelm), (a_elm), a_field)
|
||||||
|
|
||||||
#define ql_head_insert(a_head, a_elm, a_field) do { \
|
#define ql_head_insert(a_head, a_elm, a_field) do { \
|
||||||
if (ql_first(a_head) != NULL) { \
|
if (ql_first(a_head) != NULL) { \
|
||||||
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
||||||
} \
|
} \
|
||||||
ql_first(a_head) = (a_elm); \
|
ql_first(a_head) = (a_elm); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_tail_insert(a_head, a_elm, a_field) do { \
|
#define ql_tail_insert(a_head, a_elm, a_field) do { \
|
||||||
if (ql_first(a_head) != NULL) { \
|
if (ql_first(a_head) != NULL) { \
|
||||||
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
||||||
} \
|
} \
|
||||||
ql_first(a_head) = qr_next((a_elm), a_field); \
|
ql_first(a_head) = qr_next((a_elm), a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_remove(a_head, a_elm, a_field) do { \
|
#define ql_remove(a_head, a_elm, a_field) do { \
|
||||||
if (ql_first(a_head) == (a_elm)) { \
|
if (ql_first(a_head) == (a_elm)) { \
|
||||||
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
||||||
} \
|
} \
|
||||||
if (ql_first(a_head) != (a_elm)) { \
|
if (ql_first(a_head) != (a_elm)) { \
|
||||||
qr_remove((a_elm), a_field); \
|
qr_remove((a_elm), a_field); \
|
||||||
} else { \
|
} else { \
|
||||||
ql_first(a_head) = NULL; \
|
ql_first(a_head) = NULL; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_head_remove(a_head, a_type, a_field) do { \
|
#define ql_head_remove(a_head, a_type, a_field) do { \
|
||||||
a_type *t = ql_first(a_head); \
|
a_type *t = ql_first(a_head); \
|
||||||
ql_remove((a_head), t, a_field); \
|
ql_remove((a_head), t, a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_tail_remove(a_head, a_type, a_field) do { \
|
#define ql_tail_remove(a_head, a_type, a_field) do { \
|
||||||
a_type *t = ql_last(a_head, a_field); \
|
a_type *t = ql_last(a_head, a_field); \
|
||||||
ql_remove((a_head), t, a_field); \
|
ql_remove((a_head), t, a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ql_foreach(a_var, a_head, a_field) \
|
#define ql_foreach(a_var, a_head, a_field) \
|
||||||
qr_foreach((a_var), ql_first(a_head), a_field)
|
qr_foreach((a_var), ql_first(a_head), a_field)
|
||||||
|
|
||||||
#define ql_reverse_foreach(a_var, a_head, a_field) \
|
#define ql_reverse_foreach(a_var, a_head, a_field) \
|
||||||
qr_reverse_foreach((a_var), ql_first(a_head), a_field)
|
qr_reverse_foreach((a_var), ql_first(a_head), a_field)
|
||||||
|
@ -1,98 +1,98 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 Jason Evans <jasone@canonware.com>.
|
* Copyright (C) 2002 Jason Evans <jasone@canonware.com>.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
* notice(s), this list of conditions and the following disclaimer
|
* notice(s), this list of conditions and the following disclaimer
|
||||||
* unmodified other than the allowable addition of one or more
|
* unmodified other than the allowable addition of one or more
|
||||||
* copyright notices.
|
* copyright notices.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice(s), this list of conditions and the following disclaimer in
|
* notice(s), this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* distribution.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/* Ring definitions. */
|
/* Ring definitions. */
|
||||||
#define qr(a_type) \
|
#define qr(a_type) \
|
||||||
struct { \
|
struct { \
|
||||||
a_type *qre_next; \
|
a_type *qre_next; \
|
||||||
a_type *qre_prev; \
|
a_type *qre_prev; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ring functions. */
|
/* Ring functions. */
|
||||||
#define qr_new(a_qr, a_field) do { \
|
#define qr_new(a_qr, a_field) do { \
|
||||||
(a_qr)->a_field.qre_next = (a_qr); \
|
(a_qr)->a_field.qre_next = (a_qr); \
|
||||||
(a_qr)->a_field.qre_prev = (a_qr); \
|
(a_qr)->a_field.qre_prev = (a_qr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next)
|
#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next)
|
||||||
|
|
||||||
#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev)
|
#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev)
|
||||||
|
|
||||||
#define qr_before_insert(a_qrelm, a_qr, a_field) do { \
|
#define qr_before_insert(a_qrelm, a_qr, a_field) do { \
|
||||||
(a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \
|
(a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \
|
||||||
(a_qr)->a_field.qre_next = (a_qrelm); \
|
(a_qr)->a_field.qre_next = (a_qrelm); \
|
||||||
(a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \
|
(a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \
|
||||||
(a_qrelm)->a_field.qre_prev = (a_qr); \
|
(a_qrelm)->a_field.qre_prev = (a_qr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define qr_after_insert(a_qrelm, a_qr, a_field) \
|
#define qr_after_insert(a_qrelm, a_qr, a_field) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
(a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \
|
(a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \
|
||||||
(a_qr)->a_field.qre_prev = (a_qrelm); \
|
(a_qr)->a_field.qre_prev = (a_qrelm); \
|
||||||
(a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \
|
(a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \
|
||||||
(a_qrelm)->a_field.qre_next = (a_qr); \
|
(a_qrelm)->a_field.qre_next = (a_qr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define qr_meld(a_qr_a, a_qr_b, a_field) do { \
|
#define qr_meld(a_qr_a, a_qr_b, a_field) do { \
|
||||||
void *t; \
|
void *t; \
|
||||||
(a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \
|
(a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \
|
||||||
(a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \
|
(a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \
|
||||||
t = (a_qr_a)->a_field.qre_prev; \
|
t = (a_qr_a)->a_field.qre_prev; \
|
||||||
(a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
|
(a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
|
||||||
(a_qr_b)->a_field.qre_prev = t; \
|
(a_qr_b)->a_field.qre_prev = t; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* qr_meld() and qr_split() are functionally equivalent, so there's no need to
|
/* qr_meld() and qr_split() are functionally equivalent, so there's no need to
|
||||||
* have two copies of the code. */
|
* have two copies of the code. */
|
||||||
#define qr_split(a_qr_a, a_qr_b, a_field) \
|
#define qr_split(a_qr_a, a_qr_b, a_field) \
|
||||||
qr_meld((a_qr_a), (a_qr_b), a_field)
|
qr_meld((a_qr_a), (a_qr_b), a_field)
|
||||||
|
|
||||||
#define qr_remove(a_qr, a_field) do { \
|
#define qr_remove(a_qr, a_field) do { \
|
||||||
(a_qr)->a_field.qre_prev->a_field.qre_next \
|
(a_qr)->a_field.qre_prev->a_field.qre_next \
|
||||||
= (a_qr)->a_field.qre_next; \
|
= (a_qr)->a_field.qre_next; \
|
||||||
(a_qr)->a_field.qre_next->a_field.qre_prev \
|
(a_qr)->a_field.qre_next->a_field.qre_prev \
|
||||||
= (a_qr)->a_field.qre_prev; \
|
= (a_qr)->a_field.qre_prev; \
|
||||||
(a_qr)->a_field.qre_next = (a_qr); \
|
(a_qr)->a_field.qre_next = (a_qr); \
|
||||||
(a_qr)->a_field.qre_prev = (a_qr); \
|
(a_qr)->a_field.qre_prev = (a_qr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define qr_foreach(var, a_qr, a_field) \
|
#define qr_foreach(var, a_qr, a_field) \
|
||||||
for ((var) = (a_qr); \
|
for ((var) = (a_qr); \
|
||||||
(var) != NULL; \
|
(var) != NULL; \
|
||||||
(var) = (((var)->a_field.qre_next != (a_qr)) \
|
(var) = (((var)->a_field.qre_next != (a_qr)) \
|
||||||
? (var)->a_field.qre_next : NULL))
|
? (var)->a_field.qre_next : NULL))
|
||||||
|
|
||||||
#define qr_reverse_foreach(var, a_qr, a_field) \
|
#define qr_reverse_foreach(var, a_qr, a_field) \
|
||||||
for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \
|
for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \
|
||||||
(var) != NULL; \
|
(var) != NULL; \
|
||||||
(var) = (((var) != (a_qr)) \
|
(var) = (((var) != (a_qr)) \
|
||||||
? (var)->a_field.qre_prev : NULL))
|
? (var)->a_field.qre_prev : NULL))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -53,7 +53,7 @@ BSC32=bscmake.exe
|
|||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv /DELAYLOAD:shlwapi.dll
|
||||||
# SUBTRACT LINK32 /pdb:none
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "KernelEx Base NonShared - Win32 Debug"
|
!ELSEIF "$(CFG)" == "KernelEx Base NonShared - Win32 Debug"
|
||||||
@ -80,7 +80,7 @@ BSC32=bscmake.exe
|
|||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shlwapi.lib shell32.lib rpcrt4.lib usp10.lib ../../common/KernelEx.lib ../../kexcrt/kexcrt.lib libc.lib delayimp.lib /nologo /dll /map /debug /machine:I386 /nodefaultlib /OPT:NOWIN98 /DELAYLOAD:shell32.dll /DELAYLOAD:rpcrt4.dll /DELAYLOAD:usp10.dll /DELAYLOAD:comdlg32.dll /DELAYLOAD:winspool.drv /DELAYLOAD:shlwapi.dll
|
||||||
# SUBTRACT LINK32 /pdb:none
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
!ENDIF
|
!ENDIF
|
||||||
@ -153,6 +153,14 @@ SOURCE=.\gdi32\_gdi32_apilist.h
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\gdi32\ScriptCache.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\gdi32\ScriptCache.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\gdi32\UberGDI.c
|
SOURCE=.\gdi32\UberGDI.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
@ -225,6 +233,10 @@ SOURCE=.\shell32\SHGetSpecialFolder_fix.c
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\shell32\SHParseDisplayName.c
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\shell32\unishell32.c
|
SOURCE=.\shell32\unishell32.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
|
40
apilibs/kexbasen/shell32/SHParseDisplayName.c
Executable file
40
apilibs/kexbasen/shell32/SHParseDisplayName.c
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* KernelEx
|
||||||
|
* Copyright (C) 2010, Tihiy
|
||||||
|
*
|
||||||
|
* This file is part of KernelEx source code.
|
||||||
|
*
|
||||||
|
* KernelEx is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* KernelEx is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with GNU Make; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
|
||||||
|
/* MAKE_EXPORT SHParseDisplayName_new=SHParseDisplayName */
|
||||||
|
HRESULT WINAPI SHParseDisplayName_new(PCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut)
|
||||||
|
{
|
||||||
|
IShellFolder *psf;
|
||||||
|
HRESULT ret = SHGetDesktopFolder(&psf);
|
||||||
|
if (SUCCEEDED(ret))
|
||||||
|
{
|
||||||
|
ULONG attrs = sfgaoIn;
|
||||||
|
LPOLESTR pszNameCopyW = StrDupW(pszName);
|
||||||
|
ret = psf->ParseDisplayName(NULL,pbc,pszNameCopyW,NULL,ppidl,&attrs);
|
||||||
|
if (psfgaoOut) *psfgaoOut = attrs;
|
||||||
|
psf->Release();
|
||||||
|
LocalFree(pszNameCopyW);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
@ -45,6 +45,7 @@ static const apilib_named_api shell32_named_apis[] =
|
|||||||
DECL_API("SHGetSpecialFolderLocation", SHGetSpecialFolderLocation_fix),
|
DECL_API("SHGetSpecialFolderLocation", SHGetSpecialFolderLocation_fix),
|
||||||
DECL_API("SHGetSpecialFolderPathA", SHGetSpecialFolderPathA_fix),
|
DECL_API("SHGetSpecialFolderPathA", SHGetSpecialFolderPathA_fix),
|
||||||
DECL_API("SHGetSpecialFolderPathW", SHGetSpecialFolderPathW_fix),
|
DECL_API("SHGetSpecialFolderPathW", SHGetSpecialFolderPathW_fix),
|
||||||
|
DECL_API("SHParseDisplayName", SHParseDisplayName_new),
|
||||||
DECL_API("ShellAboutW", ShellAboutW_fwd),
|
DECL_API("ShellAboutW", ShellAboutW_fwd),
|
||||||
DECL_API("ShellExecuteExW", ShellExecuteExW_fwd),
|
DECL_API("ShellExecuteExW", ShellExecuteExW_fwd),
|
||||||
DECL_API("ShellExecuteW", ShellExecuteW_fwd),
|
DECL_API("ShellExecuteW", ShellExecuteW_fwd),
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#ifndef _SHELL32_APILIST_H
|
#ifndef _SHELL32_APILIST_H
|
||||||
#define _SHELL32_APILIST_H
|
#define _SHELL32_APILIST_H
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
#include "kexcoresdk.h"
|
#include "kexcoresdk.h"
|
||||||
|
|
||||||
BOOL init_shell32();
|
BOOL init_shell32();
|
||||||
@ -34,6 +35,7 @@ HRESULT WINAPI SHGetFolderPathW_new(HWND hwndOwner, int nFolder, HANDLE hToken,
|
|||||||
HRESULT WINAPI SHGetSpecialFolderLocation_fix(HWND hwndOwner, int nFolder, LPVOID *_ppidl);
|
HRESULT WINAPI SHGetSpecialFolderLocation_fix(HWND hwndOwner, int nFolder, LPVOID *_ppidl);
|
||||||
BOOL WINAPI SHGetSpecialFolderPathA_fix(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
|
BOOL WINAPI SHGetSpecialFolderPathA_fix(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
|
||||||
BOOL WINAPI SHGetSpecialFolderPathW_fix(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
|
BOOL WINAPI SHGetSpecialFolderPathW_fix(HWND hwndOwner, LPWSTR lpszPath, int nFolder, BOOL fCreate);
|
||||||
|
HRESULT WINAPI SHParseDisplayName_new(PCWSTR pszName, IBindCtx *pbc, LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut);
|
||||||
FWDPROC DragQueryFileW_fwd;
|
FWDPROC DragQueryFileW_fwd;
|
||||||
FWDPROC ExtractIconExW_fwd;
|
FWDPROC ExtractIconExW_fwd;
|
||||||
FWDPROC ExtractIconW_fwd;
|
FWDPROC ExtractIconW_fwd;
|
||||||
|
@ -47,6 +47,7 @@ static const apilib_named_api winspool_named_apis[] =
|
|||||||
DECL_API("DeletePrinterDriverW", DeletePrinterDriverW_fwd),
|
DECL_API("DeletePrinterDriverW", DeletePrinterDriverW_fwd),
|
||||||
DECL_API("DeviceCapabilitiesW", DeviceCapabilitiesW_fwd),
|
DECL_API("DeviceCapabilitiesW", DeviceCapabilitiesW_fwd),
|
||||||
DECL_API("DocumentPropertiesW", DocumentPropertiesW_fwd),
|
DECL_API("DocumentPropertiesW", DocumentPropertiesW_fwd),
|
||||||
|
DECL_API("EnumPrintersW", EnumPrintersW_new),
|
||||||
DECL_API("GetDefaultPrinterA", GetDefaultPrinterA),
|
DECL_API("GetDefaultPrinterA", GetDefaultPrinterA),
|
||||||
DECL_API("GetDefaultPrinterW", GetDefaultPrinterW),
|
DECL_API("GetDefaultPrinterW", GetDefaultPrinterW),
|
||||||
DECL_API("GetPrintProcessorDirectoryW", GetPrintProcessorDirectoryW_fwd),
|
DECL_API("GetPrintProcessorDirectoryW", GetPrintProcessorDirectoryW_fwd),
|
||||||
|
@ -58,6 +58,7 @@ FWDPROC SetJobW_fwd;
|
|||||||
FWDPROC SetPrinterDataW_fwd;
|
FWDPROC SetPrinterDataW_fwd;
|
||||||
FWDPROC SetPrinterW_fwd;
|
FWDPROC SetPrinterW_fwd;
|
||||||
FWDPROC StartDocPrinterW_fwd;
|
FWDPROC StartDocPrinterW_fwd;
|
||||||
|
BOOL WINAPI EnumPrintersW_new(DWORD Flags, LPWSTR NameW, DWORD Level, LPBYTE pPrinterEnumW, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned);
|
||||||
/*** AUTOGENERATED APILIST DECLARATIONS END ***/
|
/*** AUTOGENERATED APILIST DECLARATIONS END ***/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* KernelEx
|
* KernelEx
|
||||||
* Copyright (C) 2010, Tihiy
|
* Copyright (C) 2010, Tihiy
|
||||||
|
* Copyright (C) 2010, Xeno86
|
||||||
|
*
|
||||||
|
* Parts adapted from WINE Project.
|
||||||
|
* Copyright 1996 John Harvey
|
||||||
|
* Copyright 1998 Andreas Mohr
|
||||||
|
* Copyright 1999 Klaas van Gend
|
||||||
|
* Copyright 1999, 2000 Huw D M Davies
|
||||||
|
* Copyright 2001 Marcus Meissner
|
||||||
|
* Copyright 2005-2009 Detlef Riekenberg
|
||||||
*
|
*
|
||||||
* This file is part of KernelEx source code.
|
* This file is part of KernelEx source code.
|
||||||
*
|
*
|
||||||
@ -19,9 +28,255 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include "common.h"
|
||||||
#include "unifwd.h"
|
#include "unifwd.h"
|
||||||
|
|
||||||
|
static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1), sizeof(PRINTER_INFO_2),
|
||||||
|
sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4),
|
||||||
|
sizeof(PRINTER_INFO_5)};
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* DEVMODEdupWtoA
|
||||||
|
* Creates an ansi copy of supplied devmode
|
||||||
|
*/
|
||||||
|
static LPDEVMODEW DEVMODEdupAtoW(const DEVMODEA *dmA)
|
||||||
|
{
|
||||||
|
LPDEVMODEW dmW;
|
||||||
|
WORD size;
|
||||||
|
|
||||||
|
if (!dmA) return NULL;
|
||||||
|
size = dmA->dmSize + CCHDEVICENAME +
|
||||||
|
((dmA->dmSize > FIELD_OFFSET(DEVMODEA, dmFormName)) ? CCHFORMNAME : 0);
|
||||||
|
|
||||||
|
dmW = (LPDEVMODEW) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
|
||||||
|
if (!dmW) return NULL;
|
||||||
|
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, (LPSTR)dmA->dmDeviceName, -1,
|
||||||
|
dmW->dmDeviceName, CCHDEVICENAME);
|
||||||
|
|
||||||
|
if (FIELD_OFFSET(DEVMODEA, dmFormName) >= dmA->dmSize) {
|
||||||
|
memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
|
||||||
|
dmA->dmSize - FIELD_OFFSET(DEVMODEA, dmSpecVersion));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
|
||||||
|
FIELD_OFFSET(DEVMODEA, dmFormName) - FIELD_OFFSET(DEVMODEA, dmSpecVersion));
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, (LPSTR)dmA->dmFormName, -1,
|
||||||
|
dmW->dmFormName, CCHFORMNAME);
|
||||||
|
|
||||||
|
memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize - FIELD_OFFSET(DEVMODEA, dmLogPixels));
|
||||||
|
}
|
||||||
|
|
||||||
|
dmW->dmSize = size;
|
||||||
|
memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize, dmA->dmDriverExtra);
|
||||||
|
return dmW;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_printerinfo_WtoA(LPBYTE outW, LPBYTE pPrintersA,
|
||||||
|
DWORD level, DWORD outlen, DWORD numentries)
|
||||||
|
{
|
||||||
|
DWORD id = 0;
|
||||||
|
LPWSTR ptr;
|
||||||
|
INT len;
|
||||||
|
|
||||||
|
len = pi_sizeof[level] * numentries;
|
||||||
|
ptr = (LPWSTR) (outW + len);
|
||||||
|
/* first structures */
|
||||||
|
outlen -= len;
|
||||||
|
/* then text in unicode (we count in wchars from now on) */
|
||||||
|
outlen /= 2;
|
||||||
|
|
||||||
|
/* copy the numbers of all PRINTER_INFO_* first */
|
||||||
|
memcpy(outW, pPrintersA, len);
|
||||||
|
|
||||||
|
while (id < numentries) {
|
||||||
|
switch (level) {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) outW;
|
||||||
|
PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) pPrintersA;
|
||||||
|
|
||||||
|
if (piA->pDescription) {
|
||||||
|
piW->pDescription = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pDescription, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pName) {
|
||||||
|
piW->pName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pComment) {
|
||||||
|
piW->pComment = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pComment, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) outW;
|
||||||
|
PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) pPrintersA;
|
||||||
|
LPDEVMODEW dmW;
|
||||||
|
|
||||||
|
if (piA->pServerName) {
|
||||||
|
piW->pServerName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pServerName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pPrinterName) {
|
||||||
|
piW->pPrinterName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPrinterName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pShareName) {
|
||||||
|
piW->pShareName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pShareName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pPortName) {
|
||||||
|
piW->pPortName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPortName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pDriverName) {
|
||||||
|
piW->pDriverName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pDriverName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pComment) {
|
||||||
|
piW->pComment = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pComment, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pLocation) {
|
||||||
|
piW->pLocation = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pLocation, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmW = DEVMODEdupAtoW(piA->pDevMode);
|
||||||
|
if (dmW) {
|
||||||
|
/* align DEVMODEA to a DWORD boundary */
|
||||||
|
len = (2 - ( (DWORD_PTR) ptr & 1)) & 1;
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
|
||||||
|
piW->pDevMode = (LPDEVMODEW) ptr;
|
||||||
|
len = dmW->dmSize + dmW->dmDriverExtra;
|
||||||
|
memcpy(ptr, dmW, len);
|
||||||
|
HeapFree(GetProcessHeap(), 0, dmW);
|
||||||
|
|
||||||
|
ptr += len/2+1;
|
||||||
|
outlen -= len/2+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (piA->pSepFile) {
|
||||||
|
piW->pSepFile = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pSepFile, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pPrintProcessor) {
|
||||||
|
piW->pPrintProcessor = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPrintProcessor, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pDatatype) {
|
||||||
|
piW->pDatatype = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pDatatype, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pParameters) {
|
||||||
|
piW->pParameters = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pParameters, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pSecurityDescriptor) {
|
||||||
|
piW->pSecurityDescriptor = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) outW;
|
||||||
|
PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) pPrintersA;
|
||||||
|
|
||||||
|
if (piA->pPrinterName) {
|
||||||
|
piW->pPrinterName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPrinterName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pServerName) {
|
||||||
|
piW->pServerName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pServerName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
{
|
||||||
|
PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) outW;
|
||||||
|
PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) pPrintersA;
|
||||||
|
|
||||||
|
if (piA->pPrinterName) {
|
||||||
|
piW->pPrinterName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPrinterName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
if (piA->pPortName) {
|
||||||
|
piW->pPortName = ptr;
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, piA->pPortName, -1,
|
||||||
|
ptr, outlen);
|
||||||
|
ptr += len;
|
||||||
|
outlen -= len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pPrintersA += pi_sizeof[level];
|
||||||
|
outW += pi_sizeof[level];
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//AddForm - not supported
|
//AddForm - not supported
|
||||||
FORWARD_TO_UNICOWS(AddJobW);
|
FORWARD_TO_UNICOWS(AddJobW);
|
||||||
FORWARD_TO_UNICOWS(AddMonitorW);
|
FORWARD_TO_UNICOWS(AddMonitorW);
|
||||||
@ -47,7 +302,51 @@ FORWARD_TO_UNICOWS(DocumentPropertiesW);
|
|||||||
//EnumMonitorsW - not implemented
|
//EnumMonitorsW - not implemented
|
||||||
//EnumPortsW - not implemented
|
//EnumPortsW - not implemented
|
||||||
//EnumPrinterDriversW - not implemented
|
//EnumPrinterDriversW - not implemented
|
||||||
//EnumPrintersW - not implemented
|
|
||||||
|
/* MAKE_EXPORT EnumPrintersW_new=EnumPrintersW */
|
||||||
|
BOOL WINAPI EnumPrintersW_new(
|
||||||
|
DWORD Flags,
|
||||||
|
LPWSTR NameW,
|
||||||
|
DWORD Level,
|
||||||
|
LPBYTE pPrinterEnumW,
|
||||||
|
DWORD cbBuf,
|
||||||
|
LPDWORD pcbNeeded,
|
||||||
|
LPDWORD pcReturned
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
DWORD needed;
|
||||||
|
DWORD returned;
|
||||||
|
LPBYTE pPrinterEnumA;
|
||||||
|
|
||||||
|
ALLOC_WtoA(Name);
|
||||||
|
pPrinterEnumA = (pPrinterEnumW && cbBuf) ? (LPBYTE) HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
|
||||||
|
ret = EnumPrintersA(Flags, NameA, Level, pPrinterEnumA, cbBuf, &needed, &returned);
|
||||||
|
if (Level <= 5)
|
||||||
|
needed = (needed - pi_sizeof[Level]) * 2 + pi_sizeof[Level];
|
||||||
|
if (pcbNeeded)
|
||||||
|
*pcbNeeded = needed;
|
||||||
|
if (pcReturned)
|
||||||
|
*pcReturned = returned;
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
if (cbBuf >= needed)
|
||||||
|
{
|
||||||
|
convert_printerinfo_WtoA(pPrinterEnumW, pPrinterEnumA, Level, needed, returned);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
if (pcReturned)
|
||||||
|
*pcReturned = 0;
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, pPrinterEnumA);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
//EnumPrintProcessorDatatypesW - not implemented
|
//EnumPrintProcessorDatatypesW - not implemented
|
||||||
//EnumPrintProcessorsW - not implemented
|
//EnumPrintProcessorsW - not implemented
|
||||||
//GetForm - not supported
|
//GetForm - not supported
|
||||||
|
@ -45,6 +45,7 @@ static const apilib_named_api advapi32_named_apis[] =
|
|||||||
DECL_API("ConvertStringSidToSidA", ConvertStringSidToSidA_stub),
|
DECL_API("ConvertStringSidToSidA", ConvertStringSidToSidA_stub),
|
||||||
DECL_API("ConvertStringSidToSidW", ConvertStringSidToSidW_stub),
|
DECL_API("ConvertStringSidToSidW", ConvertStringSidToSidW_stub),
|
||||||
DECL_API("CopySid", CopySid_new),
|
DECL_API("CopySid", CopySid_new),
|
||||||
|
DECL_API("CreateProcessWithLogonW", CreateProcessWithLogonW_stub),
|
||||||
DECL_API("CreateRestrictedToken", CreateRestrictedToken_new),
|
DECL_API("CreateRestrictedToken", CreateRestrictedToken_new),
|
||||||
DECL_API("CreateWellKnownSid", CreateWellKnownSid_new),
|
DECL_API("CreateWellKnownSid", CreateWellKnownSid_new),
|
||||||
DECL_API("CryptAcquireContextW", CryptAcquireContextW_stub),
|
DECL_API("CryptAcquireContextW", CryptAcquireContextW_stub),
|
||||||
@ -82,6 +83,8 @@ static const apilib_named_api advapi32_named_apis[] =
|
|||||||
DECL_API("InitializeAcl", InitializeAcl_new),
|
DECL_API("InitializeAcl", InitializeAcl_new),
|
||||||
DECL_API("InitializeSecurityDescriptor", InitializeSecurityDescriptor_new),
|
DECL_API("InitializeSecurityDescriptor", InitializeSecurityDescriptor_new),
|
||||||
DECL_API("InitializeSid", InitializeSid_new),
|
DECL_API("InitializeSid", InitializeSid_new),
|
||||||
|
DECL_API("InitiateSystemShutdownExA", InitiateSystemShutdownExA_stub),
|
||||||
|
DECL_API("InitiateSystemShutdownExW", InitiateSystemShutdownExW_stub),
|
||||||
DECL_API("IsValidSecurityDescriptor", IsValidSecurityDescriptor_new),
|
DECL_API("IsValidSecurityDescriptor", IsValidSecurityDescriptor_new),
|
||||||
DECL_API("IsValidSid", IsValidSid_new),
|
DECL_API("IsValidSid", IsValidSid_new),
|
||||||
DECL_API("IsWellKnownSid", IsWellKnownSid_stub),
|
DECL_API("IsWellKnownSid", IsWellKnownSid_stub),
|
||||||
|
@ -58,6 +58,9 @@ STUB QueryWindows31FilesMigration_stub;
|
|||||||
STUB SynchronizeWindows31FilesAndWindowsNTRegistry_stub;
|
STUB SynchronizeWindows31FilesAndWindowsNTRegistry_stub;
|
||||||
STUB EnumServicesStatusExA_stub;
|
STUB EnumServicesStatusExA_stub;
|
||||||
STUB EnumServicesStatusExW_stub;
|
STUB EnumServicesStatusExW_stub;
|
||||||
|
STUB CreateProcessWithLogonW_stub;
|
||||||
|
STUB InitiateSystemShutdownExA_stub;
|
||||||
|
STUB InitiateSystemShutdownExW_stub;
|
||||||
BOOL WINAPI OpenProcessToken_new(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle);
|
BOOL WINAPI OpenProcessToken_new(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle);
|
||||||
BOOL WINAPI OpenThreadToken_new(HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, HANDLE *TokenHandle);
|
BOOL WINAPI OpenThreadToken_new(HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, HANDLE *TokenHandle);
|
||||||
BOOL WINAPI DuplicateTokenEx_new(HANDLE ExistingTokenHandle, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE DuplicateTokenHandle);
|
BOOL WINAPI DuplicateTokenEx_new(HANDLE ExistingTokenHandle, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, PHANDLE DuplicateTokenHandle);
|
||||||
|
@ -51,3 +51,7 @@ UNIMPL_FUNC(SynchronizeWindows31FilesAndWindowsNTRegistry,4);
|
|||||||
|
|
||||||
UNIMPL_FUNC(EnumServicesStatusExA, 10);
|
UNIMPL_FUNC(EnumServicesStatusExA, 10);
|
||||||
UNIMPL_FUNC(EnumServicesStatusExW, 10);
|
UNIMPL_FUNC(EnumServicesStatusExW, 10);
|
||||||
|
|
||||||
|
UNIMPL_FUNC(CreateProcessWithLogonW, 11);
|
||||||
|
UNIMPL_FUNC(InitiateSystemShutdownExA, 6);
|
||||||
|
UNIMPL_FUNC(InitiateSystemShutdownExW, 6);
|
||||||
|
@ -32,3 +32,18 @@ BOOL WINAPI RemoveFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv)
|
|||||||
{
|
{
|
||||||
return RemoveFontResourceA(str);
|
return RemoveFontResourceA(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT AddFontMemResourceEx_stub=AddFontMemResourceEx */
|
||||||
|
HANDLE WINAPI AddFontMemResourceEx_stub(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts)
|
||||||
|
{
|
||||||
|
if (!pbFont || !cbFont || !pcFonts)
|
||||||
|
return NULL;
|
||||||
|
*pcFonts = 1;
|
||||||
|
return (HANDLE) 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKE_EXPORT RemoveFontMemResourceEx_stub=RemoveFontMemResourceEx */
|
||||||
|
BOOL WINAPI RemoveFontMemResourceEx_stub(HANDLE fh)
|
||||||
|
{
|
||||||
|
return (fh == (HANDLE) 0x10000) ? TRUE : FALSE;
|
||||||
|
}
|
@ -28,6 +28,7 @@
|
|||||||
static BOOL blockkexgdiobj;
|
static BOOL blockkexgdiobj;
|
||||||
static WORD g_GDILH_addr;
|
static WORD g_GDILH_addr;
|
||||||
static DWORD g_GdiBase;
|
static DWORD g_GdiBase;
|
||||||
|
static int script_cache_psidx;
|
||||||
|
|
||||||
#define REBASEGDI(x) ((PVOID)( g_GdiBase + LOWORD((DWORD)(x)) ))
|
#define REBASEGDI(x) ((PVOID)( g_GdiBase + LOWORD((DWORD)(x)) ))
|
||||||
#define REBASEGDIHIGH(x) ( g_GdiBase + (DWORD)(x) )
|
#define REBASEGDIHIGH(x) ( g_GdiBase + (DWORD)(x) )
|
||||||
@ -40,6 +41,7 @@ BOOL InitGDIObjects(void)
|
|||||||
g_GdiBase = MapSL( LoadLibrary16("gdi") << 16 );
|
g_GdiBase = MapSL( LoadLibrary16("gdi") << 16 );
|
||||||
g_GDILH_addr = ((PINSTANCE16)g_GdiBase)->pLocalHeap;
|
g_GDILH_addr = ((PINSTANCE16)g_GdiBase)->pLocalHeap;
|
||||||
blockkexgdiobj = (BOOL)GetProcAddress(GetModuleHandle("rp10.dll"),"blockkexgdiobj");
|
blockkexgdiobj = (BOOL)GetProcAddress(GetModuleHandle("rp10.dll"),"blockkexgdiobj");
|
||||||
|
script_cache_psidx = kexPsAllocIndex();
|
||||||
return (BOOL)g_GdiBase;
|
return (BOOL)g_GdiBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +161,18 @@ BOOL WINAPI DeleteObject_fix( HGDIOBJ hObject )
|
|||||||
DWORD violated = 0;
|
DWORD violated = 0;
|
||||||
if ( obj->wOwner ) //not system objects
|
if ( obj->wOwner ) //not system objects
|
||||||
{
|
{
|
||||||
|
if (obj->wType == GDI_TYPE_FONT)
|
||||||
|
{
|
||||||
|
typedef void (*DeleteUSPFontCache_fn)(HFONT hFont);
|
||||||
|
DeleteUSPFontCache_fn DeleteUSPFontCache = (DeleteUSPFontCache_fn) kexPsGetValue(script_cache_psidx);
|
||||||
|
if (!DeleteUSPFontCache)
|
||||||
|
{
|
||||||
|
DeleteUSPFontCache = (DeleteUSPFontCache_fn)GetProcAddress(LoadLibrary("KEXBASEN.DLL"), "DeleteUSPFontCache");
|
||||||
|
kexPsSetValue(script_cache_psidx, DeleteUSPFontCache);
|
||||||
|
}
|
||||||
|
if (DeleteUSPFontCache)
|
||||||
|
DeleteUSPFontCache((HFONT)hObject);
|
||||||
|
}
|
||||||
if (obj->wType == GDI_TYPE_FONT && ((PFONTOBJ16)obj)->wSelCount >= SEL_FONT_ONCE )
|
if (obj->wType == GDI_TYPE_FONT && ((PFONTOBJ16)obj)->wSelCount >= SEL_FONT_ONCE )
|
||||||
{
|
{
|
||||||
DBGPRINTF(("somebody is trying to delete selected font %p\n",hObject));
|
DBGPRINTF(("somebody is trying to delete selected font %p\n",hObject));
|
||||||
|
@ -30,6 +30,8 @@ extern const apilib_api_table apitable_gdi32;
|
|||||||
/*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/
|
/*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/
|
||||||
INT WINAPI AddFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv);
|
INT WINAPI AddFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv);
|
||||||
BOOL WINAPI RemoveFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv);
|
BOOL WINAPI RemoveFontResourceExA_new(LPCSTR str, DWORD fl, PVOID pdv);
|
||||||
|
HANDLE WINAPI AddFontMemResourceEx_stub(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts);
|
||||||
|
BOOL WINAPI RemoveFontMemResourceEx_stub(HANDLE fh);
|
||||||
DWORD WINAPI GetObjectType_fix(HGDIOBJ hgdiobj);
|
DWORD WINAPI GetObjectType_fix(HGDIOBJ hgdiobj);
|
||||||
BOOL WINAPI DeleteObject_fix(HGDIOBJ hObject);
|
BOOL WINAPI DeleteObject_fix(HGDIOBJ hObject);
|
||||||
HGDIOBJ WINAPI SelectObject_fix(HDC hdc, HGDIOBJ hgdiobj);
|
HGDIOBJ WINAPI SelectObject_fix(HDC hdc, HGDIOBJ hgdiobj);
|
||||||
@ -53,8 +55,6 @@ STUB SetDCBrushColor_stub;
|
|||||||
STUB SetDCPenColor_stub;
|
STUB SetDCPenColor_stub;
|
||||||
STUB GetDCBrushColor_stub;
|
STUB GetDCBrushColor_stub;
|
||||||
STUB GetDCPenColor_stub;
|
STUB GetDCPenColor_stub;
|
||||||
STUB AddFontMemResourceEx_stub;
|
|
||||||
STUB RemoveFontMemResourceEx_stub;
|
|
||||||
INT WINAPI AddFontResourceExW_new(LPCWSTR strW, DWORD fl, PVOID pdv);
|
INT WINAPI AddFontResourceExW_new(LPCWSTR strW, DWORD fl, PVOID pdv);
|
||||||
INT WINAPI AddFontResourceW_new(LPCWSTR strW);
|
INT WINAPI AddFontResourceW_new(LPCWSTR strW);
|
||||||
int WINAPI EnumFontFamiliesExA_new(HDC hdc, LPLOGFONTA pLogfontA, FONTENUMPROCA pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags);
|
int WINAPI EnumFontFamiliesExA_new(HDC hdc, LPLOGFONTA pLogfontA, FONTENUMPROCA pEnumFontFamExProc, LPARAM lParam, DWORD dwFlags);
|
||||||
|
@ -25,5 +25,3 @@ UNIMPL_FUNC(SetDCBrushColor, 2);
|
|||||||
UNIMPL_FUNC(SetDCPenColor, 2);
|
UNIMPL_FUNC(SetDCPenColor, 2);
|
||||||
UNIMPL_FUNC(GetDCBrushColor, 1);
|
UNIMPL_FUNC(GetDCBrushColor, 1);
|
||||||
UNIMPL_FUNC(GetDCPenColor, 1);
|
UNIMPL_FUNC(GetDCPenColor, 1);
|
||||||
UNIMPL_FUNC(AddFontMemResourceEx, 4);
|
|
||||||
UNIMPL_FUNC(RemoveFontMemResourceEx, 1);
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* KernelEx
|
* KernelEx
|
||||||
* Copyright (C) 2009, Xeno86
|
* Copyright (C) 2009-2010, Xeno86
|
||||||
* Copyright (C) 2009, Tihiy
|
* Copyright (C) 2009, Tihiy
|
||||||
*
|
*
|
||||||
* This file is part of KernelEx source code.
|
* This file is part of KernelEx source code.
|
||||||
@ -107,11 +107,19 @@ static int CALLBACK EnumFontFamExConv(const LOGFONTA *plfA,
|
|||||||
tmW->ntmTm.tmBreakChar = tmA->ntmTm.tmBreakChar;
|
tmW->ntmTm.tmBreakChar = tmA->ntmTm.tmBreakChar;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tmW->ntmTm.ntmFlags = tmA->ntmTm.ntmFlags;
|
if (FontType == TRUETYPE_FONTTYPE)
|
||||||
tmW->ntmTm.ntmSizeEM = tmA->ntmTm.ntmSizeEM;
|
{
|
||||||
tmW->ntmTm.ntmCellHeight = tmA->ntmTm.ntmCellHeight;
|
tmW->ntmTm.ntmFlags = tmA->ntmTm.ntmFlags;
|
||||||
tmW->ntmTm.ntmAvgWidth = tmA->ntmTm.ntmAvgWidth;
|
tmW->ntmTm.ntmSizeEM = tmA->ntmTm.ntmSizeEM;
|
||||||
memcpy(&tmW->ntmFontSig, &tmA->ntmFontSig, sizeof(FONTSIGNATURE));
|
tmW->ntmTm.ntmCellHeight = tmA->ntmTm.ntmCellHeight;
|
||||||
|
tmW->ntmTm.ntmAvgWidth = tmA->ntmTm.ntmAvgWidth;
|
||||||
|
memset(&tmW->ntmFontSig, 0, sizeof(FONTSIGNATURE));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(&tmW->ntmTm.ntmFlags, 0, sizeof(NEWTEXTMETRICEXW)
|
||||||
|
- FIELD_OFFSET(NEWTEXTMETRICEXW, ntmTm.ntmFlags));
|
||||||
|
}
|
||||||
|
|
||||||
return pef->EnumProcW((LOGFONTW*) &elfeW, (TEXTMETRICW*) &ntmeW, FontType, pef->lParam);
|
return pef->EnumProcW((LOGFONTW*) &elfeW, (TEXTMETRICW*) &ntmeW, FontType, pef->lParam);
|
||||||
}
|
}
|
||||||
|
@ -128,12 +128,12 @@ BOOL WINAPI WriteFile_fix(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesTo
|
|||||||
UINT WINAPI GetTempFileNameA_fix(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPTSTR lpTempFileName)
|
UINT WINAPI GetTempFileNameA_fix(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPTSTR lpTempFileName)
|
||||||
{
|
{
|
||||||
static int g_tempprefix = 0;
|
static int g_tempprefix = 0;
|
||||||
|
char temppref[2];
|
||||||
|
|
||||||
if (!lpPathName)
|
if (!lpPathName)
|
||||||
lpPathName = "\\";
|
lpPathName = "\\";
|
||||||
if (!lpPrefixString)
|
if (!lpPrefixString)
|
||||||
{
|
{
|
||||||
char temppref[2];
|
|
||||||
g_tempprefix++;
|
g_tempprefix++;
|
||||||
g_tempprefix %= 5;
|
g_tempprefix %= 5;
|
||||||
temppref[0] = '0' + g_tempprefix;
|
temppref[0] = '0' + g_tempprefix;
|
||||||
|
@ -223,9 +223,9 @@ LRESULT WINAPI CallProcAnsiWithUnicode( WNDPROC callback, HWND hwnd, UINT msg, W
|
|||||||
{
|
{
|
||||||
LPSTR textA;
|
LPSTR textA;
|
||||||
int len = CallWindowProcA( callback, hwnd, msg == LB_GETTEXT ? LB_GETTEXTLEN : CB_GETLBTEXTLEN, wParam, 0 );
|
int len = CallWindowProcA( callback, hwnd, msg == LB_GETTEXT ? LB_GETTEXTLEN : CB_GETLBTEXTLEN, wParam, 0 );
|
||||||
ABUFFER_ALLOC(textA,len);
|
ABUFFER_ALLOC(textA,len); //note that len does not include null
|
||||||
LRESULT ret = CallWindowProcA( callback, hwnd, msg, wParam,(LPARAM)textA );
|
LRESULT ret = CallWindowProcA( callback, hwnd, msg, wParam,(LPARAM)textA );
|
||||||
ABUFFER_toW(textA,lParam,len);
|
ABUFFER_toW(textA,lParam,len+1);
|
||||||
BUFFER_FREE(textA);
|
BUFFER_FREE(textA);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,9 @@
|
|||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
buffer = (LPSTR)alloca( buffer##size ); \
|
buffer = (LPSTR)alloca( buffer##size ); \
|
||||||
*buffer='\0';
|
buffer[0]='\0'; \
|
||||||
|
buffer[len]='\0'; \
|
||||||
|
buffer[buffer##size-1]='\0';
|
||||||
|
|
||||||
#define WBUFFER_ALLOC(buffer,len) \
|
#define WBUFFER_ALLOC(buffer,len) \
|
||||||
int buffer##size = ((len+1) * sizeof(WCHAR)); \
|
int buffer##size = ((len+1) * sizeof(WCHAR)); \
|
||||||
@ -74,7 +76,8 @@
|
|||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
buffer = (LPWSTR)alloca( buffer##size ); \
|
buffer = (LPWSTR)alloca( buffer##size ); \
|
||||||
*buffer='\0';
|
buffer[0]='\0'; \
|
||||||
|
buffer[len]='\0';
|
||||||
|
|
||||||
#define ABUFFER_toW(bufferA,bufferW,lenW) MultiByteToWideChar(CP_ACP, 0, bufferA, -1, (LPWSTR)bufferW, lenW);
|
#define ABUFFER_toW(bufferA,bufferW,lenW) MultiByteToWideChar(CP_ACP, 0, bufferA, -1, (LPWSTR)bufferW, lenW);
|
||||||
#define WBUFFER_toA(bufferW,bufferA,lenA) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)bufferA, lenA, NULL, NULL);
|
#define WBUFFER_toA(bufferW,bufferA,lenA) WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)bufferA, lenA, NULL, NULL);
|
||||||
|
@ -365,7 +365,7 @@ SOURCE=.\Gdi32\_gdi32_stubs.c
|
|||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\Gdi32\FontResourceExA.c
|
SOURCE=.\Gdi32\FontResourceEx.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ static const apilib_named_api shell32_named_apis[] =
|
|||||||
DECL_API("IsUserAnAdmin", IsUserAnAdmin_new),
|
DECL_API("IsUserAnAdmin", IsUserAnAdmin_new),
|
||||||
DECL_API("SHCreateShellItem", SHCreateShellItem_stub),
|
DECL_API("SHCreateShellItem", SHCreateShellItem_stub),
|
||||||
DECL_API("SHOpenFolderAndSelectItems", SHOpenFolderAndSelectItems_stub),
|
DECL_API("SHOpenFolderAndSelectItems", SHOpenFolderAndSelectItems_stub),
|
||||||
DECL_API("SHParseDisplayName", SHParseDisplayName_stub),
|
|
||||||
/*** AUTOGENERATED APILIST NAMED EXPORTS END ***/
|
/*** AUTOGENERATED APILIST NAMED EXPORTS END ***/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ extern const apilib_api_table apitable_shell32;
|
|||||||
/*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/
|
/*** AUTOGENERATED APILIST DECLARATIONS BEGIN ***/
|
||||||
LPWSTR* WINAPI CommandLineToArgvW_new(LPCWSTR lpCmdline, int* numargs);
|
LPWSTR* WINAPI CommandLineToArgvW_new(LPCWSTR lpCmdline, int* numargs);
|
||||||
BOOL WINAPI IsUserAnAdmin_new(void);
|
BOOL WINAPI IsUserAnAdmin_new(void);
|
||||||
STUB SHParseDisplayName_stub;
|
|
||||||
STUB SHCreateShellItem_stub;
|
STUB SHCreateShellItem_stub;
|
||||||
STUB SHOpenFolderAndSelectItems_stub;
|
STUB SHOpenFolderAndSelectItems_stub;
|
||||||
/*** AUTOGENERATED APILIST DECLARATIONS END ***/
|
/*** AUTOGENERATED APILIST DECLARATIONS END ***/
|
||||||
|
@ -21,6 +21,5 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
UNIMPL_FUNC(SHParseDisplayName, 5);
|
|
||||||
UNIMPL_FUNC(SHCreateShellItem, 4);
|
UNIMPL_FUNC(SHCreateShellItem, 4);
|
||||||
UNIMPL_FUNC(SHOpenFolderAndSelectItems, 4);
|
UNIMPL_FUNC(SHOpenFolderAndSelectItems, 4);
|
||||||
|
@ -10,15 +10,15 @@ REGEDIT4
|
|||||||
"*\\FIREFOX SETUP 3*.EXE"="WINXP"
|
"*\\FIREFOX SETUP 3*.EXE"="WINXP"
|
||||||
"*FIREFOX\\UNINSTALL\\HELPER.EXE"="WINXP"
|
"*FIREFOX\\UNINSTALL\\HELPER.EXE"="WINXP"
|
||||||
"*\\FIREFOX*PRE*.INSTALLER.EXE"="WINXP"
|
"*\\FIREFOX*PRE*.INSTALLER.EXE"="WINXP"
|
||||||
"*\\XUL.DLL"="WINXP"
|
"*\\XUL.DLL"="NT2K"
|
||||||
"*\\FIREFOX.EXE"="DCFG1"
|
"*\\FIREFOX.EXE"="DCFG1"
|
||||||
"*\\SEAMONKEY.EXE"="DCFG1"
|
"*\\SEAMONKEY.EXE"="DCFG1"
|
||||||
;-Java
|
;-Java
|
||||||
"*\\JAVA.EXE"="DCFG1"
|
"*\\JAVA.EXE"="DCFG1"
|
||||||
"*\\JAVAW.EXE"="DCFG1"
|
"*\\JAVAW.EXE"="DCFG1"
|
||||||
;-GIMP
|
;-GIMP
|
||||||
"*\\BIN\\GIMP-2.6.EXE"="WIN2K"
|
"*\\BIN\\GIMP-2.6.EXE"="NT2K"
|
||||||
"*\\GIMP-2.6*-SETUP.EXE"="WIN2K"
|
"*\\GIMP-2.6*-SETUP.EXE"="NT2K"
|
||||||
;-Webkit
|
;-Webkit
|
||||||
"*\\QTWEBKIT4.DLL"="WINXP"
|
"*\\QTWEBKIT4.DLL"="WINXP"
|
||||||
;-AbiWord
|
;-AbiWord
|
||||||
@ -55,4 +55,6 @@ REGEDIT4
|
|||||||
;-DirectX installer
|
;-DirectX installer
|
||||||
"*\\DXSETUP.EXE"=dword:00000001
|
"*\\DXSETUP.EXE"=dword:00000001
|
||||||
"*\\DXWEBSETUP.EXE"=dword:00000001
|
"*\\DXWEBSETUP.EXE"=dword:00000001
|
||||||
|
;-OpenOffice.org
|
||||||
|
"*\\PROGRAM\\CRASHREP.EXE"=dword:00000001
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
#ifndef __VERSION_H
|
#ifndef __VERSION_H
|
||||||
#define __VERSION_H
|
#define __VERSION_H
|
||||||
|
|
||||||
#define VERSION_STR "4.5 Beta 1"
|
#define VERSION_STR "4.5 Beta 2"
|
||||||
#define VERSION_CODE 0x04050001
|
#define VERSION_CODE 0x04050002
|
||||||
#define RCVERSION 4, 5, 0, 1
|
#define RCVERSION 4, 5, 0, 2
|
||||||
#define _RCVERSION_ "4, 5, 0, 1"
|
#define _RCVERSION_ "4, 5, 0, 2"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -44,6 +44,7 @@ void SettingsDB::clear()
|
|||||||
{
|
{
|
||||||
EnterCriticalSection(&cs);
|
EnterCriticalSection(&cs);
|
||||||
db.clear();
|
db.clear();
|
||||||
|
db_wild.clear();
|
||||||
appsetting as;
|
appsetting as;
|
||||||
as.flags = LDR_KEX_DISABLE;
|
as.flags = LDR_KEX_DISABLE;
|
||||||
db.insert(pair<sstring,appsetting>(own_path, as));
|
db.insert(pair<sstring,appsetting>(own_path, as));
|
||||||
@ -263,19 +264,19 @@ void SettingsDB::dump_db()
|
|||||||
{
|
{
|
||||||
map<sstring, appsetting>::const_iterator it;
|
map<sstring, appsetting>::const_iterator it;
|
||||||
|
|
||||||
dbgprintf("User settings:\n");
|
printf("User settings:\n");
|
||||||
for (it = db.begin() ; it != db.end() ; it++)
|
for (it = db.begin() ; it != db.end() ; it++)
|
||||||
{
|
{
|
||||||
ApiConfiguration* conf = it->second.conf;
|
ApiConfiguration* conf = it->second.conf;
|
||||||
dbgprintf("%-40s %-10s %02x\n", static_cast<const char*>(it->first),
|
printf("%-40s %-10s %02x\n", static_cast<const char*>(it->first),
|
||||||
conf ? conf->get_name() : "unknown", it->second.flags);
|
conf ? conf->get_name() : "unknown", it->second.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgprintf("\nPredefined settings:\n");
|
printf("\nPredefined settings:\n");
|
||||||
for (it = db_wild.begin() ; it != db_wild.end() ; it++)
|
for (it = db_wild.begin() ; it != db_wild.end() ; it++)
|
||||||
{
|
{
|
||||||
ApiConfiguration* conf = it->second.conf;
|
ApiConfiguration* conf = it->second.conf;
|
||||||
dbgprintf("%-40s %-10s %02x\n", static_cast<const char*>(it->first),
|
printf("%-40s %-10s %02x\n", static_cast<const char*>(it->first),
|
||||||
conf ? conf->get_name() : "unknown", it->second.flags);
|
conf ? conf->get_name() : "unknown", it->second.flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -542,20 +542,20 @@ bool ApiConfiguration::is_initialized()
|
|||||||
|
|
||||||
void ApiConfiguration::dump()
|
void ApiConfiguration::dump()
|
||||||
{
|
{
|
||||||
dbgprintf("ApiConfiguration %s\n", get_name());
|
printf("ApiConfiguration %s\n", get_name());
|
||||||
for (int i = 0 ; i < api_tables_count ; i++)
|
for (int i = 0 ; i < api_tables_count ; i++)
|
||||||
{
|
{
|
||||||
dbgprintf("Covered module #%d: %s\n", i, overridden_module_names[i]);
|
printf("Covered module #%d: %s\n", i, overridden_module_names[i]);
|
||||||
dbgprintf("Named apis (count = %d)\n", api_tables[i].named_apis_count);
|
printf("Named apis (count = %d)\n", api_tables[i].named_apis_count);
|
||||||
for (int j = 0 ; j < api_tables[i].named_apis_count ; j++)
|
for (int j = 0 ; j < api_tables[i].named_apis_count ; j++)
|
||||||
dbgprintf("\t%-32s %08x\n", api_tables[i].named_apis[j].api_name,
|
printf("\t%-32s %08x\n", api_tables[i].named_apis[j].api_name,
|
||||||
api_tables[i].named_apis[j].address);
|
api_tables[i].named_apis[j].address);
|
||||||
dbgprintf("Unnamed apis (count = %d)\n", api_tables[i].unnamed_apis_count);
|
printf("Unnamed apis (count = %d)\n", api_tables[i].unnamed_apis_count);
|
||||||
for (int j = 0 ; j < api_tables[i].unnamed_apis_count ; j++)
|
for (int j = 0 ; j < api_tables[i].unnamed_apis_count ; j++)
|
||||||
dbgprintf("\t%-5d %08x\n", j, api_tables[i].unnamed_apis[j]);
|
printf("\t%-5d %08x\n", j, api_tables[i].unnamed_apis[j]);
|
||||||
dbgprintf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
dbgprintf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -416,12 +416,12 @@ bool ApiConfigurationManager::parse_overrides(ApiConfiguration* apiconf)
|
|||||||
|
|
||||||
void ApiConfigurationManager::dump_configurations()
|
void ApiConfigurationManager::dump_configurations()
|
||||||
{
|
{
|
||||||
dbgprintf("Dumping all api configurations (count = %d) ...\n\n", apiconf_cnt);
|
printf("Dumping all api configurations (count = %d) ...\n\n", apiconf_cnt);
|
||||||
for (int i = 0 ; i < apiconf_cnt ; i++)
|
for (int i = 0 ; i < apiconf_cnt ; i++)
|
||||||
{
|
{
|
||||||
apiconf_ptrs[i]->dump();
|
apiconf_ptrs[i]->dump();
|
||||||
}
|
}
|
||||||
dbgprintf("End dump\n\n");
|
printf("End dump\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -713,18 +713,18 @@ void dump_imtes(void)
|
|||||||
IMTE** pmteModTable = *ppmteModTable;
|
IMTE** pmteModTable = *ppmteModTable;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
dbgprintf("Dumping IMTEs...\n");
|
printf("Dumping IMTEs...\n");
|
||||||
for (WORD i = 0 ; i < imteMax ; i++)
|
for (WORD i = 0 ; i < imteMax ; i++)
|
||||||
{
|
{
|
||||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||||
if (imte)
|
if (imte)
|
||||||
{
|
{
|
||||||
dbgprintf("%s\n", imte->pszFileName);
|
printf("%s\n", imte->pszFileName);
|
||||||
|
|
||||||
for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR)
|
for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR)
|
||||||
{
|
{
|
||||||
MODREF_KEX kmr(mr);
|
MODREF_KEX kmr(mr);
|
||||||
dbgprintf("\t%02x %-7s %-12s\n",
|
printf("\t%02x %-7s %-12s\n",
|
||||||
kmr.as.flags,
|
kmr.as.flags,
|
||||||
kmr.as.conf ? kmr.as.conf->get_name() : "none",
|
kmr.as.conf ? kmr.as.conf->get_name() : "none",
|
||||||
pmteModTable[mr->ppdb->pExeMODREF->mteIndex]->pszModName);
|
pmteModTable[mr->ppdb->pExeMODREF->mteIndex]->pszModName);
|
||||||
@ -733,7 +733,7 @@ void dump_imtes(void)
|
|||||||
total++;
|
total++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbgprintf("\nEnd dump total %d IMTEs\n\n", total);
|
printf("\nEnd dump total %d IMTEs\n\n", total);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,24 +31,6 @@ static HMODULE hShell32;
|
|||||||
static LPFNGETCLASSOBJECT SHGetClassObject;
|
static LPFNGETCLASSOBJECT SHGetClassObject;
|
||||||
|
|
||||||
|
|
||||||
/* Hall of shame */
|
|
||||||
static const char* blacklist[] = {
|
|
||||||
"COOLTYPE.DLL", /* Adobe Acrobat Reader 5.0.5, Adobe Photoshop 7.0 */
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static bool is_blacklisted()
|
|
||||||
{
|
|
||||||
for (int i = 0 ; blacklist[i] ; i++)
|
|
||||||
{
|
|
||||||
if (GetModuleHandle(blacklist[i]))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool is_shell32_v5()
|
static bool is_shell32_v5()
|
||||||
{
|
{
|
||||||
DLLGETVERSIONPROC DllGetVersion;
|
DLLGETVERSIONPROC DllGetVersion;
|
||||||
@ -146,12 +128,25 @@ STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HMODULE GetCurrentModule()
|
||||||
|
{
|
||||||
|
MEMORY_BASIC_INFORMATION mbi;
|
||||||
|
static int dummy;
|
||||||
|
VirtualQuery(&dummy, &mbi, sizeof(mbi));
|
||||||
|
return (HMODULE)mbi.AllocationBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
|
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||||
{
|
{
|
||||||
if (dwReason == DLL_PROCESS_ATTACH)
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
{
|
{
|
||||||
if (is_blacklisted())
|
char szPath[MAX_PATH];
|
||||||
return FALSE;
|
|
||||||
|
/* LoadLibrary(self) trick to prevent premature unload in buggy programs
|
||||||
|
* such as Adobe Photoshop, Acrobat Reader,... */
|
||||||
|
GetModuleFileName(GetCurrentModule(), szPath, sizeof(szPath));
|
||||||
|
LoadLibrary(szPath);
|
||||||
|
|
||||||
g_hModule = hModule;
|
g_hModule = hModule;
|
||||||
DisableThreadLibraryCalls(hModule);
|
DisableThreadLibraryCalls(hModule);
|
||||||
|
@ -70,6 +70,9 @@ bool kill_all_referents()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
|
|
||||||
|
//let the processes die before proceeding
|
||||||
|
Sleep(1000);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ void Setup::find_ExportFromX()
|
|||||||
{
|
{
|
||||||
static const short pattern[] = {
|
static const short pattern[] = {
|
||||||
0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0x40,0x10,0x8B,0x14,0x81,0x8B,0x44,
|
0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0x40,0x10,0x8B,0x14,0x81,0x8B,0x44,
|
||||||
0x24,0x14,0x3D,0x00,0x00,0x01,0x00,0x8B,0x4A,0x04,0x73,0x15,0x3B,0x1D,
|
0x24,0x14,0x3D,0x00,0x00,0x01,0x00,0x8B,0x4A,0x04,0x73,0x15,-1,0x1D,
|
||||||
-1,-1,-1,-1,0x75,0x04,0x6A,0x32,0xEB,0x3E,0x50,0x51,0xE8,-2,-2,-2,-2,
|
-1,-1,-1,-1,0x75,0x04,0x6A,0x32,0xEB,0x3E,0x50,0x51,0xE8,-2,-2,-2,-2,
|
||||||
0xEB,0x0C,0xFF,0x74,0x24,0x14,0x6A,0x00,0x51,0xE8,-2,-2,-2,-2,0x83,
|
0xEB,0x0C,0xFF,0x74,0x24,0x14,0x6A,0x00,0x51,0xE8,-2,-2,-2,-2,0x83,
|
||||||
0x7F,0x54,0x00,0x8B,0xF0
|
0x7F,0x54,0x00,0x8B,0xF0
|
||||||
|
Reference in New Issue
Block a user