윈도우즈 터미널 서버에 대한 라이센스가 없는 경우 기본 2명(콘솔까지 하면 3명)이 접근이 가능한데, 여러 사람이 자주 사용하는 윈도우즈 서버에 특정한 사용자가 터미널로 로그인 중인 경우 다른 사용자의 접근이 차단됩니다.
만약 이미 접속중인 사용자가 작업을 완료한 이후에, 연결을 끊지 않으면 계속 연결이 유지되고, 그로 인하여 다른 작업이 필요한 사용자가 접속을 하지 못하는 문제가 발생하는 경우가 종종 있어서 관리상 문제가 되는 경우가 있었습니다.
이와 같은 문제를 방지하기 위하여, 기존 연결된 사용자가 접속한 서버에서 작업을 하지 않으면 화면 보호기가 동작되는 것처럼 자동으로 연결이 끊어지도록 설정하는 방법이 있는데, 아래와 같습니다.
위 그림에서와 같이 관리도구의 "터미널 서비스 구성"을 실행합니다.
구성 관리자에서 RDP-Tcp 연결에 대한 등록 정보창을 띄운 후에, 아래와 같이 세션 부분을 설정합니다.
10분 동안 작업이 없으면 연결되어 있는 세션 연결이 강제로 끊어지도록 설정한 예입니다.
부가적으로 터미널 접속시, 클라이언트의 장치를 사용하지 않도록 몇 가지 설정합니다.(프린터 등을 매핑하면, 이벤트 로그에 프린터 드라이버를 찾을 수 없다는 오류가 많이 쌓여 있죠.)
위와 같이 설정해 놓으면 실수로 접속을 끊지 않은 터미널 세션의 연결을 강제로 끊어주어 다른 사용자가 접속하여 작업을 할 수 있도록 합니다.
Delphi7을 이용한 ActiveForm을 제작하였더니, 다음과 같은 오류가 발생하였습니다.
TActiveForm의 OnDestroy가 호출되지 않는 문제가 있었고, ActiveForm을 오랫동안 사용하게 되면, 알 수 없는 오류들이 발생하는 것이었습니다.
구글링을 하여 보면, 여러 자료들이 나오고 아래 참고자료를 참고해 보시면 되고, 저는 다음과 같이 해결하였습니다.
먼저 델파이 VCL의 axctrls.pas 소스의 ParkingWindow 윈도우 부분을 아래와 같이 수정합니다. 수정 전에 원본 axctrls.pas 파일과 axctrls.dcu 파일을 백업해 둡니다.
function ParkingWindow: HWND;
var
TempClass: TWndClass;
ParkingName : String;
begin
// 2009-06-23 : 각 컨트롤별로 ParkingWindow를 갖도록 함
// Result := xParkingWindow;
// if Result <> 0 then Exit;
ParkingName := 'DAXParkingWindow_' + Format('%p', [@ParkingWindowProc]);
FillChar(TempClass, sizeof(TempClass), 0);
// if not GetClassInfo(HInstance, 'DAXParkingWindow', TempClass) then
if not GetClassInfo(HInstance, PChar(ParkingName), TempClass) then
begin
TempClass.hInstance := HInstance;
TempClass.lpfnWndProc := @ParkingWindowProc;
// TempClass.lpszClassName := 'DAXParkingWindow';
TempClass.lpszClassName := PChar(ParkingName);
if Windows.RegisterClass(TempClass) = 0 then
raise EOutOfResources.Create(SWindowClass);
end;
xParkingWindow := CreateWindowEx(WS_EX_TOOLWINDOW, TempClass.lpszClassName, nil,
WS_POPUP, GetSystemMetrics(SM_CXSCREEN) div 2,
GetSystemMetrics(SM_CYSCREEN) div 2, 0, 0, 0, 0, HInstance, nil);
SetWindowPos(xParkingWindow, 0, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOREDRAW
or SWP_NOZORDER or SWP_SHOWWINDOW);
Result := xParkingWindow;
end;
프로젝트에 axctrls.pas 소스를 첨가하여 컴파일하여 axctrls.dcu 파일을 생성하고, axctrls.dcu 파일을 델파이가 설치된 디렉토리의 Lib 및 Lib\Debug 디렉토리에 복사합니다.
아래 참고자료의 첫번째 URL 정보를 참고하여 패치를 작성하였으나, XP에서 문제가 해결되지 않고 여전히 발생하였습니다. 다각도로 디버깅을 하여본 결과, 첫 번째 창이 사라질 때, 파킹 윈도우(ParkingWindow)도 함께 사라져버리는 것이었습니다. 그래서 첫 번째 창을 닫아버리면 세 번째 창을 띄울때부터는 DAX나 System Error 1400이나, Access Violation이 발생하는 것이었습니다.
그래서 위와 같이 처음 두 줄을 주석 처리하여 각 ActiveForm마다 새로운 파킹 윈도우(ParkingWindow가 생성되도록 하였너니, DAX 등과 같은 오류가 발생하지는 않았습니다.
그러나, 위와 같이 피치한 이후에도 사용자들에게서 몇 가지 문제점이 나타났습니다.
리소스를 더 이상 할당 할 수 없는 문제가 발생하는 경우가 있었고, 그래도 여전히 System. Error 1400 오류가 발생하는 경우가 나타났었습니다.
특이한 EurekaLog에 메모리 누스가 상당히 많이 잡한다는 점이었는데, VCL문제인지, 패치한 소스에 문제인지는 좀더 분석을 해봐야 겠습니다.
OnDestroy가 호출되지 않는 문제는 BeforeDestruction 메소드를 override 하여 OnDestroy 이벤트 핸들러를 재할당하는 방식으로 해결하였습니다.
procedure TActiveFormX1.BeforeDestruction;
begin
OnDestroy := ActiveFormDestroy;
inherited;
end;