2036 lines
57 KiB
Batchfile
2036 lines
57 KiB
Batchfile
@rem = '--*-Perl-*--
|
|
@echo off
|
|
if "%OS%" == "Windows_NT" goto WinNT
|
|
perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
|
goto endofperl
|
|
:WinNT
|
|
perl -x -S "%0" %*
|
|
if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
|
|
if %errorlevel% == 9009 echo You do not have Perl in your PATH.
|
|
goto endofperl
|
|
@rem ';
|
|
#!perl
|
|
#line 14
|
|
|
|
#
|
|
# This Perl program generates the "IsolationAware" stubs
|
|
# in winbase.inl, winuser.inl, prsht.h, commctrl.h, commdlg.h.
|
|
#
|
|
# It is run by the makefile.inc files in
|
|
# base\published
|
|
# windows\published
|
|
# shell\published\inc
|
|
#
|
|
# The name "shfusion2" comes from these stubs being the public replacement
|
|
# for "shfusion" -- shell\lib\shfusion.
|
|
#
|
|
# Generation of the stubs is driven by declarations in the .w files.
|
|
# The stubs vary in a few ways.
|
|
# Some are just for delayload purposes -- all the actctx functions.
|
|
# Some delayload the entire .dll -- comctl32.dll.
|
|
# Others activate around static links -- kernel32.dll, user32.dll, comdlg32.dll
|
|
# some do not activate at all -- the actctx functions
|
|
# winbase.inl gets an extra chunk of "less generated" / "relatively hardcoded"
|
|
# code, that the stubs in the other files depend on.
|
|
# winbase.inl exports two symbols to all the stubs, and one extra symbol
|
|
# to two stubs in prsht.h
|
|
# The two symbols are ActivateMyActCtx, g_fDownlevel.
|
|
# The third symbol is g_hActCtx.
|
|
# All symbols get "mangled".
|
|
# Each header also gets a small function for calling GetProcAddress with an implied
|
|
# HMODULE parameter. This function's name is also "mangled".
|
|
# Besides "mangling", all external symbols are clearly "namespaced" with a relatively
|
|
# long "namespace" -- IsolationAware or IsolationAwarePrivate.
|
|
#
|
|
# owner=JayKrell
|
|
#
|
|
|
|
#
|
|
# $ scalar/string/number
|
|
# @ list/array
|
|
# $ hash
|
|
# {} hash
|
|
#
|
|
|
|
$true = 1;
|
|
$false = 0;
|
|
$newline = "\n";
|
|
|
|
$ErrorMessagePrefix = 'NMAKE : U1234: ' . $ENV{'SDXROOT'} . '\\tools\\shfusion2.bat ';
|
|
|
|
sub ErrorExit
|
|
{
|
|
exit;
|
|
}
|
|
|
|
sub ErrorPrint
|
|
{
|
|
print(@_);
|
|
}
|
|
|
|
sub DebugPrint
|
|
{
|
|
print(@_);
|
|
}
|
|
|
|
sub DebugExit
|
|
{
|
|
exit;
|
|
}
|
|
|
|
sub EarlySuccessExit
|
|
{
|
|
exit;
|
|
}
|
|
|
|
sub MakeLower
|
|
{
|
|
my($x) = ($_[0]);
|
|
return "\L$x";
|
|
}
|
|
|
|
sub MakeUpper
|
|
{
|
|
my($x) = ($_[0]);
|
|
return "\U$x";
|
|
}
|
|
|
|
sub MakeTitlecase
|
|
{
|
|
# first character uppercase, the rest lowercase
|
|
my($x) = ($_[0]);
|
|
$x = "\L$x";
|
|
$x = "\u$x";
|
|
return $x;
|
|
}
|
|
|
|
sub ToIdentifier
|
|
{
|
|
# replace dots with underscores
|
|
my($x) = ($_[0]);
|
|
$x =~ s/\./_/g;
|
|
return $x;
|
|
}
|
|
|
|
sub RemoveSpacesAroundStars
|
|
{
|
|
my($x) = ($_[0]);
|
|
$x =~ s/ *\* */\*/g;
|
|
return $x;
|
|
}
|
|
|
|
sub RemoveSpacesAroundCommas
|
|
{
|
|
my($x) = ($_[0]);
|
|
$x =~ s/ *, */,/g;
|
|
return $x;
|
|
}
|
|
|
|
sub RemoveTrailingComma
|
|
{
|
|
my($x) = ($_[0]);
|
|
$x =~ s/, *$//g;
|
|
return $x;
|
|
}
|
|
|
|
sub RemoveLeadingAndTrailingSpaces
|
|
{
|
|
my($x) = ($_[0]);
|
|
$x =~ s/^ +//g;
|
|
$x =~ s/ +$//g;
|
|
return $x;
|
|
}
|
|
|
|
sub MakePublicCapitalizedSymbol
|
|
{
|
|
#
|
|
# ISOLATION_AWARE_WORDWITHNOUNDERSCORES
|
|
# ISOLATIONAWARE_MULTIPLE_UNDERSCORE_SEPERATED_WORDS
|
|
#
|
|
# not great, but consistent with existing symbols
|
|
#
|
|
my($name) = ($_[0]);
|
|
if ($name !~ /[A-Z_0-9]/)
|
|
{
|
|
# warning..
|
|
}
|
|
if ($name =~ /_/)
|
|
{
|
|
return "ISOLATIONAWARE_" . $name;
|
|
}
|
|
else
|
|
{
|
|
return "ISOLATION_AWARE_" . $name;
|
|
}
|
|
}
|
|
|
|
sub MakePublicPreprocessorSymbol
|
|
{
|
|
my($name) = ($_[0]);
|
|
return MakePublicCapitalizedSymbol($name);
|
|
}
|
|
|
|
sub ComInterfaceParameterReplacementIdentifier
|
|
{
|
|
my($name) = ($_[0]);
|
|
$header = BaseName($headerLeafName);
|
|
|
|
if ($name =~ /^[A-Z_0-9]+$/)
|
|
{
|
|
$name = 'ISOLATIONAWARE' . MakeUpper($header) . '_' . $name;
|
|
}
|
|
elsif ($name =~ /^[A-Z0-9]+$/)
|
|
{
|
|
$name = 'ISOLATION_AWARE_' . MakeUpper($header) . '_' . $name;
|
|
}
|
|
else
|
|
{
|
|
$name = 'IsolationAware' . MakeTitlecase($header) . $name;
|
|
}
|
|
return $name;
|
|
}
|
|
|
|
$INLINE = MakePublicPreprocessorSymbol("INLINE");
|
|
|
|
sub ObscurePrivateName
|
|
{
|
|
my ($namespace,$x) = ($_[0],$_[1]);
|
|
|
|
$x =~ tr/0-9/a-j/;
|
|
|
|
#
|
|
# shift and sometimes invert case
|
|
#
|
|
$x =~ tr/a-zA-Z/N-Za-mn-zA-M/;
|
|
|
|
return $namespace . $x;
|
|
}
|
|
|
|
sub MakeHeaderPrivateName
|
|
{
|
|
my($header, $name) = ($_[0], $_[1]);
|
|
$header = MakeTitlecase(BaseName($header));
|
|
|
|
return ObscurePrivateName($header . 'IsolationAwarePrivate', $name);
|
|
}
|
|
|
|
sub MakeMultiHeaderPrivateName
|
|
{
|
|
my($name) = ($_[0]);
|
|
return ObscurePrivateName('IsolationAwarePrivate', $name);
|
|
}
|
|
|
|
sub MakePublicName
|
|
{
|
|
# IsolationAwareFoo
|
|
my($name) = ($_[0]);
|
|
return "IsolationAware" . $name;
|
|
}
|
|
|
|
# g_hActCtx is also used by prsht.h
|
|
$g_hActCtx = MakeHeaderPrivateName('winbase.h', 'g_hActCtx');
|
|
$g_fDownlevel = MakeMultiHeaderPrivateName('g_fDownlevel');
|
|
$g_fCreatedActCtx = MakeHeaderPrivateName('winbase.h', 'g_fCreatedActCtx');
|
|
$g_fCleanupCalled = MakeHeaderPrivateName('winbase.h', 'g_fCleanupCalled');
|
|
$ActivateMyActCtx = MakeMultiHeaderPrivateName('ActivateMyActCtx');
|
|
$GetMyActCtx = MakeHeaderPrivateName('winbase.h', 'GetMyActCtx');
|
|
$QueryActCtxW = MakePublicName('QueryActCtxW');
|
|
$FindActCtxSectionStringW = MakePublicName('FindActCtxSectionStringW');
|
|
$ActivateActCtx = MakePublicName('ActivateActCtx');
|
|
$DeactivateActCtx = MakePublicName('DeactivateActCtx');
|
|
$Init = MakePublicName('Init');
|
|
$Cleanup = MakePublicName('Cleanup');
|
|
$CreateActCtxW = MakePublicName('CreateActCtxW');
|
|
$MyGetProcAddress = MakeMultiHeaderPrivateName('MyGetProcAddress');
|
|
$LoadA = MakeHeaderPrivateName('winbase.h', 'LoadA');
|
|
$LoadW = MakeHeaderPrivateName('winbase.h', 'LoadW');
|
|
$NameA = MakeHeaderPrivateName('winbase.h', 'NameA');
|
|
$NameW = MakeHeaderPrivateName('winbase.h', 'NameW');
|
|
$LoadedModule = MakeHeaderPrivateName('winbase.h', 'LoadedModule');
|
|
|
|
$CONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('CONSTANT_MODULE_INFO');
|
|
$_CONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('_CONSTANT_MODULE_INFO');
|
|
$PCONSTANT_MODULE_INFO = MakeMultiHeaderPrivateName('PCONSTANT_MODULE_INFO');
|
|
|
|
$MUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('MUTABLE_MODULE_INFO');
|
|
$_MUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('_MUTABLE_MODULE_INFO');
|
|
$PMUTABLE_MODULE_INFO = MakeMultiHeaderPrivateName('PMUTABLE_MODULE_INFO');
|
|
|
|
$ENABLED = MakePublicPreprocessorSymbol('ENABLED');
|
|
|
|
$MyLoadLibraryA = MakeMultiHeaderPrivateName('MyLoadLibraryA');
|
|
$MyLoadLibraryW = MakeMultiHeaderPrivateName('MyLoadLibraryW');
|
|
$MyGetModuleHandleA = MakeMultiHeaderPrivateName('MyGetModuleHandleA');
|
|
$MyGetModuleHandleW = MakeMultiHeaderPrivateName('MyGetModuleHandleW');
|
|
|
|
use Class::Struct;
|
|
use IO::File;
|
|
|
|
#
|
|
# If ENV{_NTDRIVE} or ENV{_NTROOT} not defined, look here.
|
|
#
|
|
%NtDriveRootDefaults =
|
|
(
|
|
"jaykrell" =>
|
|
{
|
|
"_NTDRIVE" => "f:",
|
|
"_NTROOT" => "\\jaykrell"
|
|
},
|
|
"default" =>
|
|
{
|
|
"_NTDRIVE" => "z:",
|
|
"_NTROOT" => "\\nt"
|
|
}
|
|
);
|
|
|
|
sub Indent
|
|
{
|
|
return $_[0] . " ";
|
|
}
|
|
|
|
sub Outdent
|
|
{
|
|
return substr($_[0], 4);
|
|
}
|
|
|
|
#
|
|
# for Perl embedded in headers, stick data in global hashtables, but hide
|
|
# the Perl syntax in what looks like C function calls.
|
|
#
|
|
sub DeclareFunctionErrorValue
|
|
{
|
|
my($function,$errorValue) = ($_[0], $_[1]);
|
|
$FunctionErrorValue{$function} = MakeStringTrue($errorValue);
|
|
#DebugPrint($function . " error value is " . $errorValue . "\n");
|
|
}
|
|
sub DelayLoad { $DelayLoad{$_[0]} = 1; }
|
|
sub MapHeaderToDll { $MapHeaderToDll{MakeLower(BaseName($_[0]))} = MakeLower($_[1]); }
|
|
sub ActivateAroundDelayLoad { DelayLoad($_[0]); $ActivateAroundDelayLoad{$_[0]} = 1; }
|
|
sub ActivateAroundFunctionCall { $ActivateAroundFunctionCall{$_[0]} = 1; }
|
|
sub NoActivateAroundFunctionCall {$NoActivateAroundFunctionCall{$_[0]} = 1;}
|
|
sub ActivateNULLAroundFunctionCall { $ActivateNULLAroundFunctionCall{$_[0]} = 1; }
|
|
sub PerHeaderMacroEnable { $PerHeaderMacroEnable{MakeLower(BaseName($_[0]))} = 1; }
|
|
sub DeclareExportName32 { $ExportName32{$_[0]} = $_[1]; }
|
|
sub DeclareExportName64 { $ExportName64{$_[0]} = $_[1]; }
|
|
sub Undef { $Undef{$_[0]} = 1; }
|
|
sub PoundIf { $PoundIfCondition{$_[0]} = $_[1]; }
|
|
sub SetInsertionPoint { $InsertionPoint{MakeLower(BaseName($_[0]))} = $_[1]; }
|
|
sub IgnoreFunction { $IgnoreFunction{$_[0]} = 1; }
|
|
sub NeverFails { $NeverFails{$_[0]} = 1; $ActivateAroundFunctionCall{$_[0]} = 0; $ActivateAroundDelayLoad{$_[0]} = 0; }
|
|
sub NoMacro { $NoMacro{$_[0]} = 1; }
|
|
|
|
#
|
|
# MFC #includes commctrl.h without __IStream_INTERFACE_DEFINED__ defined but
|
|
# then later manually declares ImageList_Read/Write.
|
|
#
|
|
# Let ISOLATION_AWARE_ENABLED mean that ImageList_Read/Write/Ex declarations are really
|
|
# desired even if __IStream_INTERFACE_DEFINED__ is not defined.
|
|
#
|
|
sub DeclareComInterface
|
|
{
|
|
#
|
|
# for example: DeclareComInterface("IStream", "LPSTREAM", "typedef IStream *LPSTREAM;");
|
|
#
|
|
my($interface) = ($_[0]);
|
|
my($parameter_type) = ($_[1]);
|
|
my($typedef) = ($_[2]);
|
|
|
|
$ComInterfaceParameterType{$parameter_type} = $interface;
|
|
$ComInterfaceParameterTypedef{$parameter_type} = $typedef;
|
|
}
|
|
|
|
#
|
|
# for Perl on the command line
|
|
#
|
|
sub SetStubsFile
|
|
{
|
|
$StubsFile = $_[0];
|
|
#DebugPrint("StubsFile is " . $StubsFile . "\n");
|
|
}
|
|
|
|
|
|
sub LeafPath
|
|
{
|
|
my($x) = ($_[0]);
|
|
my($y)= $x;
|
|
if ($y =~ /\\/) # does it contain slashes?
|
|
{
|
|
($y) = ($x =~ /.*\\(.+)/); # get everything after the last slash
|
|
}
|
|
#DebugPrint("leaf path of $x is $y\n");
|
|
return $y;
|
|
}
|
|
|
|
sub BaseName
|
|
{
|
|
my($x) = ($_[0]);
|
|
$x = LeafPath($x);
|
|
if ($x =~ /\./)
|
|
{
|
|
$x =~ s/^(.*)\..*$/$1/;
|
|
}
|
|
return $x;
|
|
}
|
|
|
|
sub RemoveExtension { return BaseName($_[0]); }
|
|
|
|
sub GetNtDriveOrRoot
|
|
{
|
|
my($name) = ($_[0]);
|
|
my($x);
|
|
|
|
$x = $ENV{$name};
|
|
if ($x)
|
|
{
|
|
return $x;
|
|
}
|
|
$x = $NtDriveRootDefaults{MakeLower($ENV{"COMPUTERNAME"})}
|
|
|| $NtDriveRootDefaults{MakeLower($ENV{"USERNAME"})}
|
|
|| $NtDriveRootDefaults{$ENV{"default"}};
|
|
return $x{$name};
|
|
}
|
|
|
|
sub GetNtDrive
|
|
{
|
|
return GetNtDriveOrRoot("_NTDRIVE");
|
|
};
|
|
|
|
sub GetNtRoot
|
|
{
|
|
return GetNtDriveOrRoot("_NTROOT");
|
|
};
|
|
|
|
struct Function => # I don't know what syntax is in play here, just following an example..
|
|
{
|
|
name => '$',
|
|
ret => '$',
|
|
retname => '$', # just for Hungarian purposes
|
|
#
|
|
# argsTypesNames and argNames are comma delimited strings,
|
|
# wrapped in parentheses.
|
|
#
|
|
# argsTypeNames and argsNames are exactly the forms we need to
|
|
# print a few times.
|
|
#
|
|
# For more sophisticated processing, these should be arrays or hashes,
|
|
# and we would save away argsTypes too.
|
|
#
|
|
argsTypesNames => '$',
|
|
argsNames => '$',
|
|
error => '$', # eg NULL, 0, -1, FALSE
|
|
dll => '$', # eg: kernel32.dll, comctl32.dll
|
|
header => '$', # eg: winuser, commctrl
|
|
delayload => '$', # boolean
|
|
};
|
|
|
|
#
|
|
# Headers have versions of GetProcAddress where the .dll is implied.
|
|
# This generates a call to such a GetProcAddress wrapper.
|
|
#
|
|
sub GenerateGetProcAddressCall
|
|
{
|
|
my($header, $dll, $function) = ($_[0], $_[1], $_[2]);
|
|
my($x);
|
|
|
|
$dll = MakeTitlecase($dll);
|
|
|
|
$x .= MakeHeaderPrivateName($header, 'GetProcAddress_' . ToIdentifier($dll));
|
|
$x .= '("' . $function . '")';
|
|
|
|
return $x;
|
|
}
|
|
|
|
$code = '';
|
|
|
|
$WinbaseSpecialCode1='
|
|
|
|
/* These wrappers prevent warnings about taking the addresses of __declspec(dllimport) functions. */
|
|
' . $INLINE . ' HMODULE WINAPI '. $MyLoadLibraryA .'(LPCSTR s) { return LoadLibraryA(s); }
|
|
' . $INLINE . ' HMODULE WINAPI '. $MyLoadLibraryW .'(LPCWSTR s) { return LoadLibraryW(s); }
|
|
' . $INLINE . ' HMODULE WINAPI '. $MyGetModuleHandleA .'(LPCSTR s) { return GetModuleHandleA(s); }
|
|
' . $INLINE . ' HMODULE WINAPI '. $MyGetModuleHandleW .'(LPCWSTR s) { return GetModuleHandleW(s); }
|
|
|
|
/* temporary support for out of sync headers */
|
|
#define IsolationAwarePrivateG_FqbjaLEiEL ' . $g_fDownlevel . '
|
|
#define IsolationAwarePrivatenCgIiAgEzlnCgpgk ' . $ActivateMyActCtx . '
|
|
#define WinbaseIsolationAwarePrivateG_HnCgpgk ' . $g_hActCtx . '
|
|
#define IsolationAwarePrivatezlybADyIBeAeln ' . $MyLoadLibraryA . '
|
|
#define IsolationAwarePrivatezlybADyIBeAelJ ' . $MyLoadLibraryW . '
|
|
#define IsolationAwarePrivatezltEgCebCnDDeEff ' . $MyGetProcAddress . '
|
|
|
|
BOOL WINAPI ' . $ActivateMyActCtx . '(ULONG_PTR* pulpCookie);
|
|
|
|
/*
|
|
These are private.
|
|
*/
|
|
__declspec(selectany) HANDLE ' . $g_hActCtx . ' = INVALID_HANDLE_VALUE;
|
|
__declspec(selectany) BOOL ' . $g_fDownlevel . ' = FALSE;
|
|
__declspec(selectany) BOOL ' . $g_fCreatedActCtx . ' = FALSE;
|
|
__declspec(selectany) BOOL ' . $g_fCleanupCalled . ' = FALSE;
|
|
|
|
';
|
|
|
|
$WinbaseSpecialCode2='
|
|
|
|
#define WINBASE_NUMBER_OF(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
typedef struct ' . $_CONSTANT_MODULE_INFO . ' {
|
|
HMODULE (WINAPI * ' . $LoadA . ')(LPCSTR a);
|
|
HMODULE (WINAPI * ' . $LoadW . ')(LPCWSTR w);
|
|
PCSTR ' . $NameA . ';
|
|
PCWSTR ' . $NameW . ';
|
|
} ' . $CONSTANT_MODULE_INFO . ';
|
|
typedef const ' . $CONSTANT_MODULE_INFO . ' *' . $PCONSTANT_MODULE_INFO . ';
|
|
|
|
typedef struct ' . $_MUTABLE_MODULE_INFO . ' {
|
|
HMODULE ' . $LoadedModule . ';
|
|
} ' . $MUTABLE_MODULE_INFO . ', *' . $PMUTABLE_MODULE_INFO . ';
|
|
|
|
' . $INLINE . ' FARPROC WINAPI
|
|
' . $MyGetProcAddress . '(
|
|
' . $PCONSTANT_MODULE_INFO . ' c,
|
|
' . $PMUTABLE_MODULE_INFO . ' m,
|
|
LPCSTR ProcName
|
|
)
|
|
{
|
|
static HMODULE s_moduleUnicows;
|
|
static BOOL s_fUnicowsInitialized;
|
|
FARPROC Proc = NULL;
|
|
HMODULE hModule;
|
|
|
|
/*
|
|
get unicows.dll loaded on-demand
|
|
*/
|
|
if (!s_fUnicowsInitialized)
|
|
{
|
|
if ((GetVersion() & 0x80000000) != 0)
|
|
{
|
|
GetFileAttributesW(L"???.???");
|
|
s_moduleUnicows = GetModuleHandleA("Unicows.dll");
|
|
}
|
|
s_fUnicowsInitialized = TRUE;
|
|
}
|
|
|
|
/*
|
|
always call GetProcAddress(unicows) before the usual .dll
|
|
*/
|
|
if (s_moduleUnicows != NULL)
|
|
{
|
|
Proc = GetProcAddress(s_moduleUnicows, ProcName);
|
|
if (Proc != NULL)
|
|
goto Exit;
|
|
}
|
|
|
|
hModule = m->' . $LoadedModule . ';
|
|
if (hModule == NULL)
|
|
{
|
|
hModule = (((GetVersion() & 0x80000000) != 0) ? (*c->' . $LoadA . ')(c->' . $NameA . ') : (*c->' . $LoadW . ')(c->' . $NameW . '));
|
|
if (hModule == NULL)
|
|
goto Exit;
|
|
m->' . $LoadedModule . ' = hModule;
|
|
}
|
|
Proc = GetProcAddress(hModule, ProcName);
|
|
Exit:
|
|
return Proc;
|
|
}
|
|
|
|
' . $INLINE . ' BOOL WINAPI ' . $GetMyActCtx . '(void)
|
|
/*
|
|
The correctness of this function depends on it being statically
|
|
linked into its clients.
|
|
|
|
This function is private to functions present in this header.
|
|
Do not use it.
|
|
*/
|
|
{
|
|
BOOL fResult = FALSE;
|
|
ACTIVATION_CONTEXT_BASIC_INFORMATION actCtxBasicInfo;
|
|
ULONG_PTR ulpCookie = 0;
|
|
|
|
if (' . $g_fDownlevel . ')
|
|
{
|
|
fResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (' . $g_hActCtx . ' != INVALID_HANDLE_VALUE)
|
|
{
|
|
fResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!' . $QueryActCtxW . '(
|
|
QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS
|
|
| QUERY_ACTCTX_FLAG_NO_ADDREF,
|
|
&' . $g_hActCtx . ',
|
|
NULL,
|
|
ActivationContextBasicInformation,
|
|
&actCtxBasicInfo,
|
|
sizeof(actCtxBasicInfo),
|
|
NULL
|
|
))
|
|
goto Exit;
|
|
|
|
/*
|
|
If QueryActCtxW returns NULL, try CreateActCtx(3).
|
|
*/
|
|
if (actCtxBasicInfo.hActCtx == NULL)
|
|
{
|
|
ACTCTXW actCtx;
|
|
WCHAR rgchFullModulePath[MAX_PATH + 2];
|
|
DWORD dw;
|
|
HMODULE hmodSelf;
|
|
PGET_MODULE_HANDLE_EXW pfnGetModuleHandleExW;
|
|
|
|
pfnGetModuleHandleExW = (PGET_MODULE_HANDLE_EXW)' . GenerateGetProcAddressCall('winbase.h', 'kernel32.dll', 'GetModuleHandleExW') . ';
|
|
if (pfnGetModuleHandleExW == NULL)
|
|
goto Exit;
|
|
|
|
if (!(*pfnGetModuleHandleExW)(
|
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
|
|
| GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
|
(LPCWSTR)&' . $g_hActCtx . ',
|
|
&hmodSelf
|
|
))
|
|
goto Exit;
|
|
|
|
rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 1] = 0;
|
|
rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] = 0;
|
|
dw = GetModuleFileNameW(hmodSelf, rgchFullModulePath, WINBASE_NUMBER_OF(rgchFullModulePath)-1);
|
|
if (dw == 0)
|
|
goto Exit;
|
|
if (rgchFullModulePath[WINBASE_NUMBER_OF(rgchFullModulePath) - 2] != 0)
|
|
{
|
|
SetLastError(ERROR_BUFFER_OVERFLOW);
|
|
goto Exit;
|
|
}
|
|
|
|
actCtx.cbSize = sizeof(actCtx);
|
|
actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
|
|
actCtx.lpSource = rgchFullModulePath;
|
|
actCtx.lpResourceName = (LPCWSTR)(ULONG_PTR)3;
|
|
actCtx.hModule = hmodSelf;
|
|
actCtxBasicInfo.hActCtx = ' . $CreateActCtxW . '(&actCtx);
|
|
if (actCtxBasicInfo.hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
const DWORD dwLastError = GetLastError();
|
|
if ((dwLastError != ERROR_RESOURCE_DATA_NOT_FOUND) &&
|
|
(dwLastError != ERROR_RESOURCE_TYPE_NOT_FOUND) &&
|
|
(dwLastError != ERROR_RESOURCE_LANG_NOT_FOUND) &&
|
|
(dwLastError != ERROR_RESOURCE_NAME_NOT_FOUND))
|
|
goto Exit;
|
|
|
|
actCtxBasicInfo.hActCtx = NULL;
|
|
}
|
|
|
|
' . $g_fCreatedActCtx . ' = TRUE;
|
|
}
|
|
|
|
' . $g_hActCtx . ' = actCtxBasicInfo.hActCtx;
|
|
|
|
#define ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION (2)
|
|
|
|
if (' . $ActivateActCtx . '(actCtxBasicInfo.hActCtx, &ulpCookie))
|
|
{
|
|
__try
|
|
{
|
|
ACTCTX_SECTION_KEYED_DATA actCtxSectionKeyedData;
|
|
|
|
actCtxSectionKeyedData.cbSize = sizeof(actCtxSectionKeyedData);
|
|
if (' . $FindActCtxSectionStringW . '(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"Comctl32.dll", &actCtxSectionKeyedData))
|
|
{
|
|
/* get button, edit, etc. registered */
|
|
LoadLibraryW(L"Comctl32.dll");
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
' . $DeactivateActCtx . '(0, ulpCookie);
|
|
}
|
|
}
|
|
|
|
fResult = TRUE;
|
|
Exit:
|
|
return fResult;
|
|
}
|
|
|
|
' . $INLINE . ' BOOL WINAPI ' . $Init . '(void)
|
|
/*
|
|
The correctness of this function depends on it being statically
|
|
linked into its clients.
|
|
|
|
Call this from DllMain(DLL_PROCESS_ATTACH) if you use id 3 and wish to avoid a race condition that
|
|
can cause an hActCtx leak.
|
|
Call this from your .exe\'s initialization if you use id 3 and wish to avoid a race condition that
|
|
can cause an hActCtx leak.
|
|
If you use id 2, this function fetches data from your .dll
|
|
that you do not need to worry about cleaning up.
|
|
*/
|
|
{
|
|
return ' . $GetMyActCtx . '();
|
|
}
|
|
|
|
' . $INLINE . ' void WINAPI ' . $Cleanup . '(void)
|
|
/*
|
|
Call this from DllMain(DLL_PROCESS_DETACH), if you use id 3, to avoid a leak.
|
|
Call this from your .exe\'s cleanup to possibly avoid apparent (but not actual) leaks, if use id 3.
|
|
This function does nothing, safely, if you use id 2.
|
|
*/
|
|
{
|
|
HANDLE hActCtx;
|
|
|
|
if (' . $g_fCleanupCalled . ')
|
|
return;
|
|
|
|
/* IsolationAware* calls made from here on out will OutputDebugString
|
|
and use the process default activation context instead of id 3 or will
|
|
continue to successfully use id 2 (but still OutputDebugString).
|
|
*/
|
|
' . $g_fCleanupCalled . ' = TRUE;
|
|
|
|
/* There is no cleanup to do if we did not CreateActCtx but only called QueryActCtx.
|
|
*/
|
|
if (!' . $g_fCreatedActCtx . ')
|
|
return;
|
|
|
|
hActCtx = ' . $g_hActCtx . ';
|
|
' . $g_hActCtx . ' = NULL; /* process default */
|
|
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
return;
|
|
if (hActCtx == NULL)
|
|
return;
|
|
IsolationAwareReleaseActCtx(hActCtx);
|
|
}
|
|
|
|
' . $INLINE . ' BOOL WINAPI ' . $ActivateMyActCtx . '(ULONG_PTR* pulpCookie)
|
|
/*
|
|
This function is private to functions present in this header and other headers.
|
|
*/
|
|
{
|
|
BOOL fResult = FALSE;
|
|
|
|
if (' . $g_fCleanupCalled . ')
|
|
{
|
|
const static char debugString[] = "IsolationAware function called after ' . $Cleanup . '\\n";
|
|
OutputDebugStringA(debugString);
|
|
}
|
|
|
|
if (' . $g_fDownlevel . ')
|
|
{
|
|
fResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
/* Do not call Init if Cleanup has been called. */
|
|
if (!' . $g_fCleanupCalled . ')
|
|
{
|
|
if (!' . $GetMyActCtx . '())
|
|
goto Exit;
|
|
}
|
|
/* If Cleanup has been called and id3 was in use, this will activate NULL. */
|
|
if (!' . $ActivateActCtx . '(' . $g_hActCtx . ', pulpCookie))
|
|
goto Exit;
|
|
|
|
fResult = TRUE;
|
|
Exit:
|
|
if (!fResult)
|
|
{
|
|
const DWORD dwLastError = GetLastError();
|
|
if (dwLastError == ERROR_PROC_NOT_FOUND
|
|
|| dwLastError == ERROR_CALL_NOT_IMPLEMENTED
|
|
)
|
|
{
|
|
' . $g_fDownlevel . ' = TRUE;
|
|
fResult = TRUE;
|
|
}
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
#undef WINBASE_NUMBER_OF
|
|
|
|
'
|
|
;
|
|
|
|
%MapHeaderToSpecialCode1 =
|
|
(
|
|
"winbase" => $WinbaseSpecialCode1,
|
|
"winbase.h" => $WinbaseSpecialCode1,
|
|
"Winbase" => $WinbaseSpecialCode1,
|
|
"Winbase.h" => $WinbaseSpecialCode1,
|
|
);
|
|
|
|
%MapHeaderToSpecialCode2 =
|
|
(
|
|
"winbase" => $WinbaseSpecialCode2,
|
|
"winbase.h" => $WinbaseSpecialCode2,
|
|
"Winbase" => $WinbaseSpecialCode2,
|
|
"Winbase.h" => $WinbaseSpecialCode2,
|
|
);
|
|
|
|
sub MakeStringTrue
|
|
{
|
|
($_[0] eq "0") ? "0 " : $_[0];
|
|
}
|
|
|
|
%TypeErrorValue =
|
|
(
|
|
# Individual functions can override with a #!perl comment.
|
|
# Functions that return an integer must specify. 0, -1, ~0 are too evenly split.
|
|
# HANDLE must specify (NULL, INVALID_HANDLE..)
|
|
"BOOL" => "FALSE",
|
|
"bool" => "false",
|
|
"PVOID" => "NULL",
|
|
"HICON" => "NULL",
|
|
"HIMAGELIST" => "NULL",
|
|
"HWND" => "NULL",
|
|
"COLORREF" => "RGB(0,0,0)",
|
|
"HBITMAP" => "NULL",
|
|
"LANGID" => "0",
|
|
"ATOM" => "0",
|
|
"HPROPSHEETPAGE" => "NULL",
|
|
"HDSA" => "NULL",
|
|
"HDPA" => "NULL",
|
|
|
|
# HRESULTs are treated specially!
|
|
"HRESULT" => "S_OK"
|
|
);
|
|
|
|
sub IndentMultiLineString
|
|
{
|
|
my ($indent, $string) = ($_[0], $_[1]);
|
|
|
|
if ($string)
|
|
{
|
|
$string = $indent . join("\n" . $indent, split("\n", $string)). "\n";
|
|
if ($string !~ /{/)
|
|
{
|
|
$string = ' ' . $string;
|
|
}
|
|
$string =~ s/ +\n/\n/gms;
|
|
#$string =~ s/^(.)/$indent$1/gm;
|
|
|
|
# unindent preprocessor directives
|
|
$string =~ s/^$indent#/#/gms;
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
%Hungarian =
|
|
(
|
|
# We default to empty.
|
|
"BOOL" => "f",
|
|
|
|
"int" => "n",
|
|
"short" => "n",
|
|
"long" => "n",
|
|
"INT" => "n",
|
|
"SHORT" => "n",
|
|
"LONG" => "n",
|
|
"UINT" => "n",
|
|
"USHORT" => "n",
|
|
"ULONG" => "n",
|
|
"WORD" => "n",
|
|
"DWORD" => "n",
|
|
"INT_PTR" => "n",
|
|
"LONG_PTR" => "n",
|
|
"UINT_PTR" => "n",
|
|
"ULONG_PTR" => "n",
|
|
"DWORD_PTR" => "n",
|
|
|
|
"HWND" => "window",
|
|
"HRESULT" => "",
|
|
"COLORREF" => "color",
|
|
"HICON" => "icon",
|
|
"PVOID" => "v",
|
|
"HMODULE" => "module",
|
|
"HINSTANCE" => "instance",
|
|
"HBITMAP" => "bitmap",
|
|
"LANGID" => "languageId",
|
|
"HIMAGELIST" => "imagelist",
|
|
);
|
|
|
|
$headerName = MakeLower($ARGV[0]);
|
|
#DebugPrint("ARGV is " . join(" ", @ARGV) . "\n");
|
|
#DebugExit();
|
|
@ARGV = reverse(@ARGV);
|
|
pop(ARGV);
|
|
@ARGV = reverse(@ARGV);
|
|
#DebugPrint("ARGV is " . join(" ", @ARGV) . "\n");
|
|
|
|
#
|
|
# The command line should say 'SetStubsFile('foo.sxs-stubs');'
|
|
#
|
|
eval(join("\n", @ARGV));
|
|
|
|
if ($headerName =~ /\\/)
|
|
{
|
|
($headerLeafName) = ($headerName =~ /.+\\(.+)/);
|
|
$headerFullPath = $headerName;
|
|
}
|
|
else
|
|
{
|
|
$headerLeafName = $headerName;
|
|
$headerFullPath = GetNtDrive() . GetNtRoot() . "\\public\\sdk\\inc\\" . $headerName;
|
|
}
|
|
#DebugPrint($headerFullPath);
|
|
open(headerFileHandle, "< " . $headerFullPath) || die;
|
|
|
|
#
|
|
# extract out the executable code
|
|
# /* #!perl */
|
|
#
|
|
|
|
# $code .= "/* " . $headerFullPath . " */\n\n";
|
|
|
|
# read all the lines into one string
|
|
$file = join("", <headerFileHandle>);
|
|
|
|
# if it doesn't contain any embedded Perl, then we are a no-op, just spit it out
|
|
# This way we can run over all files, makes it easier to edit shell\published\makefile.inc.
|
|
if ($file !~ /#!perl/ms)
|
|
{
|
|
print($file);
|
|
EarlySuccessExit();
|
|
}
|
|
|
|
#
|
|
# Change WINOLEAPI_(type) to just type.
|
|
# This lets objbase.h/ole2.h work.
|
|
#
|
|
@types = qw(void HINSTANCE BOOL int LPVOID DWORD ULONG HOLEMENU HANDLE HGLOBAL);
|
|
foreach $type (@types)
|
|
{
|
|
$file =~ s/\bWINOLEAPI_\($type\) +/$type\n/g;
|
|
};
|
|
$file =~ s/\bWINOLEAPI\b/HRESULT\n/g;
|
|
|
|
#
|
|
# Remove stuff that doesn't mean much.
|
|
#
|
|
$file =~ s/\bWINAPIV\b/ /g;
|
|
$file =~ s/\bWINAPI\b/ /g;
|
|
$file =~ s/\b__stdcall\b/ /g;
|
|
$file =~ s/\b_stdcall\b/ /g;
|
|
$file =~ s/\b__cdecl\b/ /g;
|
|
$file =~ s/\b_cdecl\b/ /g;
|
|
$file =~ s/\b__fastcall\b //g;
|
|
$file =~ s/\b_fastcall\b/ /g;
|
|
$file =~ s/\bCALLBACK\b/ /g;
|
|
$file =~ s/\bPASCAL\b/ /g;
|
|
$file =~ s/\bAPIENTRY\b/ /g;
|
|
$file =~ s/\bFAR\b/ /g;
|
|
$file =~ s/\bNEAR\b/ /g;
|
|
$file =~ s/\bvolatile\b/ /g;
|
|
$file =~ s/\bIN\b/ /g;
|
|
$file =~ s/\bOUT\b/ /g;
|
|
$file =~ s/\bDECLSPEC_NORETURN\b/ /g;
|
|
$file =~ s/\bOPTIONAL\b/ /g;
|
|
|
|
# honor backslash line continuations, before removing preprocessor directives
|
|
$file =~ s/\\\n//gms;
|
|
|
|
# execute perl code embedded in comments
|
|
# quadratic behavior where we keep searching for the string, remove, search, remove..
|
|
# without remembering where the previous find was
|
|
while ($file =~ s/\/\* ?#!perl(.*?)\*\///ms)
|
|
{
|
|
$_ = $1;
|
|
|
|
# C++ comments in the Perl comment are removed
|
|
s/\/\/.*?$//gms; # support C++ comments within the #!perl C comment.
|
|
|
|
# something resembling C comment close is restored
|
|
# escape-o-rama..
|
|
s/\* \//\*\//gms;
|
|
|
|
eval;
|
|
#DebugPrint;
|
|
}
|
|
|
|
#DebugPrint($file);
|
|
#DebugExit();
|
|
|
|
# remove comments, before removing preprocessor directives
|
|
$file =~ s/\/\*.*?\*\//\n/gms;
|
|
$file =~ s/\/\/.*?$//gms;
|
|
|
|
#DebugPrint($file);
|
|
#DebugExit();
|
|
|
|
# remove preprocessor directives
|
|
# must do this before we make one statement per line in pursuit
|
|
# of an easy typedef/struct removal
|
|
$file =~ s/^[ \t]*#.*$//gm;
|
|
|
|
# remove FORCEINLINE functions, assuming they don't contain any braces..
|
|
$file =~ s/FORCEINLINE.+?}//gms;
|
|
|
|
# remove extern C open and close
|
|
# must do this before we make one statement per line in pursuit
|
|
# of an easy typedef/struct removal
|
|
$file =~ s/\bextern\b \"C\" {$//gm;
|
|
$file =~ s/^}$//gm;
|
|
|
|
#
|
|
# cleanup commdlg.h
|
|
#
|
|
# remove Afx blah
|
|
$file =~ s/^.*Afx.*$//gm;
|
|
# remove IID blah
|
|
$file =~ s/^.*DEFINE_GUID.*$//gm;
|
|
# remove IPrintDialogCallback
|
|
$file =~ s/DECLARE_INTERFACE_.+?};//gs;
|
|
|
|
#
|
|
# cleanup ole2.h
|
|
#
|
|
$file =~ s/typedef struct _OLESTREAMVTBL.+}.+?;.+?;//gs;
|
|
|
|
#
|
|
# futz with whitespace (has to do with having removed comments from within structs)
|
|
# we do this more later
|
|
#
|
|
$file =~ s/[ \t\n]+/ /g;
|
|
|
|
# remove typedefs and structs, this is extremely sloppy and fragile
|
|
# .. we fold statements to be single lines, and then only keep statements that have parens,
|
|
# and then remove single line typedefs and structs as well
|
|
# .. avoiding counting braces ..
|
|
$file =~ s/\n/ /gms; # remove all newlines
|
|
$file =~ s/;/;\n/gms; # each statement on its own line (also struct fields on their own line)
|
|
$file =~ s/^[^()]+$//gm; # only keep statements with parens
|
|
|
|
#
|
|
# types with parens that don't have typedefs will defeat the above, for example:
|
|
# struct foo {
|
|
# void (*bar)(void);
|
|
# };
|
|
#
|
|
# Still, just by requiring a leading "WIN" on function declarations, we can live with structs and
|
|
# typedefs in the file.
|
|
#
|
|
|
|
$file =~ s/^ +//gm; # remove spaces at start of line
|
|
$file =~ s/^typedef\b.+;$//gm; # remove typedefs (they're probably already gone)
|
|
$file =~ s/^struct\b.+;$//gm; # remove structs (they're probably already gone)
|
|
|
|
$file =~ s/\n+/\n/g; # remove empty lines
|
|
|
|
#DebugPrint $file;
|
|
|
|
$file =~ s/^.+\.\.\..+$//gm; # remove vararg functions
|
|
|
|
# format as one function declaration per line, no empty lines (some of this is redundant
|
|
# given how we now remove typedefs and structs)
|
|
$file =~ s/[ \t\n]+/ /g;
|
|
$file =~ s/;/;\n/g;
|
|
$file =~ s/^.+?\bWinMain\b.+?$//gm; # WinMain looks wierd due to #ifdef _MAC. Remove it.
|
|
$file =~ s/\n+/\n/g; # remove empty lines (again)
|
|
$file =~ s/^ +//gm; # remove spaces at line starts (again)
|
|
$file =~ s/\A\n+//g; # remove newline from very start of file
|
|
|
|
# more simplications, more whitespace, fewer other characters
|
|
$file =~ s/\);$//gm; # get rid of trailing semi and rparen
|
|
#$file =~ s/\(/ \(/g; # make sure whitespace precedes lparens, to set them off from function name
|
|
$file =~ s/\*/ \* /g; # make sure stars are whitespace delimited
|
|
$file =~ s/\( +/\(/g; # remove whitespace after lparen
|
|
|
|
$file =~ s/\bWINBASEAPI\b/ /g;
|
|
$file =~ s/\bWINADVAPI\b/ /g;
|
|
$file =~ s/\bWINUSERAPI\b/ /g;
|
|
$file =~ s/\bWINCOMMCTRLAPI\b/ /g;
|
|
$file =~ s/\bWINGDIAPI\b/ /g;
|
|
$file =~ s/\bWINCOMMDLGAPI\b/ /g;
|
|
$file =~ s/\bWIN[A-Z]+API\b/ /g;
|
|
$file =~ s/^ +//gm; # remove whitespace at start of lines
|
|
|
|
# normalize what empty parameter lists look like between (VOID) and (void)
|
|
# leave PVOID and LPVOID alone (\b for word break)
|
|
# lowercase others while we're at it
|
|
$file =~ s/\b(VOID|CONST|INT|LONG|SHORT)\b/\L$1\E/g;
|
|
$file =~ s/\($/\(void/gm; # change the occasional C++ form (this is broken if compiling for C) to the C form
|
|
|
|
# yet more whitespace cleanup
|
|
#$file =~ s/ *(,|\*) */$1/g; # remove whitespace around commas and stars
|
|
$file =~ s/ *, */,/g; # remove whitespace around commas
|
|
$file =~ s/^ +//gm; # remove spaces at start of line
|
|
$file =~ s/ +$//gm; # remove spaces at end of line
|
|
$file =~ s/ +/ /g; # runs of spaces to single spaces
|
|
|
|
if (0)
|
|
{
|
|
DebugPrint $file;
|
|
DebugExit();
|
|
}
|
|
|
|
foreach $line (split("\n", $file))
|
|
{
|
|
@argsTypes = ();
|
|
$unnamed_counter = 1;
|
|
|
|
# split off return type and name at first lparen
|
|
#($retname, $args) = ($line =~ /WIN[A-Z]+ ([^(]+)\((.+)/);
|
|
($retname, $args) = ($line =~ /([^(]+)\((.+)/);
|
|
|
|
# split off name as last space delimited from return type and name,
|
|
# allowing return type to be multiple tokens
|
|
($ret, $name) = ($retname =~ /(.*) ([^ ]+)/);
|
|
|
|
$args =~ s/^ +//g; # cleanup whitespace (again)
|
|
$args =~ s/ +$//g; # cleanup whitespace (again!)
|
|
$args =~ s/ +/ /g; # cleanup whitespace (again!!)
|
|
|
|
#
|
|
# now split up args, split their name from their type, and provide names for unnamed ones
|
|
# and note if they are void
|
|
# the key is to generate the two strings, argNamesAndTypes and argNames
|
|
#
|
|
# unnamed parameters are parameters that either
|
|
# have only one token
|
|
# or whose last token is a star
|
|
# we don't handle C++ references or "untypedefed structs passed by value" like "void F(struct G);"
|
|
# or inline defined structs "void F(struct G { int i; });"
|
|
#
|
|
$argNames = "";
|
|
if ($args !~ /^void$/)
|
|
{
|
|
#
|
|
# args2 is args with unnamed parameters inserted as needed.
|
|
# args is replaced by args2 when we finish building args2.
|
|
#
|
|
$args2 = "";
|
|
foreach $arg (split(/,/, $args))
|
|
{
|
|
#
|
|
# If a parameter contains just one word, it is unnamed.
|
|
# The word is the type and there is no name.
|
|
#
|
|
if ($arg =~ /^ *\w+ *$/)
|
|
{
|
|
$argName = "unnamed" . $unnamed_counter++;
|
|
$argType = $arg; # The whole arg is the type since there's no name.
|
|
}
|
|
#
|
|
# If a parameter ends with a star, it is unnamed.
|
|
#
|
|
elsif ($arg =~ /\* *$/)
|
|
{
|
|
$argName = "unnamed" . $unnamed_counter++;
|
|
$argType = $arg; # The whole arg is the type since there's no name.
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# The last word is the name, whatever precedes it is the type.
|
|
# This does not work with arrays and pointers to functions, unless
|
|
# typedefs are used.
|
|
#
|
|
($argType, $argName) = ($arg =~ /(.+?)(\w+)$/);
|
|
}
|
|
$argType = RemoveSpacesAroundStars($argType);
|
|
$argType = RemoveSpacesAroundCommas($argType);
|
|
$argType = RemoveTrailingComma($argType);
|
|
$argType = RemoveLeadingAndTrailingSpaces($argType);
|
|
|
|
$comType = $ComInterfaceParameterType{$argType};
|
|
#DebugPrint($name . ' ' . $argType . " -> " . $comType . "\n");
|
|
if ($comType)
|
|
{
|
|
$comData{$comType}{$argType} = 1;
|
|
$argType = ComInterfaceParameterReplacementIdentifier($argType);
|
|
}
|
|
$argNames .= $argName . ',';
|
|
$args2 .= $argType . ' ' . $argName . ',';
|
|
push(@argsTypes, ($argType));
|
|
}
|
|
$args = $args2;
|
|
}
|
|
$dll = $MapHeaderToDll{RemoveExtension($headerLeafName)};
|
|
|
|
if ( ($DelayLoad{$dll}
|
|
|| $DelayLoad{$name}
|
|
|| ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
|
|
|| $ActivateAroundFunctionCall{$name}
|
|
|| $ActivateNULLAroundFunctionCall{$name})
|
|
&& !$IgnoreFunction{$name}
|
|
)
|
|
{
|
|
$args = RemoveSpacesAroundStars($args);
|
|
$argNames = RemoveSpacesAroundStars($argNames);
|
|
$args = RemoveSpacesAroundCommas($args);
|
|
$argNames = RemoveSpacesAroundCommas($argNames);
|
|
$args = RemoveTrailingComma($args);
|
|
$argNames = RemoveTrailingComma($argNames);
|
|
$args = RemoveLeadingAndTrailingSpaces($args);
|
|
$argNames = RemoveLeadingAndTrailingSpaces($argNames);
|
|
|
|
$function = Function->new();
|
|
$function->ret($ret);
|
|
$function->name($name);
|
|
$function->argsTypesNames("(". $args . ")");
|
|
$function->argsNames("(". $argNames . ")");
|
|
|
|
$error = MakeStringTrue($FunctionErrorValue{$name});
|
|
if (!$error)
|
|
{
|
|
$error = MakeStringTrue($TypeErrorValue{$ret});
|
|
}
|
|
#DebugPrint("error for $ret:$name is $error\n");
|
|
if (!$error && $ret ne "void" && $ret ne "HRESULT" && !$NeverFails{$name})
|
|
{
|
|
ErrorPrint($ErrorMessagePrefix . "don't know know error value for $dll:$name:$ret:$args\n");
|
|
ErrorPrint($ErrorMessagePrefix . "line is '" . $line . "'\n");
|
|
ErrorExit();
|
|
#$error = "((" . $ret . ")0)";
|
|
}
|
|
$function->error($error);
|
|
|
|
$retname = $Hungarian{$ret};
|
|
if (!$retname)
|
|
{
|
|
$retname = "result";
|
|
}
|
|
else
|
|
{
|
|
$retname .= "Result";
|
|
}
|
|
$function->retname($retname);
|
|
|
|
$function->dll($dll);
|
|
$function->header(RemoveExtension(MakeLower($headerLeafName)) . ".h");
|
|
|
|
if ($DelayLoad{$dll} || $DelayLoad{$name})
|
|
{
|
|
$function->delayload($true);
|
|
}
|
|
push(@functions, ($function));
|
|
#DebugPrint("pushed " . $name . "\n");
|
|
}
|
|
else
|
|
{
|
|
#DebugPrint("didn't push " . $name . "(" . $dll . ")\n");
|
|
}
|
|
}
|
|
|
|
sub InsertCodeIntoFile
|
|
{
|
|
my($code, $filePath) = ($_[0], $_[1]);
|
|
my($fileContents, $fileHandle);
|
|
my($stubsFileHandle);
|
|
my($yearnow);
|
|
my($insertionPoint);
|
|
my($generateInclude);
|
|
|
|
#DebugPrint("/* InsertCodeIntoFile */");
|
|
|
|
$fileHandle = new IO::File($filePath, "r");
|
|
$fileContents = join("", $fileHandle->getlines());
|
|
|
|
#
|
|
# We have decided to sometimes use an #include in order to not be so large.
|
|
#
|
|
|
|
# Remove the executable perl code.
|
|
$fileContents =~ s/\/\* ?#!perl.*?\*\/\n+/\n/msg;
|
|
$fileContents =~ s/\/\* ?#!perl.*?\*\///msg;
|
|
|
|
$insertionPoint = $InsertionPoint{MakeLower(BaseName($filePath))};
|
|
#DebugPrint("LeafPath is " . LeafPath($filePath));
|
|
#DebugPrint("filePath is $filePath");
|
|
#DebugPrint("insertionPoint is $insertionPoint");
|
|
|
|
if ($insertionPoint || $StubsFile)
|
|
{
|
|
$code =
|
|
"#if defined(__cplusplus)\n"
|
|
. "extern \"C\" {\n"
|
|
. "#endif\n\n"
|
|
. $code
|
|
. "\n#if defined(__cplusplus)\n"
|
|
. "} /* __cplusplus */\n"
|
|
. "#endif\n"
|
|
;
|
|
}
|
|
|
|
if ($StubsFile)
|
|
{
|
|
#DebugPrint("StubsFile is $StubsFile\n");
|
|
$stubsFileHandle = new IO::File($StubsFile, "w");
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
|
|
my ($firstyear) = 2001;
|
|
$year += 1900;
|
|
if ($year == $firstyear)
|
|
{
|
|
$stubsFileHandle->print("/* Copyright (c) " . $firstyear . " Microsoft Corp. All rights reserved. */\n");
|
|
}
|
|
else
|
|
{
|
|
$stubsFileHandle->print("/* Copyright (c) " . $firstyear . "-" . $year .", Microsoft Corp. All rights reserved. */\n");
|
|
}
|
|
#$stubsFileHandle->print("/* This file generated " . localtime() . " */\n");
|
|
$stubsFileHandle->print("\n");
|
|
|
|
$stubsFileHandle->print("#if _MSC_VER > 1000\n");
|
|
$stubsFileHandle->print("#pragma once\n");
|
|
$stubsFileHandle->print("#endif\n");
|
|
$stubsFileHandle->print("\n");
|
|
|
|
$stubsFileHandle->print($code);
|
|
|
|
$generateInclude = 1;
|
|
}
|
|
if ($generateInclude)
|
|
{
|
|
# generate the include, within #if
|
|
$code = "";
|
|
$code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
|
|
$code .= "#if defined($ENABLED) && ($ENABLED != 0)\n";
|
|
$code .= "#include \"" . LeafPath($StubsFile) . "\"\n";
|
|
$code .= "#endif /* $ENABLED */\n";
|
|
$code .= "#endif /* RC */";
|
|
}
|
|
|
|
if ($insertionPoint)
|
|
{
|
|
#DebugPrint("/* abc */");
|
|
$fileContents =~ s/$insertionPoint/\n$code\n/ms;
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# put the #include or the code into the the file
|
|
#
|
|
# The #include or the code goes before the last
|
|
# occurence of #ifdef __cplusplus or #if defined(__cplusplus).
|
|
#
|
|
$fileContents =~ s/(.+)(#if[defined( \t]+__cplusplus.*?$})/$1\n\n$code\n\n$2/ms;
|
|
}
|
|
return $fileContents;
|
|
};
|
|
|
|
sub GenerateHeaderCommon1
|
|
{
|
|
my($function) = ($_[0]);
|
|
my($x, $dll, $dllid, $header);
|
|
|
|
#DebugPrint("2\n");
|
|
$dll = MakeLower($function->dll());
|
|
$dllid = MakeTitlecase(ToIdentifier($dll));
|
|
$header = MakeLower(BaseName($function->header())) . ".h";
|
|
|
|
$x .= '
|
|
|
|
#if !defined(ISOLATION_AWARE_USE_STATIC_LIBRARY)
|
|
#define ISOLATION_AWARE_USE_STATIC_LIBRARY 0
|
|
#endif
|
|
|
|
#if !defined(ISOLATION_AWARE_BUILD_STATIC_LIBRARY)
|
|
#define ISOLATION_AWARE_BUILD_STATIC_LIBRARY 0
|
|
#endif
|
|
|
|
#if !defined(' . $INLINE . ')
|
|
#if ISOLATION_AWARE_BUILD_STATIC_LIBRARY
|
|
#define ' . $INLINE . ' /* nothing */
|
|
#else
|
|
#if defined(__cplusplus)
|
|
#define ' . $INLINE . ' inline
|
|
#else
|
|
#define ' . $INLINE . ' __inline
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
';
|
|
|
|
$x .= "#if !ISOLATION_AWARE_USE_STATIC_LIBRARY\n";
|
|
|
|
$x .= $MapHeaderToSpecialCode1{$header};
|
|
|
|
$x .= "FARPROC WINAPI ";
|
|
$x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
|
|
$x .= "(LPCSTR pszProcName);\n\n";
|
|
|
|
$x .= $SpecialChunksOfCode{$header};
|
|
|
|
$x .= "#endif /* ISOLATION_AWARE_USE_STATIC_LIBRARY */\n";
|
|
|
|
return $x;
|
|
}
|
|
|
|
sub GenerateHeaderCommon2
|
|
{
|
|
my($function) = ($_[0]);
|
|
my($x);
|
|
my($dll);
|
|
my($LoadLibrary);
|
|
my($indent);
|
|
my($dllid);
|
|
my($activate);
|
|
my($header);
|
|
my($exit);
|
|
my($exit_ret);
|
|
my($exit_leave);
|
|
|
|
$LoadLibA = $MyLoadLibraryA; # or GetModuleHandle
|
|
$LoadLibW = $MyLoadLibraryW; # or GetModuleHandle
|
|
$dll = MakeLower($function->dll());
|
|
$dllid = ToIdentifier(MakeTitlecase($dll));
|
|
$indent = "";
|
|
$activate = $ActivateAroundDelayLoad{$dll};
|
|
$header = MakeLower(LeafPath($function->header()));
|
|
|
|
#DebugPrint("header is " . $header . "\n");
|
|
|
|
$x .= $MapHeaderToSpecialCode2{$header};
|
|
|
|
$x .= $INLINE . " FARPROC WINAPI ";
|
|
$x .= MakeHeaderPrivateName($header, "GetProcAddress_$dllid");
|
|
$x .= "(LPCSTR pszProcName)\n";
|
|
$x .= "/* This function is shared by the other stubs in this header. */\n";
|
|
$x .= "{\n";
|
|
$indent = Indent($indent);
|
|
if ($activate)
|
|
{
|
|
$x .= $indent . "FARPROC proc = NULL;\n";
|
|
}
|
|
$x .= $indent . "static HMODULE s_module;\n";
|
|
|
|
$exit_ret = "return proc;\n";
|
|
$exit_leave = "__leave;\n";
|
|
$exit = $exit_ret;
|
|
|
|
if ($activate)
|
|
{
|
|
$x .= $indent . "BOOL fActivateActCtxSuccess = FALSE;\n";
|
|
$x .= $indent . "ULONG_PTR ulpCookie = 0;\n";
|
|
}
|
|
$Dll = MakeTitlecase($function->dll());
|
|
if ($Dll eq "Kernel32.dll")
|
|
{
|
|
$x .= $indent . "/* Use GetModuleHandle instead of LoadLibrary on kernel32.dll because */\n";
|
|
$x .= $indent . "/* we already necessarily have a reference on kernel32.dll. */\n";
|
|
$LoadLibA = $MyGetModuleHandleA;
|
|
$LoadLibW = $MyGetModuleHandleW;
|
|
}
|
|
else
|
|
{
|
|
$LoadLibrary = "LoadLibrary";
|
|
}
|
|
$x .= $indent . "const static $CONSTANT_MODULE_INFO\n";
|
|
$x .= $indent . " c = { $LoadLibA, $LoadLibW, \"$Dll\", L\"$Dll\" };\n";
|
|
$x .= $indent . "static $MUTABLE_MODULE_INFO m;\n\n";
|
|
|
|
if ($activate)
|
|
{
|
|
$x .= $indent . "__try\n";
|
|
$x .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$exit = $exit_leave;
|
|
|
|
$x .= $indent . "if (!" . $g_fDownlevel . ")\n";
|
|
$x .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$x .= $indent . "fActivateActCtxSuccess = ";
|
|
$x .= $ActivateMyActCtx;
|
|
$x .= "(&ulpCookie);\n";
|
|
$x .= $indent . "if (!fActivateActCtxSuccess)\n";
|
|
$x .= IndentMultiLineString($indent, $exit);
|
|
$indent = Outdent($indent);
|
|
$x .= $indent . "}\n";
|
|
|
|
$x .= $indent . "proc = $MyGetProcAddress(&c, &m, pszProcName);\n";
|
|
|
|
$indent = Outdent($indent);
|
|
$x .= $indent . "}\n";
|
|
$x .= $indent . "__finally\n";
|
|
$x .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$x .= $indent . "if (!" . $g_fDownlevel . " && fActivateActCtxSuccess)\n";
|
|
$x .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
|
|
$x .= $indent . "const DWORD dwLastError = (proc == NULL) ? GetLastError() : NO_ERROR;\n";
|
|
$x .= $indent . "(void)" . $DeactivateActCtx . "(0, ulpCookie);\n";
|
|
$x .= $indent . "if (proc == NULL)\n";
|
|
$x .= $indent . " SetLastError(dwLastError);\n";
|
|
|
|
$indent = Outdent($indent);
|
|
$x .= $indent . "}\n";
|
|
$indent = Outdent($indent);
|
|
$x .= $indent . "}\n";
|
|
|
|
$x .= $indent . "return proc;\n";
|
|
}
|
|
else
|
|
{
|
|
$x .= $indent . "return $MyGetProcAddress(&c, &m, pszProcName);\n";
|
|
}
|
|
$x .= "}\n\n";
|
|
|
|
return $x;
|
|
}
|
|
|
|
sub GeneratePrototype
|
|
{
|
|
my($function) = ($_[0]);
|
|
my($proto);
|
|
|
|
$proto .= $function->ret() . " WINAPI ";
|
|
$proto .= MakePublicName($function->name());
|
|
$proto .= $function->argsTypesNames() . ";\n";
|
|
|
|
return $proto;
|
|
}
|
|
|
|
sub DelayLoadOrActivateAroundFunction
|
|
{
|
|
my($function) = ($_[0]);
|
|
my($dll);
|
|
my($name);
|
|
my($activate);
|
|
my($delayload);
|
|
|
|
$dll = $function->dll();
|
|
$name = $function->name();
|
|
|
|
$activate = $ActivateAroundFunctionCall{$name} || ($ActivateAroundFunctionCall{$dll} && !$NoActivateAroundFunctionCall{$name})
|
|
|| $ActivateNULLAroundFunctionCall{$name};
|
|
$delayload = $DelayLoad{$name} || $DelayLoad{$dll};
|
|
|
|
return ($activate || $delayload);
|
|
}
|
|
|
|
sub DoesHeaderNeedWin32ToHresult
|
|
{
|
|
my($function);
|
|
|
|
foreach $function (@functions)
|
|
{
|
|
if ($function->ret() eq "HRESULT" && DelayLoadOrActivateAroundFunction($function))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub GenerateStub
|
|
{
|
|
my($function) = ($_[0]);
|
|
my($activate);
|
|
my($delayload);
|
|
my($stub);
|
|
my($indent);
|
|
my($name);
|
|
my($dll);
|
|
my($ret);
|
|
my($retname);
|
|
my($exit);
|
|
my($exit_ret);
|
|
my($exit_leave);
|
|
|
|
$name = $function->name();
|
|
$dll = $function->dll();
|
|
$dllid = MakeTitlecase(ToIdentifier($dll));
|
|
$ret = $function->ret();
|
|
$retname = $function->retname();
|
|
|
|
$indent = "";
|
|
$stub = "";
|
|
|
|
$activate = $ActivateAroundFunctionCall{$name} || $ActivateAroundFunctionCall{$dll}
|
|
|| $ActivateNULLAroundFunctionCall{$name};
|
|
$delayload = $DelayLoad{$name} || $DelayLoad{$dll};
|
|
|
|
if ($function->ret() eq "HRESULT")
|
|
{
|
|
$exit_ret = "return $Win32ToHresult();\n";
|
|
$exit_leave = "{\n $retname = $Win32ToHresult();\n __leave;\n}";
|
|
}
|
|
elsif ($ret eq "void")
|
|
{
|
|
$exit_ret = "return;\n";
|
|
$exit_leave = "__leave;\n";
|
|
}
|
|
else
|
|
{
|
|
$exit_ret = "return " . $function->retname() . ";\n";
|
|
$exit_leave = "__leave;\n";
|
|
}
|
|
$exit = $exit_ret;
|
|
|
|
# "prototype"
|
|
$stub .= $INLINE . " " . $ret . " WINAPI ";
|
|
$stub .= MakePublicName($function->name());
|
|
$stub .= $function->argsTypesNames() . "\n";
|
|
$stub .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
|
|
# locals
|
|
if ($ret ne "void")
|
|
{
|
|
$stub .= $indent . $ret . " " . $function->retname() . " = " . $function->error() . ";\n";
|
|
}
|
|
if ($delayload)
|
|
{
|
|
$stub .= $indent . "typedef " . $ret . " (WINAPI* PFN)" . $function->argsTypesNames() . ";\n";
|
|
$stub .= $indent . "static PFN s_pfn;\n";
|
|
}
|
|
|
|
$stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"locals"});
|
|
|
|
if ($activate)
|
|
{
|
|
$stub .= $indent . "ULONG_PTR ulpCookie = 0;\n";
|
|
$stub .= $indent . "const BOOL fActivateActCtxSuccess = " . $g_fDownlevel . " || ";
|
|
}
|
|
|
|
# code (partly merged with local sometimes ("initialization" in the strict C++ terminology sense)
|
|
if ($activate)
|
|
{
|
|
if ($ActivateNULLAroundFunctionCall{$function->name()})
|
|
{
|
|
$stub .= $ActivateActCtx;
|
|
$stub .= "(NULL, &ulpCookie);\n";
|
|
}
|
|
else
|
|
{
|
|
$stub .= $ActivateMyActCtx;
|
|
$stub .= "(&ulpCookie);\n";
|
|
}
|
|
$stub .= $indent . "if (!fActivateActCtxSuccess)\n";
|
|
$stub .= IndentMultiLineString($indent, $exit);
|
|
$stub .= $indent . "__try\n";
|
|
$stub .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$exit = $exit_leave;
|
|
}
|
|
if ($delayload)
|
|
{
|
|
$stub .= $indent . "if (s_pfn == NULL)\n";
|
|
$stub .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$stub .= $indent . "s_pfn = (PFN)";
|
|
$stub .= MakeHeaderPrivateName($function->header(), "GetProcAddress_$dllid");
|
|
$stub .= "(";
|
|
#
|
|
# Some functions are exported with different names
|
|
# on Win64 vs. Win32.
|
|
#
|
|
if ($ExportName32{$name} || $ExportName64{$name})
|
|
{
|
|
if (!$ExportName32{$name})
|
|
{
|
|
$ExportName32{$name} = $name;
|
|
}
|
|
if (!$ExportName64{$name})
|
|
{
|
|
$ExportName64{$name} = $name;
|
|
}
|
|
$stub .= "\n#if defined(_WIN64)\n";
|
|
$stub .= $indent . "\"" . $ExportName64{$name} . "\"\n";
|
|
$stub .= "#else\n";
|
|
$stub .= $indent . "\"" . $ExportName32{$name} . "\"\n";
|
|
$stub .= "#endif\n";
|
|
$stub .= $indent;
|
|
}
|
|
else
|
|
{
|
|
$stub .= "\"" . $name . "\"";
|
|
}
|
|
$stub .= ");\n";
|
|
$stub .= $indent . "if (s_pfn == NULL)\n";
|
|
$stub .= IndentMultiLineString($indent, $exit);
|
|
$indent = Outdent($indent);
|
|
$stub .= $indent . "}\n";
|
|
}
|
|
|
|
if ($SpecialChunksOfCode{$function->name()}{"body"})
|
|
{
|
|
$stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"body"});
|
|
}
|
|
else
|
|
{
|
|
$stub .= $indent;
|
|
if ($ret ne "void")
|
|
{
|
|
$stub .= $function->retname() . " = ";
|
|
}
|
|
if ($delayload)
|
|
{
|
|
$stub .= "s_pfn";
|
|
}
|
|
else
|
|
{
|
|
$stub .= $function->name();
|
|
}
|
|
$stub .= $function->argsNames();
|
|
$stub .= ";\n";
|
|
}
|
|
if ($activate)
|
|
{
|
|
#
|
|
# We cannot propagate the error from DeactivateActCtx.
|
|
# 1) DeactivateActCtx only fails with INVALID_PARAMETER.
|
|
# 2) How to generally cleanup the result, like of CreateWindow?
|
|
#
|
|
$indent = Outdent($indent);
|
|
$stub .= $indent . "}\n";
|
|
$stub .= $indent . "__finally\n";
|
|
$stub .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$stub .= $indent . "if (!" . $g_fDownlevel . ")\n";
|
|
$stub .= $indent . "{\n";
|
|
$indent = Indent($indent);
|
|
$maybePreserveError = 0;
|
|
if ($ret ne "void" && $ret ne "HRESULT")
|
|
{
|
|
$maybePreserveError = 1;
|
|
$stub .= $indent . "const BOOL fPreserveLastError = (" . $retname . " == " . $function->error() . ");\n";
|
|
$stub .= $indent . "const DWORD dwLastError = fPreserveLastError ? GetLastError() : NO_ERROR;\n";
|
|
}
|
|
else
|
|
{
|
|
# nothing;
|
|
}
|
|
$stub .= $indent . "(void)" . $DeactivateActCtx . "(0, ulpCookie);\n";
|
|
|
|
$stub .= IndentMultiLineString($indent, $SpecialChunksOfCode{$function->name()}{"cleanup"});
|
|
if ($maybePreserveError)
|
|
{
|
|
$stub .= $indent . "if (fPreserveLastError)\n";
|
|
$stub .= $indent . " SetLastError(dwLastError);\n";
|
|
}
|
|
$indent = Outdent($indent);
|
|
$stub .= $indent . "}\n";
|
|
$indent = Outdent($indent);
|
|
$stub .= $indent . "}\n";
|
|
}
|
|
if ($activate)
|
|
{
|
|
#$stub .= "Exit:\n";
|
|
}
|
|
if ($ret ne "void")
|
|
{
|
|
$stub .= $indent . "return " . $function->retname() . ";\n";
|
|
}
|
|
else
|
|
{
|
|
$stub .= $indent . "return;\n";
|
|
}
|
|
$indent = Outdent($indent);
|
|
$stub .= $indent . "}\n\n";
|
|
|
|
return $stub;
|
|
};
|
|
|
|
foreach $function (@functions)
|
|
{
|
|
if (0)
|
|
{
|
|
DebugPrint(
|
|
"ret:" . $function->ret()
|
|
. " name:" . $function->name()
|
|
. " argsTypesNames:" . $function->argsTypesNames()
|
|
. " argsNames:" . $function->argsNames()
|
|
. "\n"
|
|
);
|
|
}
|
|
}
|
|
|
|
$code .= "\n";
|
|
$code .= "#if !defined(RC_INVOKED) /* RC complains about long symbols in #ifs */\n";
|
|
$code .= "#if defined($ENABLED) && ($ENABLED != 0)\n";
|
|
|
|
$code .= GenerateHeaderCommon1($functions[0]);
|
|
|
|
sub AppendNewlineIfNotEmpty
|
|
{
|
|
return $_[0] ? $_[0] . "\n" : $_[0];
|
|
}
|
|
|
|
sub GeneratePoundIf
|
|
{
|
|
#
|
|
# note: nesting does not work
|
|
#
|
|
#DebugPrint "GeneratePoundIf\n";
|
|
|
|
my($function) = ($_[0]);
|
|
my($name) = $function->name();
|
|
my($condition) = $PoundIfCondition{$name};
|
|
my($state) = $PoundIfState{$condition};
|
|
my($code) = "";
|
|
|
|
if ($condition)
|
|
{
|
|
#$code .= "/* GeneratePoundIf:function=$name;condition=$condition;state=$state */\n";
|
|
}
|
|
|
|
if ($condition)
|
|
{
|
|
if (!$state)
|
|
{
|
|
$code .= GeneratePoundEndif();
|
|
$PoundIfState{$condition} = 1;
|
|
$code .= "#if $condition\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$code .= GeneratePoundEndif();
|
|
}
|
|
return $code;
|
|
}
|
|
|
|
sub GeneratePoundEndif
|
|
{
|
|
#
|
|
# note: nesting does not work
|
|
#
|
|
my ($code) = "";
|
|
my($condition);
|
|
|
|
foreach $condition (keys(%PoundIfState))
|
|
{
|
|
$code .= "#endif /* $condition */\n";
|
|
}
|
|
undef %PoundIfState; # empty it
|
|
return $code;
|
|
}
|
|
|
|
sub ComInterfaceType_IfdefSymbol
|
|
{
|
|
my($x) = ($_[0]);
|
|
|
|
#
|
|
# produced by Midl
|
|
#
|
|
return '__' . $x . '_INTERFACE_DEFINED__';
|
|
}
|
|
|
|
#
|
|
# comData is a two level hash table.
|
|
# the first key is the COM interface, like IStream
|
|
# the second key is the actual parameter type, like LPSTREAM
|
|
# the value is just 1, the second level hash table is for automatic uniquing.
|
|
#
|
|
# Multiple parameter types may map to the same COM interface, like for a bogus example:
|
|
#
|
|
# typedef IStream *LPSTREAM;
|
|
# typedef IStream *LPSTREAM2;
|
|
#
|
|
# Foo(LPSTREAM);
|
|
# Foo2(LPSTREAM2);
|
|
#
|
|
# The generated code is generalized to support that.
|
|
#
|
|
foreach $comInterface (sort(keys(%comData)))
|
|
{
|
|
$code .= $newline;
|
|
$code .= '#if ';
|
|
$or = '';
|
|
|
|
#
|
|
# First see if we need to define the COM interface.
|
|
#
|
|
# eg:
|
|
# #if !defined(REPLACEMENT_LPSTREAM) || \
|
|
# !defined(REPLACEMENT_LPSTREAM2)
|
|
#
|
|
foreach $comInterfaceParameterType (sort(keys(%{$comData{$comInterface}})))
|
|
{
|
|
$code .=
|
|
$or . '!defined(' . ComInterfaceParameterReplacementIdentifier($comInterfaceParameterType) . ')';
|
|
$or = ' || \\' . $newline . ' ';
|
|
}
|
|
$code .= $newline;
|
|
|
|
#
|
|
# Now see if we have the "real" COM interface definition from Midl.
|
|
# If not, generate it.
|
|
#
|
|
# eg:
|
|
# #if !defined(_IStream_INTERFACE_DEFINED)
|
|
# #if defined(interface)
|
|
# interface IStream; typedef interface IStream IStream;
|
|
# #else
|
|
# struct IStream; typedef struct IStream IStream;
|
|
# #endif
|
|
# #endif
|
|
#
|
|
$code .= '#if !defined(' . ComInterfaceType_IfdefSymbol($comInterface) . ')' . $newline;
|
|
$code .= ' #if defined(interface)' . $newline;
|
|
$code .= ' interface ' . $comInterface . '; typedef interface ' . $comInterface . ' ' . $comInterface . ';' . $newline;
|
|
$code .= ' #else' . $newline;
|
|
$code .= ' struct ' . $comInterface . '; typedef struct ' . $comInterface . ' ' . $comInterface . ';' . $newline;
|
|
$code .= ' #endif' . $newline;
|
|
$code .= '#endif' . $newline;
|
|
|
|
#
|
|
# Now for each parameter type, generate the typedefs if needed.
|
|
# eg:
|
|
#
|
|
# #if !defined(REPLACEMENT_LPSTREAM)
|
|
# typedef IStream *REPLACEMENT_LPSTREAM;
|
|
# #define REPLACEMENT_LPSTREAM REPLACEMENT_LPSTREAM
|
|
# #endif
|
|
# #if !defined(REPLACEMENT_LPSTREAM2)
|
|
# typedef IStream *REPLACEMENT_LPSTREAM2;
|
|
# #define REPLACEMENT_LPSTREAM2 REPLACEMENT_LPSTREAM2
|
|
# #endif
|
|
#
|
|
if (scalar(keys(%{$comData{$comInterface}})) > 1)
|
|
{
|
|
$needIndividualPoundIf = 1;
|
|
$typedefIndent = ' ';
|
|
}
|
|
else
|
|
{
|
|
$needIndividualPoundIf = 0;
|
|
$typedefIndent = '';
|
|
}
|
|
foreach $comInterfaceParameterType (sort(keys(%{$comData{$comInterface}})))
|
|
{
|
|
$replacement = ComInterfaceParameterReplacementIdentifier($comInterfaceParameterType);
|
|
|
|
if ($needIndividualPoundIf)
|
|
{
|
|
$code .= '#if !defined(' . $replacement . ')' . $newline;
|
|
}
|
|
$typedef = $ComInterfaceParameterTypedef{$comInterfaceParameterType};
|
|
$typedef =~ s/$comInterfaceParameterType/$replacement/g;
|
|
$code .= $typedefIndent . $typedef . $newline;
|
|
$code .= $typedefIndent . '#define ' . $replacement . ' ' . $replacement . $newline;
|
|
if ($needIndividualPoundIf)
|
|
{
|
|
$code .= '#endif' . $newline;
|
|
}
|
|
}
|
|
$code .= '#endif' . $newline;
|
|
}
|
|
|
|
#DebugPrint($code);
|
|
#DebugExit;
|
|
|
|
foreach $function (@functions)
|
|
{
|
|
$code .= GeneratePoundIf($function);
|
|
$code .= GeneratePrototype($function);
|
|
}
|
|
$code .= GeneratePoundEndif();
|
|
|
|
$headerBasename = BaseName($headerFullPath);
|
|
$upperBasename = MakeUpper($headerBasename);
|
|
$lowerBasename = MakeLower($headerBasename);
|
|
|
|
$Win32ToHresult = MakeHeaderPrivateName($headerBasename, 'Win32ToHresult');
|
|
if (DoesHeaderNeedWin32ToHresult())
|
|
{
|
|
$code .= $newline . $INLINE . ' HRESULT ' . $Win32ToHresult . '(void)';
|
|
$code .= '
|
|
{
|
|
DWORD dwLastError = GetLastError();
|
|
if (dwLastError == NO_ERROR)
|
|
dwLastError = ERROR_INTERNAL_ERROR;
|
|
return HRESULT_FROM_WIN32(dwLastError);
|
|
}
|
|
';
|
|
}
|
|
|
|
# hash so we can look for FooA and FooW
|
|
foreach $function (@functions)
|
|
{
|
|
#DebugPrint($function->name() . "\n");
|
|
$hashFunctionNames{$function->name()} = $function;
|
|
}
|
|
$anyStringFunctions = 0; # objbase has no A/W string functions
|
|
foreach $function (sort(keys(%hashFunctionNames)))
|
|
{
|
|
#DebugPrint($function . "\n");
|
|
# if there exists FooA and FooW, then Foo is a string function
|
|
if ($function =~ /(.+)A$/ && $hashFunctionNames{$1 . "W"})
|
|
{
|
|
$anyStringFunctions = 1;
|
|
$stringFunctionsHash{$1} = 1;
|
|
#DebugPrint($1 . " is a string function\n");
|
|
}
|
|
}
|
|
if ($anyStringFunctions)
|
|
{
|
|
$code .= "\n#if defined(UNICODE)\n\n";
|
|
foreach $function (sort(keys(%stringFunctionsHash)))
|
|
{
|
|
$code .= "#define " . MakePublicName($function);
|
|
$code .= " " . MakePublicName($function . "W") . "\n";
|
|
}
|
|
$code .= "\n#else /* UNICODE */\n\n";
|
|
foreach $function (sort(keys(%stringFunctionsHash)))
|
|
{
|
|
$code .= "#define " . MakePublicName($function);
|
|
$code .= " " . MakePublicName($function . "A") . "\n";
|
|
}
|
|
$code .= "\n#endif /* UNICODE */\n\n";
|
|
}
|
|
else
|
|
{
|
|
$code .= "\n";
|
|
}
|
|
|
|
$code .= "#if !ISOLATION_AWARE_USE_STATIC_LIBRARY\n";
|
|
|
|
foreach $function (@functions)
|
|
{
|
|
$code .= AppendNewlineIfNotEmpty(GeneratePoundIf($function));
|
|
$code .= GenerateStub($function);
|
|
}
|
|
$code .= AppendNewlineIfNotEmpty(GeneratePoundEndif());
|
|
|
|
$code .= GenerateHeaderCommon2($functions[0]);
|
|
|
|
$code .= "#endif /* ISOLATION_AWARE_USE_STATIC_LIBRARY */\n\n";
|
|
|
|
# This was for objbase.h/ole2.h, but they don't use it.
|
|
$ifPerHeaderMacroEnable = $PerHeaderMacroEnable{$lowerBasename};
|
|
$perHeaderMacroSymbol = $ENABLED . '_' . $upperBasename;
|
|
if ($ifPerHeaderMacroEnable)
|
|
{
|
|
$code .= '#if defined(' . $perHeaderMacroSymbol . ')' . $newline;
|
|
}
|
|
foreach $function (sort(keys(%hashFunctionNames)))
|
|
{
|
|
if ($NoMacro{$function})
|
|
{
|
|
$code .= " /* " . $function . " skipped, as it is a popular C++ member function name. */\n";
|
|
}
|
|
else
|
|
{
|
|
if ($Undef{$function})
|
|
{
|
|
$code .= "#if defined(" . $function . ")\n";
|
|
$code .= "#undef " . $function . "\n";
|
|
$code .= "#endif\n";
|
|
}
|
|
$code .= "#define " . $function . " " . MakePublicName($function) . "\n";
|
|
}
|
|
}
|
|
if ($PerHeaderMacroEnable{MakeLower(BaseName($headerFullPath))})
|
|
{
|
|
$code .= '#endif /* defined(' . $perHeaderMacroSymbol . ') */' . $newline;
|
|
}
|
|
|
|
#$code .= "\n#endif\n\n";
|
|
|
|
$code .= "\n#endif /* " . $ENABLED . " */\n";
|
|
$code .= "#endif /* RC */\n\n";
|
|
|
|
$code = InsertCodeIntoFile($code, $headerFullPath);
|
|
|
|
print($code);
|
|
|
|
__END__
|
|
:endofperl
|