Witam.
Mam beznadziejny problem. Korzystam z BTMemoryModule do zrzucenia dll-ki do pamięci i operowania na tym. Dlaczego tak a nie inaczej nie chce mi się tłumaczyć - tak musi być. Działałem na tym od kilku miesięcy i wszystko było ok. Program pisałem pod xp i działał. testowałem parę razy pod vistą i też nie było problemów. Przed wczoraj usłyszałem że niestety są problemy z programem który korzysta z BTMemoryModule pod Windows Server 2008. Sprawdzałem Windows 7 i wszystko gra. Problem dotyczy tylko Server 2008. Przedebugowałem kod tego unitu i wiem gdzie się wywala tylko nie mam pojęcia dlaczego. Może ktoś bardziej ogarnięty mógłby pomóc?
Wklejam kod unitu BTMemoryModule
unit BTMemoryModule;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Memory DLL loading code *
* ------------------------ *
* *
* MemoryModule "Conversion to Delphi" *
* Copyright (c) 2005 - 2006 by Martin Offenwanger / coder@dsplayer.de *
* http://www.dsplayer.de *
* *
* Original C++ Code "MemoryModule Version 0.0.1" *
* Copyright (c) 2004- 2006 by Joachim Bauch / mail@joachim-bauch.de *
* http://www.joachim-bauch.de *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{
@author(Martin Offenwanger: coder@dsplayer.de)
@created(Mar 20, 2005)
@lastmod(Sep 27, 2005)
}
interface
uses
// Borland Run-time Library
Windows;
{++++++++++++++++++++++++++++++++++++++
*** MemoryModule Type Definition ***
--------------------------------------}
type
PBTMemoryModule = ^TBTMemoryModule;
_BT_MEMORY_MODULE = packed record
headers: PImageNtHeaders;
codeBase: Pointer;
modules: Pointer;
numModules: integer;
initialized: boolean;
end;
{$EXTERNALSYM _BT_MEMORY_MODULE}
TBTMemoryModule = _BT_MEMORY_MODULE;
BT_MEMORY_MODULE = _BT_MEMORY_MODULE;
{$EXTERNALSYM BT_MEMORY_MODULE}
{++++++++++++++++++++++++++++++++++++++++++++++++++
*** Memory DLL loading functions Declaration ***
--------------------------------------------------}
// return value is nil if function fails
function BTMemoryLoadLibary(var f_data: Pointer; const f_size: int64): PBTMemoryModule; stdcall;
// return value is nil if function fails
function BTMemoryGetProcAddress(var f_module: PBTMemoryModule; const f_name: PChar): Pointer; stdcall;
// free module
procedure BTMemoryFreeLibrary(var f_module: PBTMemoryModule); stdcall;
// returns last error
function BTMemoryGetLastError: string; stdcall;
implementation
uses
// Borland Run-time Library
SysUtils;
{+++++++++++++++++++++++++++++++++++
*** Dll EntryPoint Definition ***
-----------------------------------}
type
TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall;
{++++++++++++++++++++++++++++++++++++++++
*** Missing Windows API Definitions ***
----------------------------------------}
PImageBaseRelocation = ^TImageBaseRelocation;
_IMAGE_BASE_RELOCATION = packed record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
end;
{$EXTERNALSYM _IMAGE_BASE_RELOCATION}
TImageBaseRelocation = _IMAGE_BASE_RELOCATION;
IMAGE_BASE_RELOCATION = _IMAGE_BASE_RELOCATION;
{$EXTERNALSYM IMAGE_BASE_RELOCATION}
PImageImportDescriptor = ^TImageImportDescriptor;
_IMAGE_IMPORT_DESCRIPTOR = packed record
OriginalFirstThunk: DWORD;
TimeDateStamp: DWORD;
ForwarderChain: DWORD;
Name: DWORD;
FirstThunk: DWORD;
end;
{$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}
TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;
{$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}
PImageImportByName = ^TImageImportByName;
_IMAGE_IMPORT_BY_NAME = packed record
Hint: Word;
Name: array[0..255] of Byte; // original: "Name: array [0..0] of Byte;"
end;
{$EXTERNALSYM _IMAGE_IMPORT_BY_NAME}
TImageImportByName = _IMAGE_IMPORT_BY_NAME;
IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;
{$EXTERNALSYM IMAGE_IMPORT_BY_NAME}
const
IMAGE_SIZEOF_BASE_RELOCATION = 8;
{$EXTERNALSYM IMAGE_SIZEOF_BASE_RELOCATION}
IMAGE_REL_BASED_HIGHLOW = 3;
{$EXTERNALSYM IMAGE_REL_BASED_HIGHLOW}
IMAGE_ORDINAL_FLAG32 = DWORD($80000000);
{$EXTERNALSYM IMAGE_ORDINAL_FLAG32}
var
lastErrStr: string;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++
*** Memory DLL loading functions Implementation ***
-----------------------------------------------------}
function BTMemoryGetLastError: string; stdcall;
begin
Result := lastErrStr;
end;
function GetFieldOffset(const Struc; const Field): Cardinal; stdcall;
begin
Result := Cardinal(@Field) - Cardinal(@Struc);
end;
function GetImageFirstSection(NtHeader: PImageNtHeaders): PImageSectionHeader; stdcall;
begin
Result := PImageSectionHeader(Cardinal(NtHeader) +
GetFieldOffset(NtHeader^, NtHeader^.OptionalHeader) +
NtHeader^.FileHeader.SizeOfOptionalHeader);
end;
function GetHeaderDictionary(f_module: PBTMemoryModule; f_idx: integer): PImageDataDirectory; stdcall;
begin
Result := PImageDataDirectory(@(f_module.headers.OptionalHeader.DataDirectory[f_idx]));
end;
function GetImageOrdinal(Ordinal: DWORD): Word; stdcall;
begin
Result := Ordinal and $FFFF;
end;
function GetImageSnapByOrdinal(Ordinal: DWORD): Boolean; stdcall;
begin
Result := ((Ordinal and IMAGE_ORDINAL_FLAG32) <> 0);
end;
procedure CopySections(const f_data: Pointer; const f_old_headers: TImageNtHeaders; f_module: PBTMemoryModule); stdcall;
var
l_size, i: integer;
l_codebase: Pointer;
l_dest: Pointer;
l_section: PImageSectionHeader;
begin
l_codebase := f_module.codeBase;
l_section := GetImageFirstSection(f_module.headers);
for i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin
// section doesn't contain data in the dll itself, but may define
// uninitialized data
if (l_section.SizeOfRawData = 0) then begin
l_size := f_old_headers.OptionalHeader.SectionAlignment;
if l_size > 0 then begin
l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_size, MEM_COMMIT, PAGE_READWRITE);
l_section.Misc.PhysicalAddress := cardinal(l_dest);
ZeroMemory(l_dest, l_size);
end;
inc(longword(l_section), sizeof(TImageSectionHeader));
// Continue with the nex loop
Continue;
end;
// commit memory block and copy data from dll
l_dest := VirtualAlloc(Pointer(Cardinal(l_codebase) + l_section.VirtualAddress), l_section.SizeOfRawData, MEM_COMMIT, PAGE_READWRITE);
CopyMemory(l_dest, Pointer(longword(f_data) + l_section.PointerToRawData), l_section.SizeOfRawData);
l_section.Misc.PhysicalAddress := cardinal(l_dest);
// IMAGE_SIZEOF_SECTION_HEADER
inc(longword(l_section), sizeof(TImageSectionHeader));
end;
end;
procedure PerformBaseRelocation(f_module: PBTMemoryModule; f_delta: Cardinal); stdcall;
var
l_i: Cardinal;
l_codebase: Pointer;
l_directory: PImageDataDirectory;
l_relocation: PImageBaseRelocation;
l_dest: Pointer;
l_relInfo: ^Word;
l_patchAddrHL: ^DWord;
l_type, l_offset: integer;
begin
l_codebase := f_module.codeBase;
l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
if l_directory.Size > 0 then begin
l_relocation := PImageBaseRelocation(Cardinal(l_codebase) + l_directory.VirtualAddress);
while l_relocation.VirtualAddress > 0 do begin
l_dest := Pointer((Cardinal(l_codebase) + l_relocation.VirtualAddress));
l_relInfo := Pointer(Cardinal(l_relocation) + IMAGE_SIZEOF_BASE_RELOCATION);
for l_i := 0 to (trunc(((l_relocation.SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2)) - 1) do begin
// the upper 4 bits define the type of relocation
l_type := (l_relInfo^ shr 12);
// the lower 12 bits define the offset
l_offset := l_relInfo^ and $FFF;
//showmessage(inttostr(l_relInfo^));
if l_type = IMAGE_REL_BASED_HIGHLOW then begin
// change complete 32 bit address
l_patchAddrHL := Pointer(Cardinal(l_dest) + Cardinal(l_offset));
l_patchAddrHL^ := l_patchAddrHL^ + f_delta;
end;
inc(l_relInfo);
end;
l_relocation := Pointer(cardinal(l_relocation) + l_relocation.SizeOfBlock);
end;
end;
end;
function BuildImportTable(f_module: PBTMemoryModule): boolean; stdcall;
var
l_codeBase: Pointer;
l_directory: PImageDataDirectory;
l_importDesc: PImageImportDescriptor;
l_thunkRef, l_funcRef: ^DWORD;
l_handle: HMODULE;
l_temp: integer;
l_thunkData: TImageImportByName;
begin
Result := true;
l_codeBase := f_module.codeBase;
l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (l_directory.Size > 0) then begin
l_importDesc := PImageImportDescriptor(Cardinal(l_codeBase) + l_directory.VirtualAddress);
while (not IsBadReadPtr(l_importDesc, sizeof(TImageImportDescriptor))) and (l_importDesc.Name <> 0) do begin
l_handle := LoadLibrary(PChar(Cardinal(l_codeBase) + l_importDesc.Name));
if (l_handle = INVALID_HANDLE_VALUE) then begin
lastErrStr := 'BuildImportTable: can''t load library: ' + PChar(Cardinal(l_codeBase) + l_importDesc.Name);
Result := false;
exit;
end;
// ReallocMemory crashes if "f_module.modules = nil"
if f_module.modules = nil then
f_module.modules := AllocMem(1);
f_module.modules := ReallocMemory(f_module.modules, ((f_module.numModules + 1) * (sizeof(HMODULE))));
if f_module.modules = nil then begin
lastErrStr := 'BuildImportTable: ReallocMemory failed';
result := false;
exit;
end;
// module->modules[module->numModules++] = handle;
l_temp := (sizeof(cardinal) * (f_module.numModules));
inc(Cardinal(f_module.modules), l_temp);
cardinal(f_module.modules^) := l_handle;
dec(Cardinal(f_module.modules), l_temp);
f_module.numModules := f_module.numModules + 1;
if l_importDesc.OriginalFirstThunk <> 0 then begin
l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.OriginalFirstThunk);
l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
end else begin
// no hint table
l_thunkRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
l_funcRef := Pointer(Cardinal(l_codeBase) + l_importDesc.FirstThunk);
end;
while l_thunkRef^ <> 0 do begin
if GetImageSnapByOrdinal(l_thunkRef^) then
l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(GetImageOrdinal(l_thunkRef^))))
else begin
CopyMemory(@l_thunkData, Pointer(Cardinal(l_codeBase) + l_thunkRef^), sizeof(TImageImportByName));
l_funcRef^ := Cardinal(GetProcAddress(l_handle, PChar(@(l_thunkData.Name))));
end;
if l_funcRef^ = 0 then begin
lastErrStr := 'BuildImportTable: GetProcAddress failed';
result := false;
break;
end;
inc(l_funcRef);
inc(l_thunkRef);
end;
inc(longword(l_importDesc), sizeof(TImageImportDescriptor));
end;
end;
end;
function GetSectionProtection(SC: cardinal): cardinal; stdcall;
//SC ImageSectionHeader.Characteristics
begin
result := 0;
if (SC and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
result := result or PAGE_NOCACHE;
// E - Execute, R Read , W Write
if (SC and IMAGE_SCN_MEM_EXECUTE) <> 0 //E ?
then if (SC and IMAGE_SCN_MEM_READ) <> 0 //ER ?
then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //ERW ?
then result := result or PAGE_EXECUTE_READWRITE
else result := result or PAGE_EXECUTE_READ
else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //EW?
then result := result or PAGE_EXECUTE_WRITECOPY
else result := result or PAGE_EXECUTE
else if (SC and IMAGE_SCN_MEM_READ) <> 0 // R?
then if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //RW?
then result := result or PAGE_READWRITE
else result := result or PAGE_READONLY
else if (SC and IMAGE_SCN_MEM_WRITE) <> 0 //W?
then result := result or PAGE_WRITECOPY
else result := result or PAGE_NOACCESS;
end;
procedure FinalizeSections(f_module: PBTMemoryModule); stdcall;
var
l_i: integer;
l_section: PImageSectionHeader;
l_protect, l_oldProtect, l_size: Cardinal;
begin
l_section := GetImageFirstSection(f_module.headers);
for l_i := 0 to f_module.headers.FileHeader.NumberOfSections - 1 do begin
if (l_section.Characteristics and IMAGE_SCN_MEM_DISCARDABLE) <> 0 then begin
// section is not needed any more and can safely be freed
VirtualFree(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, MEM_DECOMMIT);
inc(longword(l_section), sizeof(TImageSectionHeader));
continue;
end;
l_protect := GetSectionProtection(l_section.Characteristics);
if (l_section.Characteristics and IMAGE_SCN_MEM_NOT_CACHED) <> 0 then
l_protect := (l_protect or PAGE_NOCACHE);
// determine size of region
l_size := l_section.SizeOfRawData;
if l_size = 0 then begin
if (l_section.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0 then begin
l_size := f_module.headers.OptionalHeader.SizeOfInitializedData;
end else begin
if (l_section.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) <> 0 then
l_size := f_module.headers.OptionalHeader.SizeOfUninitializedData;
end;
if l_size > 0 then begin
if not VirtualProtect(Pointer(l_section.Misc.PhysicalAddress), l_section.SizeOfRawData, l_protect, @l_oldProtect) then begin
lastErrStr := 'FinalizeSections: VirtualProtect failed';
exit;
end;
end;
end;
inc(longword(l_section), sizeof(TImageSectionHeader));
end;
end;
function BTMemoryLoadLibary(var f_data: Pointer; const f_size: int64): PBTMemoryModule; stdcall;
var
l_result: PBTMemoryModule;
l_dos_header: TImageDosHeader;
l_old_header: TImageNtHeaders;
l_code, l_headers: Pointer;
l_locationdelta: Cardinal;
l_DllEntry: TDllEntryProc;
l_successfull: boolean;
begin
l_result := nil;
Result := nil;
try
CopyMemory(@l_dos_header, f_data, sizeof(_IMAGE_DOS_HEADER));
if (l_dos_header.e_magic <> IMAGE_DOS_SIGNATURE) then begin
lastErrStr := 'BTMemoryLoadLibary: dll dos header is not valid';
exit;
end;
CopyMemory(@l_old_header, pointer(longint(f_data) + l_dos_header._lfanew), sizeof(_IMAGE_NT_HEADERS));
if l_old_header.Signature <> IMAGE_NT_SIGNATURE then begin
lastErrStr := 'BTMemoryLoadLibary: IMAGE_NT_SIGNATURE is not valid';
exit;
end;
// reserve memory for image of library
l_code := VirtualAlloc(Pointer(l_old_header.OptionalHeader.ImageBase), l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if l_code = nil then
// try to allocate memory at arbitrary position
l_code := VirtualAlloc(nil, l_old_header.OptionalHeader.SizeOfImage, MEM_RESERVE, PAGE_READWRITE);
if l_code = nil then begin
lastErrStr := 'BTMemoryLoadLibary: VirtualAlloc failed';
exit;
end;
// alloc space for the result record
l_result := PBTMemoryModule(HeapAlloc(GetProcessHeap(), 0, sizeof(TBTMemoryModule)));
l_result.codeBase := l_code;
l_result.numModules := 0;
l_result.modules := nil;
l_result.initialized := false;
// xy: is it correct to commit the complete memory region at once?
// calling DllEntry raises an exception if we don't...
VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
// commit memory for headers
l_headers := VirtualAlloc(l_code, l_old_header.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
// copy PE header to code
CopyMemory(l_headers, f_data, (Cardinal(l_dos_header._lfanew) + l_old_header.OptionalHeader.SizeOfHeaders));
l_result.headers := PImageNtHeaders(longint(l_headers) + l_dos_header._lfanew);
// update position
l_result.headers.OptionalHeader.ImageBase := cardinal(l_code);
// copy sections from DLL file block to new memory location
CopySections(f_data, l_old_header, l_result);
// adjust base address of imported data
l_locationdelta := Cardinal(Cardinal(l_code) - l_old_header.OptionalHeader.ImageBase);
if l_locationdelta <> 0 then
PerformBaseRelocation(l_result, l_locationdelta);
// load required dlls and adjust function table of imports
if not BuildImportTable(l_result) then begin
lastErrStr := lastErrStr + ' BTMemoryLoadLibary: BuildImportTable failed';
Abort;
end;
// mark memory pages depending on section headers and release
// sections that are marked as "discardable"
FinalizeSections(l_result);
// get entry point of loaded library
if (l_result.headers.OptionalHeader.AddressOfEntryPoint) <> 0 then begin
@l_DllEntry := Pointer(Cardinal(l_code) + l_result.headers.OptionalHeader.AddressOfEntryPoint);
if @l_DllEntry = nil then begin
lastErrStr := 'BTMemoryLoadLibary: Get DLLEntyPoint failed';
Abort;
end;
l_successfull := l_DllEntry(Cardinal(l_code), DLL_PROCESS_ATTACH, nil);
if not l_successfull then begin
lastErrStr := 'BTMemoryLoadLibary: Can''t attach library';
Abort;
end;
l_result.initialized := true;
end;
except
BTMemoryFreeLibrary(l_result);
exit;
end;
Result := l_result;
end;
function BTMemoryGetProcAddress(var f_module: PBTMemoryModule; const f_name: PChar): Pointer; stdcall;
var
l_codeBase: Pointer;
l_idx: integer;
l_i: DWORD;
l_nameRef: ^DWORD;
l_ordinal: ^WORD;
l_exports: PImageExportDirectory;
l_directory: PImageDataDirectory;
l_temp: ^DWORD;
begin
Result := nil;
l_codeBase := f_module.codeBase;
l_idx := -1;
l_directory := GetHeaderDictionary(f_module, IMAGE_DIRECTORY_ENTRY_EXPORT);
if l_directory.Size = 0 then begin
lastErrStr := 'BTMemoryGetProcAddress: no export table found';
exit;
end;
l_exports := PImageExportDirectory(Cardinal(l_codeBase) + l_directory.VirtualAddress);
if ((l_exports.NumberOfNames = 0) or (l_exports.NumberOfFunctions = 0)) then begin
lastErrStr := 'BTMemoryGetProcAddress: DLL doesn''t export anything';
exit;
end;
// search function name in list of exported names
l_nameRef := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNames));
l_ordinal := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfNameOrdinals));
for l_i := 0 to l_exports.NumberOfNames - 1 do begin
if StrComp(f_name, PChar(Cardinal(l_codeBase) + l_nameRef^)) = 0 then begin
l_idx := l_ordinal^;
break;
end;
inc(l_nameRef);
inc(l_ordinal);
end;
if (l_idx = -1) then begin
lastErrStr := 'BTMemoryGetProcAddress: exported symbol not found';
exit;
end;
if (Cardinal(l_idx) > l_exports.NumberOfFunctions - 1) then begin
lastErrStr := 'BTMemoryGetProcAddress: name <-> ordinal number don''t match';
exit;
end;
// AddressOfFunctions contains the RVAs to the "real" functions
l_temp := Pointer(Cardinal(l_codeBase) + Cardinal(l_exports.AddressOfFunctions) + Cardinal((l_idx * 4)));
Result := Pointer(Cardinal(l_codeBase) + l_temp^);
end;
procedure BTMemoryFreeLibrary(var f_module: PBTMemoryModule); stdcall;
var
l_module: PBTMemoryModule;
l_i: integer;
l_temp: integer;
l_DllEntry: TDllEntryProc;
begin
l_module := f_module;
if l_module <> nil then begin
if l_module.initialized then begin
@l_DllEntry := Pointer(Cardinal(l_module.codeBase) + l_module.headers.OptionalHeader.AddressOfEntryPoint);
l_DllEntry(Cardinal(l_module.codeBase), DLL_PROCESS_DETACH, nil);
l_module.initialized := false;
// free previously opened libraries
for l_i := 0 to l_module.numModules - 1 do begin
l_temp := (sizeof(cardinal) * (l_i));
inc(Cardinal(l_module.modules), l_temp);
if Cardinal(f_module.modules^) <> INVALID_HANDLE_VALUE then
FreeLibrary(Cardinal(f_module.modules^));
dec(Cardinal(l_module.modules), l_temp);
end;
FreeMemory(l_module.modules);
if l_module.codeBase <> nil then
// release memory of library
VirtualFree(l_module.codeBase, 0, MEM_RELEASE);
HeapFree(GetProcessHeap(), 0, f_module);
Pointer(f_module) := nil;
end;
end;
end;
end.
błąd wywala się w w funkcji BTMemoryLoadLibary dokładnie w miejscu:
l_successfull := l_DllEntry(Cardinal(l_code), DLL_PROCESS_ATTACH, nil);
l_DllEntry
to typ funkcji
TDllEntryProc = function(hinstdll: THandle; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall;
czy Server 2008 ma jakieś zabezpieczenie czy ograniczenia jeśli chodzi o pamięć? Bo to zdecydowanie wina systemu. Ktoś ma jakiekolwiek pomysły co może być przyczyną lub jak to zmienić.