Keyboard layout changes to default when exiting dbgrid

چند روز پيش يکي از دوستان با من تماس گرفت و سوالي از من کرد.
سوال ايشون اين بود: يک برنامه را مي خواهيم با دلفي 2010 کامپايل کنيم. اين برنامه شامل يک DBGrid و يک کنترل ديگه مثل Edit هستش. حال اگر در زمان اجرا، Layout کيبورد رو عوض کنيم، مثلا به فارسي تغيير بديم و از DBGrid خارج بشيم، Layout کيبورد، هنگام خارج شدن به حالت اولش برمي گرده. حالا چطور ميشه جلوي اين کار رو گرفت.
حالا خود من به اين مشکل برخوردم و به روش زير حلش کردم:
اول به "source\Win32\db" در مسير نصب دلفي بريد، به عنوان مثال
C:\Program Files (x86)\Embarcadero\RAD Studio\7.0\source\Win32\db
فايل DBGrids.pas رو پيدا کنيد و به مسير ديگري کپي کنيد.
در فايلي که کپي کرديد، دنبال پروسيجر "TCustomDBGrid.WMKillFocus" بگرديد. که به صورت زير نوشته شده
procedure TCustomDBGrid.WMKillFocus(var Message: TMessage);
begin
  ImeName := Screen.DefaultIme;
  ImeMode := imDontCare;
  inherited;
  if not ((InplaceEditor <> nil) and
    (HWND(Message.WParam) = InplaceEditor.Handle)) then
    ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
end;
حالا پروسيجر رو به شکل زير تغيير بديد

procedure TCustomDBGrid.WMKillFocus(var Message: TMessage);
var kblayout: HKL;
begin
  kblayout := GetKeyboardLayout(0);
  ImeName := Screen.DefaultIme;
  ImeMode := imDontCare;
  inherited;
  if not ((InplaceEditor <> nil) and
    (HWND(Message.WParam) = InplaceEditor.Handle)) then
    ActivateKeyboardLayout(kblayout, KLF_ACTIVATE);
end;

حالا بايد اين فايل رو کامپايل کنيد. براي اين کار اين فايل رو در پوشه پروژتون قرار بديد و کل برنامه را Build کنيد.
شاد باشيد.

WMI - Part1

مقدمه
 
WMI راه هاي مشخصي براي فعاليت هاي پيچيده مديريتي در کامپيوتر هاي Desktop و شبکه را براي developer  ها و administrator ها فراهم مي کند. در قديم اينگونه فعاليت هاي مديريتي به وسيله  API و يا Registry انجام مي شد. اما با قبول استاندارد WMI توسط کاربران و فروشندگان، هم اکنون شما مي توانيد بدون نياز به دانستن API هاي جديد، کلاس هاي WMI را که توسط فروشندگان قطعات ارائه شده است را براي ساخت ابزار مديريتي استفاده کنيد.
از کاربران مختلفي که نياز به يادگيري WMI دارند مي توان به IT ManagerSystem ، AdministratorApplication و Application Developer  اشاره کرد. به عنوان مثال AdministratorApplication با استفاده از WMI مي توانند کامپيوتر هاي Desktop و شبکه را مديريت کنند. و يا توسعه دهندگان نرم افزار هاي (Application Developer) مديريتي بايد با رابط هاي WMI آشنا باشند تا قادر به بيرون کشيدن اطلاعات سيستمي براي نرم افزار خود باشند.

پيش درآمد

WMI (Windows Management Instrumentation) پياده سازي مايکروسافت از Web-Based Enterprise Management است که به اختصار WBEM ناميده مي شود. WBEM يک استاندارد صنعتي براي مديريت کامپيوتر هاي توزيع شده است.
WMI يک روش شي گرا براي مديريت است که بر روي CIM بنا شده است. CIM که مخففCommon Information Model است يک مدل شي گرا است که از تمامي خصوصيت هاي شي گرايي مانند abstraction, inheritance, dependencies, aggregation استفاده مي کند تا اطلاعاتي درمورد اشيائي مانند Systems, applications, networks, devices  وغيره که ساختار ويندوز بر آن ها نهاده شده است را به ما نشان دهد.
براي درک بهتر از WMI ، در بخش بعدي ساختار WMI شرح داده خواهد شد.

مفاهيم پايه اي معماري WMI

معماري WMI از 3 لايه اصلي تشکيل شده است که عبارتند از
  1. Managed resources
  2. WMI Infrastructure
  3. Consumers

در تصوير زير معماري WMI نشان داده شده است

در اين لينک، تصويري که در MSDN به آن اشاره شده است وجود دارد که در آن به جزئيات بيشتري اشاره شده است.

1. Managed resources

Managed resources اجزاي فيزيکي و منطقي هستند که توسط WMI نمايش و مديريت مي شوند. برخي منابع سيستم که به وسيله WMI مديريت مي شوند عبارتند از:
ديسک ها، دستگاه هاي جانبي، فايل ها، شاخه ها (فولدر ها)، اجزاي شبکه ، چاپگر ها و ...
Managed resources توسط Provider با WMI ارتباط برقرار مي کند.
2. WMI Infrastructure
WMI‌ از 3 جزء CIMOM ، CIM و Provider تشکيل شده است که هرکدام به صورت جداگانه توضيح داده خواهند شد.

  • Provider
همانطور که گفته شد، Provider رابط بين WMI و Managed resources است. Provider ها درخواست ها را از نرم افزار ها و اسکريپت هاي Consumer گرفته و دستورالعمل ها را به Managed resources تحويل مي دهد.
Providerها معمولا به صورت Dll در فولدر SystemRoot%\system32\wbem% قرار دارند. WMI شامل چندين Provider توکار براي سيستم عامل هاي مختلف است که به نام Provider هاي استاندارد شناخته مي شوند.
در جدول زير مشخصات چند Provider براي شما آماده شده است.


Description

DLL

Namespace

Provider

Maps Active Directory objects to WMI.

dsprov.dll

root\directory\ldap

Active Directory provider

Manage Windows event logs, for example, read,
backup, clear, copy, delete, monitor, rename, compress, uncompress,
and change event log settings.

ntevt.dll

root\cimv2

Event Log provider

Provides access to raw performance data.

wbemperf.dll

root\cimv2

Performance Counter provider

Read, write, enumerate, monitor, create, and delete
registry keys and values.

stdprov.dll

root\default

Registry provider

Provides access to SNMP MIB data and traps from
SNMP-managed devices.

snmpincl.dll

root\snmp

SNMP provider

Provides access to information on WDM device
drivers.

wmiprov.dll

root\wmi

WDM provider

Provides information about the computer, disks,
peripheral devices, files, folders, file systems, networking
components, operating system, printers, processes, security,
services, shares, SAM users and groups, and more.

cimwin32.dll

root\cimv2

Win32 provider

Provides access to information about installed
software.

msiprov.dll

root\cimv2

Windows Installer provider

  • CIMOM
CIMOM فعل و انفعال هاي بين Provider و Consumer را در دست مي گيرد. اينگونه فرض کنيد که CIMOM به عنوان دلال اطلاعات WMI است. همه درخواست ها و داده هاي WMI به وسيله  CIMOM جريان دارند.
  • CIM
WMI بر يک ايده بنيان گذاري شده که پيکربندي و اطلاعات مديريت شده از منابع مختلف، به صورت الگوي يکنواخت نمايش داده شوند. CIM يک الگوست، که اين الگو بر مبناي استاندارد DMTF Common Information Model standard بنا نهاده شده است. اين الگو بر مبناي کلاس ها بنا نهاده شده است. کلاس ها يک طرح از منابع مديريتي WMI هستند. کلاس ها شامل خصوصيات (properties) و متد ها يي(methods) هستند. Properties حالت يک منبع را شرح مي دهند و methods توابع اجرايي هستند که عمليات هايي را روي منابع انجام  مي دهند. کلاس ها به فضاهاي نام (namespaces) دسته بندي مي شوند. Namespace ها يک گروهبندي منطقي از کلاس هايي هستند که در يک حوزه مديريتي مشترک قرار دارند. به عنوان مثال فضاي نام " root\cimv2" شامل کلاس هايي است که دربرگيرنده منابع عمومي کامپيوتر و سيستم عامل هستند. به عنوان نمونه کلاس هاي زير را براي فضاي نام " root\cimv2" مي توان نام برد:
Win32_Service ، Win32_Process ، Win32_Printer و ...
همانطور که در پيش درآمد نيز گفته شد CIM يک مدل شي گرا است که از تمامي خصوصيت هاي شي گرايي مانند abstraction, inheritance, dependencies, aggregation استفاده مي کند تا اطلاعاتي درمورد اشياعي مانند ystems, applications, networks, devices  وغيره که ساختار ويندوز بر آن ها نهاده شده است را به ما نشان دهد.
  • WMI Scripting Library
همانطور که در در شکل نمايش داده شده است، يک قسمت ديگر در Infrastructure  وجود دارد که WMI Scripting Library نام دارد. اين قسمت مجموعه اي از اشيا را فراهم مي کنند که WMI Infrastructure  را از طريق زبان هاي اسکريپتي مانند VBScript, Jscript و ... قابل دسترس مي سازند. اشياء WMI scripting library يک مدل يک شکل و يکنواخت از WMI Infrastructure را مهيا مي کنند.
اسکريپت زير که به زبان VBS است، نام تمامي سرويس هاي کامپيوتر را نمايش مي دهد
Set wbemServices = GetObject("winmgmts:\\127.0.0.1")
Set wbemObjectSet = wbemServices.InstancesOf("Win32_Service")

For Each wbemObject In wbemObjectSet
    WScript.Echo "Display Name:  " & wbemObject.DisplayName
Next

عبارت 127.0.0.1 به سيستمي که اين اسکريپت بر روي آن اجرا مي شود اشاره دارد. شما مي توانيد به جاي اين عبارت نام سيستم خود را به جاي آن وارد نماييد. براي اجراي اسکريپت فوق، آن را در فايلي با پسوند vbs ذخيره کنيد، و سپس  داخل محيط داس Command-Promptaشويد( از منوي استارت گزينه Run را انتخاب کنيد و عبارت CMD را درون آن تايپ نماييد و روي OK کليک کنيد) حال عبارت زير را تايپ و اجرا کنيد.
cscript Filename.vbs  
به ياد داشته باشيد که بجاي عبارت Filename ، نام و مسير فايل خود را بنويسيد.


3. WMI Consumers
Consumers بالاترين لايه است. Consumers مي تواند اسکريپت، نرم افزار مديريتي ، نرم افزار تحت وب و ... باشد که به منابع اطلاعاتي WMI Infrastructure دسترسي داشته و مديريت کند.

API

تعريف API
API به معني رابط برنامه کاربردي به مجموعه اي از دستورات گفته مي شود، که رابط بين برنامه ها و پردازنده است.
 معني ديگري که در منابع فارسي گفته شده است: API مجموعه دستوراتي است براي برقراري ارتباط بين اجزاي سيستم عامل و برنامه ها.
API در سيستم عامل ها
سيستم عامل هاي مختلف، API هاي مختلف را ارائه ميدهند و به همين خاطر است که وقتي برنامه نويس ، برنامه خود را با API ويندوز پايه گذاري مي کند، آن برنامه يا نرم افزار در سيستم عامل لينوکس قابليت اجرايي ندارد.
API  سيستم عامل ويندوز Windows API ، لينوکس Xlib و مک Mac OS X) Cocoa) است.

اگر يک جستجوي کوچک درمورد Api ها به زبان فارسي انجام داده باشيد، مي بينيد که در بيشتر مطالبي که درمورد API نوشته شده است، گفته شده است که Mac از Carbon استفاده مي کند.Cocoa يک فريم ورک جديدتر از Carbonاست. تفاوت اين دو را به اين صورت مي توان گفت که Cocoa يک لايه بالاتر از Carbon است و همچنين Carbon  يک فريم ورک به صورت procedural  و   Cocoa‌ يک فريم ورک به صورت object-oriented است. چون ادامه اين مبحث در قالب کلي اين وبلاگ نمي گنجد، بيشتر از اين درباره اين دو نوع API‌صحبت نمي کنم و شما نيز براي اطلاع بيشتر از تفاوت اين دو مي تونيد عبارت " Cocoa vs. Carbon" را جستجو کنيد.

Windows API
Windows API شامل هزاران function ، structure و constant است که ما مي توانيم آن ها را در برنامه تعريف و از آن ها استفاده کنيم. براي اينکه بتوانيم از اين توابع استفاده کنيم، ابتدا بايد آن ها را معرفي کنيم و چون اين توابع با زبان C نوشته شده اند، اين کار کمي پيچيده خواهد بود. در ادامه توضيح داده خواهد شد که زبان هاي برنامه نويسي چگونه اين توابع را در اختيار برنامه نويسان قرار خواهند داد.

API ها را مي توان به سه دسته تقسيم کرد:
•    Kernel
نام کتابخانه آن KERNEL32.DLL است و. قابليت هايي را که سيستم عامل به ما مي دهد را در بر دارد:
-Process loading.
-Context switching.
-File I/O.
-Memory management.

•    User
نام کتابخانه آن USER32.DLL است و براي کنترل نماي کاربري استفاده مي شود:
-Windows
-Menus
-Dialog Boxes
-Icons etc.,

•    GDI
نام کتابخانه آن GDI32.dll است. اين کتابخانه قابليت ايجاد خروجي هاي گرافيکي مانند پنجره ها، منوها و dialog box ها را ارائه ميدهد.
براي اطلاع از تقسيم بندي توابع و نام کتابخانه ها به لينک زير مراجعه کنيد
API و برنامه نويسي
شما قبل از اينکه چگونگي استفاده توابع API را ياد بگيريد، بايد با مفهوم هاي مختلفي مثل شيوه هاي برنامه نويسي managed/unmanaged/Native ، کدهاي safe/unsafe و ... آشنايي داشته باشيد.
پيشتر مطلبي درمورد شيوه برنامه نويسي Native و Managed در اين وبلاگ قرار داده شده بود که در اين آدرس قابل دسترس است.

اکثر زبان هاي پيشرفته برنامه نويسي اين امکان را به برنامه نويس ميدهند که از API ها استفاده کنند. در زبان هاي Native که به صورت مستقيم با API سرو کار دارند مي توان به زبان هاي ++C و Delphi و در زبان هاي Managed به #C و VB.Net اشاره کرد. در ++C دستورات در فريم ورک MFC، Microsoft Foundation Class جاسازي شده است و به همين خاطر ديگر نياز نيست که برنامه نويس تابع ها را تعريف کند.
در ادامه يک مثال از Delphi براي شما آورده شده است و نشان داده شده است که چگونه دلفي توابع API را در دل خود جاي داده است.
محيط دلفي را اجرا کرده ويک پروژه Console ايجاد کنيد و آن را به فرم زير تغيير دهيد.

program TestConsoleDateTime;

{$APPTYPE CONSOLE}

uses
  SysUtils,Windows;

var SystemTime:TSystemTime;
begin
  GetLocalTime(SystemTime);
  Writeln(
  IntToStr(SystemTime.wHour)+':'
  + IntToStr(SystemTime.wMinute) 
  +':'+ IntToStr(SystemTime.wSecond));

  Readln;
end.

اين برنامه ساعت سيستم را نمايش ميدهد. ما در کد بالا به کمک تابع GetLocalTime توانستيم ساعت جاري را بدست بياوريم. حال اگر کليد Ctrl را نگه داريد و روي کد GetLocalTime  در برنامه کليک کنيد، محيط دلفي شما را به صفحه جديدي (کد يونيت Windows)هدايت خواهد کرد. در صفحه جديد کد زير به نمايش در خواهد آمد

procedure GetLocalTime; external kernel32 name 'GetLocalTime';


در اينجا براي دلفي تعريف شده است که با فراخواني پروسيجر GetLocalTime ، تابع GetLocalTime در kernel32.dll فراخواني شود.
همانطور که ديديد دستورات API در داخل دستورات دلفي قرار داده شده اند و ما بدون اينکه آن ها را تعريف کنيم،  و يا از ساختار آن با خبر باشيم مي توانيم از آن ها استفاده کنيم. البته دانستن ساختار و استفاده از کد هاي API براي برنامه نويساني که از زبان هاي برنامه نويسي Native استفاده مي کنند اهميت بالايي دارد.

API در #C
براي استفاده از توابع API در برنامه خود، ابتدا بايد با ساختار توابع آشنا باشيم. به عنوان مثال براي تابع GetLocalTime در MSDN ساختار زير تعريف شده است
procedure void WINAPI GetLocalTime(
  __out  LPSYSTEMTIME lpSystemTime
);

اين تابع خروجي ندارد و ورودي آن (lpSystemTime  ) از نوع SystemTime است که بعد از فراخواني تابع مقداردهي مي شود.
در اين لينک ميتوانيد ساختار SystemTime را مشاهده کنيد.
براي استفاده از تابع بايد ابتدا namespace زير را به Use ها اضافه کنيم
System.Runtime.InteropServices
براي استفاده از يک تابع بايد آن را به برنامه معرفي کنيم که براي تابع GetLocalTime به صورت زير است
[DllImport("kernel32.dll")]
public static extern void GetLocalTime(out Win32.DateTime.SystemTime systemTime);
DllImport براي  فراخواني کتابخانه هاي مديريت نشده (Unmanaged) به کار برده مي شود. در اينجا کتابخانه kernel32.dll معرفي شده است.
extern براي فراخواني توابعي که در خارج اجرا مي شوند به کار مي رود که در اين مورد حتما بايد با واژه static همراه باشد. اين واژه معمولا در هنگامي که از DllImport استفاده مي شود و قرار است کد Unmanaged اجرا شود به کار ميرود.
SystemTime يک ساختار است. که به صورت زير در برنامه تعريف ميکنيم
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
 public ushort Year;
 public ushort Month;
 public ushort DayOfWeek;
 public ushort Day;
 public ushort Hour;
 public ushort Minute;
 public ushort Second;
 public ushort Milliseconds;
}

حال براي فراخواني تابع به روش زير عمل مي کنيم:

SystemTime sysTime;
GetLocalTime(out sysTime);
MessageBox.Show(System.String.Format("{0}:{1}:{2}", sysTime.Hour, sysTime.Minute,sysTime.Second));

در خط اول متغير sysTime از نوع SystemTime تعريف شده است. در خط دوم تابع GetLocalTime فراخواني شده است که در آن متغير sysTime به عنوان آرگومان خروجي داده شده است و در خط سوم تاريخ نمايش داده شده است.

براي آشنايي بيشتر يک نمونه برنامه در لينک زير قرار داده شده است
لينک يک  Win32API.7z
يا

لينک دو Win32API.7z

تصويري از نماي برنامه

Native vs. Managed

,در اين پست سعي کردم که يک نگاه کلي به کد هاي Native و Managed بوجود بيارم. براي اطلاعات بيشتر و دقيق تر مي تونيد به منابعي در آخر پست ذکر شده مراجعه کنيد.


Managed
کد Managed به کدي که کامپايلر دات نت توليد مي کند گفته مي شود. وقتي شما يک برنامه را در دات نت کامپايل مي کنيد، اين کد به Intermediate Language  تبديل مي شود. IL کد بين زبان سطح بالا مثل #C و کد زبان ماشين است. IL در فايل هاي assembly ذخيره مي شود، که به تنهايي قابليت اجرا ندارند. Common Language Runtime وظيفه اجراي اسمبلي ها را به عهده دارد. يعني اسمبلي در CLR اجرا ميشود. بعد از اين که CLR ، صحت IL را تاييد کرد، Just In Time  را فراخواني مي کند تا کد IL را به کد ماشين تبديل کند.
وقتي CLR اسمبلي را اجرا مي کند سرويس هاي مختلفي را براي آن در نظر مي گيرد، مانند: امنيت ، مديريت حافظه و رم و ...
وجود CLR اين امکان را ميدهد که کد IL بر روي هر سيستم عاملي که داراي CLR است به اجرا درآيد.


زبان هايي مثل  C#، VB.Net، C++.Net کد هاي Managed توليد مي کنند.
جاوا نيز يکي ديگر از زبان هايي است که Managed هستند. در اين زبان bytecode ها توسط  Java Virtual Machine  اجرا مي شوند.

مزايا و معايب:
مزايا:
    Portable – runs on any platform with a CLR
    Easier to write
معايب
    Can run slower
    May require more system resources
Native
کد هاي Native برخلاف کد هاي Managed به کد ماشين تبديل ميشوند و توسط پردازنده اجرا ميشوند و نيازي به Runtime براي اجرا ندارند.
وقتي به شيوه Native کد نويسي مي کنيد، بعضي از قابليت هايي که Managed ارائه ميدهد را از دست مي دهيد، مانند مديريت حافظه. به عنوان مثال بعد از اينکه يک Object  را در برنامه بوجود آورديد، بايد آن را Free کنيد، که اين عمل در دات نت به وسيله Garbage Collection انجام مي شود.
يکي از معايب ديگري که کد Native نسبت به Managed داراست، مسئله اجرا در Platform هاي مختلف است. به عنوان مثال وقتي شما برنامه را در ويندوز کامپايل مي کنيد ، کد توليد شده (EXE)  فقط در ويندوز اجرا خواهد شد.
البته اين بدان معني نيست که شما با کد Native نميتوانيد Cross-Platform برنامه بنويسيد. هم اکنون فريم ورک هايي وجود دارند که وقتي شما کد را مينويسيد، کد شما را به API سيستم عامل هاي ديگر تبديل مي کنند.


زبان هايي مثل ++C  و Delphi کد هاي Native  توليد مي کنند.
مزايا و معايب
مزايا:
    Fast performance
    Smallest footprint

معايب
    More complex to write
    Dependent on specific platform
managed data
Managed Data داده هايي هستند که توسط GarbageCollection  مديريت مي شوند.
وقتي شما با #C که کد Managed توليد مي کند برنامه نويسي مي کنيد، مصرف حافظه براي داده ها به وسيله  GarbageCollection   مديريت مي شوند. اما وقتي شما با  ++C در دات نت برنامه نويسي مي کنيد، دات نت اين اختيار را به شما مي دهد که حافظه را CLR با GarbageCollection   مديريت کند يا خود شما مديريت حافظه را در دست بگيريد. در حالت پيش فرض مديريت حافظه به عهده شماست و براي اينکه مديريت را به دات نت بسپريد ، بايد از کلمه کليدي gc__ استفاده کنيد. براي درک بهتر به مثال زير توجه کنيد:

Unmanaged Data
class Ta
{
 private:
 int a;
}

Managed Data
__gc class Ta
{
 private:
 int a;
}
منابعي که براي اطلاعات بيشتر مي توانيد به آن ها مراجعه کنيد:


جستجو