Vấn đề tôi không làm được trong VB?

Liên hệ QC

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia
13/6/06
Bài viết
4,652
Được thích
10,140
Giới tính
Nam
Nghề nghiệp
Giáo viên, CEO tại Bluesofts
Xin lỗi mọi người về cách đặt tên. Vì chưa tìm được cách đặt thích hợp nên tạm để như vậy.

Có các vấn đề sau tôi muốn làm với VB:
Phép gán hàm và thủ tục (Sub1=Sub2; Func1=Func2).
Đối số trong hàm hay thủ tục có thể là một hàm hoặc thủ tục - Callback Function.
Ép kiểu giá tri - Typecast.

Đây là những vấn đề tôi không thể làm được trên VB. Nếu làm được mong các bạn hướng dẫn cho tôi?
 
AddressOf and Callbacks:
The "AddressOf" operator is all about callbacks. "But what is a call back?" you ask. A callback is the Windows equivalent of a VB "Event". In fact, VB events (on a very low level) are just about always triggered by callback functions that catch the original event in the form of a Windows Message. Callbacks are most often seen within the Win32 API (and other C/C++ code) where notification of user and/or Windows activity is required or desired within your application. You don't see callbacks within VB much because VB handles messaging and notification via "Events", which are much easier and safer to deal with compared to callbacks and all that goes into them.
Lets say that you wanted to receive notification of EVERY message that Windows is sending to a Form within your project (even ones that you'd never use), along with a few custom messages that may be sent to your Form via some other API call(s). What you would do is setup a callback function that is recognized by Windows ("WindowProc") and then tell Windows (via the "SetWindowLong" API) to send all of it's messages meant for your Form to your callback function instead, so you can inspect them and/or react to them... and then send them on their way (via the "CallWindowProc" API). Doing this is called "Sub-Classing" and is a very powerful (but at the same time very dangerous) technique that you can use to redraw your Form, it's menus, and/or it's contents in a custom manner (or whatever you want to do with your Form).
There two draw-backs to using "AddressOf":
1) You can only retrieve the address to a function or sub (public or private) contained within a Standard VB Module. There's no way around this.
2) It can only be called as part of a parameter list to a function or sub. The way to get around it is like this:
Option Explicit

Public Sub Main()
Dim lngProcAddress As Long
lngProcAddress = GetProcAddress(AddressOf WindowProc)
End Sub

Public Function GetProcAddress(ByVal lngAddressOf As Long) As Long
GetProcAddress = lngAddressOf
End Function

Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
' < YOUR CODE GOES HERE >
End Function
You'll notice that we pass the "AddressOf" with the name of the function we want to get the address (memory pointer) of to the function "GetProcAddress" which simply returns back that value. Simple concept and is very effective. The addresses of functions and subs doesn't change so you could store the address of the functions and subs you want to reference this way so you don't have to repeatedly call AddressOf, etc.
"So lets see it in action!" you say... OK!
Here's an example of "sub-classing" as mentioned above:
Option Explicit

Private Const GWL_WNDPROC = (-4)
Private lngPrevProc As Long
Private lngHWND As Long

Private Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

' This is the CALLBACK function that receives the messages for the specified hWnd
Private Function WindowProc(ByVal hWnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
' Display the messages and their information in the IMEDIATE window
' NOTE: You can find out what messages are being passed by comparing the value of
' "uMsg" to Windows Messages (WM_*) constant values defined in the WINUSER.H file
Debug.Print _
"hWnd=" & hWnd & ", uMsg=" & uMsg & ", wParam=" & wParam & ", lParam=" & lParam

' Forward on the messages to where they were originally supposed to go. This MUST
' here or the window will become unresponsive because it will stop recieving messages
WindowProc = CallWindowProc(lngPrevProc, hWnd, uMsg, wParam, lParam)
End Function

' This function starts a new sub-classing
Public Function Subclass_Start(ByVal hWnd As Long) As Boolean
' Stop any previous sub-class
If Subclass_Stop = False Then Exit Function
' Attempt to start a new sub-class
lngPrevProc = SetWindowLong(hWnd, GWL_WNDPROC,
AddressOf WindowProc)
If lngPrevProc <> 0 Then
lngHWND = hWnd
Subclass_Start = True
End If
End Function

' This function stops any existing sub-classing
Public Function Subclass_Stop() As Boolean
' If no previous sub-class was started, just exit
If lngPrevProc = 0 Or lngHWND = 0 Then
Subclass_Stop = True
Else
' Set the message handling procedure back to what it originally was
If SetWindowLong(lngHWND, GWL_WNDPROC, lngPrevProc) <> 0 Then
Subclass_Stop = True
End If
End If
' Clear the variables used
lngPrevProc = 0
lngHWND = 0
End Function
Option Explicit

Private Sub Form_Load()
Subclass_Start Me.hWnd
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Subclass_Stop
End Sub

Here's an example of "enumeration", which is a VERY popular way for Windows to give you back information about "information lists" (like a list of all windows, a list of all the objects on a window, a list of all the installed fonts, etc):
Option Explicit

Private lngWinHandle() As Long
Private lngWinHandleCount As Long

Private Declare Function EnumWindows Lib "USER32.DLL" (ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Long

' This is the CALLBACK that enumerates through all windows in the current desktop
Private Function EnumWindowsProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
' Incrament the array of window handles
lngWinHandleCount = lngWinHandleCount + 1
ReDim Preserve lngWinHandle(1 To lngWinHandleCount) As Long
' Add the information to the array
lngWinHandle(lngWinHandleCount) = hWnd
' Tell the function to keep going
EnumWindowsProc = 1
End Function

Public Function GetAllWindows(ByRef Return_Handles() As Long, _
Optional ByRef Return_WinCount As Long) As Boolean
' Clear any previous information
Erase lngWinHandle
lngWinHandleCount = 0
' Start enumerating through the windows
If EnumWindows(
AddressOf EnumWindowsProc, 0) <> 0 Then
Return_Handles = lngWinHandle
Return_WinCount = lngWinHandleCount
GetAllWindows = True
End If
Erase lngWinHandle
lngWinHandleCount = 0
End Function
Option Explicit
Private Sub Form_Load()
Dim lngWindows() As Long
Dim lngWindowsCount As Long
Dim lngCounter As Long
Dim strWindows As String
If GetAllWindows(lngWindows, lngWindowsCount) = True Then
If lngWindowsCount > 0 Then
For lngCounter = 1 To lngWindowsCount
strWindows = strWindows & " " & lngWindows(lngCounter) & Chr(13)
Next
End If
Me.AutoRedraw = True
Me.Print strWindows
End If
Erase lngWindows
End Sub
 
Đây là 1 vài lời nói về VB:

....


For example, when you open VB and add a standard "Form" to your project, there's A LOT that goes into putting that form on the screen when you hit "F5" to execute the program and simply display the form. You have to call the "CreateWindow" to actually create the Form and give it it's properties that make up it's interface. You then have to modify it's text font, forecolor, backcolor, device context, etc. by calling various Win32 API's. Lastly, you have to hook into the Windows messages that are being sent to the newly created form by subclassing it and then catching and processing each Windows messages properly via a "WindowProc" callback function. More complex interfaces require more complex object creation and handling functionality to be programmed into the form. C and C++ programmers actually have to create all that object creation, message handling, and object destruction code by hand (or have a template of it generated).



Visual Basic's ability to do the "basics" for you like this is a powerful thing to programmers who know how to correctly use VB as a development tool, but also puts a lot of power into the hands of people that don't know much about programming. Visual Basic is mocked by C/C++ programmers because of this. They say, "Anyone can develop with VB, but it takes a real programmer to develop with C/C++." I say that the SMART programmer chooses Visual Basic because VB eliminates potential bugs in your object creation, message handling, and object destruction routines, VB offers easier and quicker handling of Windows events, VB gives you a more robust interface capabilities, VB gives you easier access to COM objects and third party controls, VB is easier to read because it is very close to reading English where C/C++ is VERY cryptic, VB allows you easy access to the Win32 API (which gives the programmer the ability to tap into the power of Windows), and on top of ALL THAT... Visual Basic has the ability to hook into the power and speed of C/C++ via components, libraries, and other code written in C/C++. Heh... where's the bragging rights now?
smile.gif


Here's the thing though... even VB programmers that have been in the industry for years don't realize the real power of VB because they don't grasp (or realize) a few key concepts and functionalities that VB offers. These concepts aren't taught, or at least are not emphasized the way they should, so I call them "VB SECRETS".
....


Nhưng mà Tuân ơi, mấy vụ này thực sự chả để làm gì đâu. Tập chung vào chất lượng và tính năng của phần mềm đi. Độ dày và chiều sâu, tính mở của tài liệu thiết kế, tài liệu nghiệp vụ, tài liệu sử dụng, tính năng thuận tiện của người dùng, v.v....
 
Thêm nữa, Google 1 lúc ra cả đống những nguồn tài liệu, code dạng này.
 
TuanVNUNI đã viết:
Phép gán hàm và thủ tục (Sub1=Sub2; Func1=Func2).
1. Mục tiêu để làm gì??? Có cần thiết trong các ứng dụng mà Tuân đang làm ko? :-=

2. Trong ngôn ngữ kia (nếu có đọc sách) thì tiếng anh họ dùng từ gì để nói lên "phép gán hàm, gán thủ tục" ???

Nếu biết được những từ tiếng anh đó, chỉ cần Google với câu "XYZ in Visual Basic" là ra hết (ví dụ: Assign function to function pointer in Visual Basic). Chủ yếu là cần dịch được cái từ tiếng anh XYZ đó là gì thôi.

Mà nói chung. Mấy vấn đề này có thể chỉ là 1 cách viết ngắn ngọn nào đó trong ngôn ngữ khác. Ở VB thì có thể thể hiện bằng cách khác tường minh hơn chứ ko phải là ko làm được mục tiêu của từng dòng lệnh. (Mỗi ngôn ngữ có 1 cách viết code khác nhau mà).

Một điều khác luôn nhớ rằng: Visual Basic hỗ trợ viết APIs nên nó sẽ dùng tất cả các APIs của Windows.

Chỉ có một điều Tuân chưa nõi rõ ra là Visual Basic ... is not truly Object Oriented Programming như VC++ (đó mới là điều đáng nói thì lại ko nêu ra :)) mặc dù Polymorphism, Inheritance, và rất nhiều khái niệm về OOP nữa... đều có thể làm được trên VB.

Nhưng vấn đề đó không quan trọng lắm vì VB vẫn giải quyết được tương đối nhiều việc cho các ứng dụng trong doanh nghiệp. Nhưng giờ ai còn làm VB, VC, Delphi nữa... chuyển lên .NET đi cho Hiện đại, cho nhanh! Cả thế giới đang tiến lên dùng .NET ầm ầm rồi mà giờ vẫn còn chuyện VB này nọ :-=

Matt Curland's new book, "Advanced Visual Basic 6: Power Techniques for Everyday Programs", shows many advanced techniques for using function pointers in VB without resorting to C.

Mà thôi, tôi đã nói là không viết nữa rồi mà Tuân vẫn cứ lôi mấy vấn đề này ra làm gì. Vừa rồi gặp trục trặc to về chuyện thức khuya này đấy. :-=
 
Lần chỉnh sửa cuối:
Cảm ơn anh! Các kỹ thuật Subclass,Hook window cùng các kỹ thuật lập trình API em đã đọc nhiều tài liệu trên mạng và cũng đã làm thành công khi tạo các control, hook các MsgBox , điều khiển from,...Trên các ngôn ngữ khác em có thể lập trình ra hàm như kiểu hàm EnumWindows, hàm này có đối số là một con trỏ hàm. Em muốn lập trình trên VB mà tạo ra loại hàm giống như hàm EnumWindows. Đối với em nó rất quan trọng vì ứng dụng chính hiện nay của em được làm bằng VB và VBA. Nếu làm được sẽ giúp rất nhiều trong xử lý của chương trình.

Tạo hàm có đối số là con trỏ hàm

Em có một ví dụ đơn giản thế này nhưng không thể làm được bằng VB. Tạo một hàm EnumArray có đói số là một hàm.

Mã:
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Sub Main()
Dim Arr
Arr = Array(1, 2, 3, 4, 5)
EnumArray Arr, AddressOf GetVar
[COLOR="Green"]'EnumArray Arr, GetProcAddress(AddressOf EnumArray)[/COLOR]
End Sub

Public Function GetProcAddress(ByVal lngAddressOf As Long) As Long
    GetProcAddress = lngAddressOf
End Function

Public Function EnumArray(Arr As Variant, ByVal lpFunc As Long) As Long
[COLOR="Green"]'lpFunc là tham số nhận AddressOf GetVar[/COLOR]
Dim Index As Long

Index = LBound(Arr, 1) - 1
For Each Varg In Arr
    Index = Index + 1
    lpFunc Index, Varg '->LỖI (đương nhiên)
    CallWindowProc lpFunc,0,Index,Varg,0& '-->LỖI
    [COLOR="Red"]'Cách sử dụng hàm lpFunc như thế nào???[/COLOR]
    'Nếu lpFunc là một hàm có cấu trúc tham số là "(lngPrevProc, hWnd, uMsg, wParam, lParam)" thì có thể sử dụng các gọi dưới đây của hàm CallWindowProc

Next

EnumArray = UBound(Arr, 1)
End Function

Function GetVar(ByVal Index As Long, Value As Variant)
    MsgBox Value, , Index
End Function

Các tạo ra hàm trên, với các ngôn ngữ khác như em biết là Delphi,C++ thì không khó gì cả. Trong VB6, nếu không viết được hàm dạng trên thì người ta vẫn làm bằng cách khác để đạt được mục đích của mình nhưng, nếu thế rõ ràng (về ngôn ngữ) VB không làm được.

Còn vấn đề lập trình đối tượng, tạo lớp Class thừa kế lớp mẹ

Em tạm thể hiện mục đích của mình với ví dụ dưới đây.
Mã:
'---------------------------------

Class1 = Object
   DoSomething
End

Class2 = Object(Class1) 'Tạo trên lớp Class1 - thừa kế lớp Class1
   DoSomething Override
End

'---------------------------------

Sub Class1.DoSomething
    MsgBox "Class1"
End Sub

Sub Class2.DoSomething
   [B]Inherited[/B] 'Thừa kế việc làm của Class1.DoSomething
   '//Do something...
    MsgBox "Class2"
End Sub

Trong VB6 em không làm được điều trên. Nếu anh biết thì có thể cho một ví dụ đơn giản không?



Vấn đề làm ứng dụng trên .NET em cũng đã nghĩ nhiều mà chưa ra được quyết định trong thời điểm này vì chiến lược sản phẩm của mình. Nhưng phải thừa nhận .NET platform là một cuộc cách mạng về công nghệ! Em vẫn đang âm thầm tìm hiểu về .NET platform.
Mặc dù thế giới công nghệ đang chuyển dịch sang .NET nhưng không phải chuyển hẳn. MS vẫn duy trì đồng thời hai nền tảng công nghệ "WIN32 platform" và ".NET platform". Ngay cả với Office2007 (một trong những cần câu cơm chính của MS) cũng được làm trên nền tảng WIN32 platform, ngôn ngữ cũ như VB6 vẫn được dùng để tạo ra các Macro trong Office nên nó vẫn rất cần thiết với mọi người. Tùy vào đối tượng và công việc và còn tùy vào chiến lược của mỗi sản phẩm mà người ta sẽ viết ứng dụng trên WIN32 hay .NET.
 
Thêm 1 chút về cách lấy địa chỉ của 1 thủ tục trong 1 DLL
Mã:
'Return the address of the specified DLL/procedure
Private Function zFnAddr(ByVal sDLL As String, ByVal sProc As String, ByVal asUnicode As Boolean) As Long
  If asUnicode Then
    zFnAddr = GetProcAddress(GetModuleHandleW(StrPtr(sDLL)), sProc)         'Get the specified procedure address
  Else
    zFnAddr = GetProcAddress(GetModuleHandleA(sDLL), sProc)                 'Get the specified procedure address
  End If
  Debug.Assert zFnAddr                                                      'In the IDE, validate that the procedure address was located
  ' ^^ FYI VB5 users. Search for zFnAddr("vba6", "EbMode") and replace with zFnAddr("vba5", "EbMode")
End Function

'Return the address of the specified ordinal method on the oCallback object, 1 = last private method, 2 = second last private method, etc
Private Function zAddressOf(ByVal oCallback As Object, ByVal nOrdinal As Long) As Long
    ' Note: used both in subclassing and hooking routines
  Dim bSub  As Byte                                                         'Value we expect to find pointed at by a vTable method entry
  Dim bVal  As Byte
  Dim nAddr As Long                                                         'Address of the vTable
  Dim i     As Long                                                         'Loop index
  Dim J     As Long                                                         'Loop limit
  
  RtlMoveMemory VarPtr(nAddr), ObjPtr(oCallback), 4                         'Get the address of the callback object's instance
  If Not zProbe(nAddr + &H1C, i, bSub) Then                                 'Probe for a Class method
    If Not zProbe(nAddr + &H6F8, i, bSub) Then                              'Probe for a Form method
      ' \\LaVolpe - Added propertypage offset
      If Not zProbe(nAddr + &H710, i, bSub) Then                            'Probe for a PropertyPage method
        If Not zProbe(nAddr + &H7A4, i, bSub) Then                          'Probe for a UserControl method
            Exit Function                                                   'Bail...
        End If
      End If
    End If
  End If
  
  i = i + 4                                                                 'Bump to the next entry
  J = i + 1024                                                              'Set a reasonable limit, scan 256 vTable entries
  Do While i < J
    RtlMoveMemory VarPtr(nAddr), i, 4                                       'Get the address stored in this vTable entry
    
    If IsBadCodePtr(nAddr) Then                                             'Is the entry an invalid code address?
      RtlMoveMemory VarPtr(zAddressOf), i - (nOrdinal * 4), 4               'Return the specified vTable entry address
      Exit Do                                                               'Bad method signature, quit loop
    End If

    RtlMoveMemory VarPtr(bVal), nAddr, 1                                    'Get the byte pointed to by the vTable entry
    If bVal <> bSub Then                                                    'If the byte doesn't match the expected value...
      RtlMoveMemory VarPtr(zAddressOf), i - (nOrdinal * 4), 4               'Return the specified vTable entry address
      Exit Do                                                               'Bad method signature, quit loop
    End If
    
    i = i + 4                                                               'Next vTable entry
  Loop
End Function

And how to use:

Mã:
....
If bIsAPIwindow Then                                                    'If user wants DestroyWindow sent should IDE end
          z_Sc(IDX_DW) = zFnAddr("user32", "DestroyWindow", bUnicode)
      End If
      z_Sc(IDX_FREE) = zFnAddr("kernel32", "VirtualFree", bUnicode)           'Store the VirtualFree function address in the thunk data
      z_Sc(IDX_BADPTR) = zFnAddr("kernel32", "IsBadCodePtr", bUnicode)        'Store the IsBadCodePtr function address in the thunk data
      z_Sc(IDX_ST) = zFnAddr("user32", "SetTimer", bUnicode)                  'Store the SetTimer function address in the thunk data
      z_Sc(IDX_KT) = zFnAddr("user32", "KillTimer", bUnicode)                 'Store the KillTimer function address in the thunk data
...
Ví dụ về việc Load 1 structure vào mảng:

Mã:
Public Function LoadArray() As Boolean
'*/ load data structure

    If Not m_bVirtualMode Then
        Set c_PtrMem = New Collection
        '/* initialize local struct
        ReDim m_cGridItem(0)
        '/* copy the structure from the pointer
[COLOR=Blue][B]        CopyMemory ByVal VarPtrArray(m_cGridItem), m_lStrctPtr, 4&
        c_PtrMem.Add m_lStrctPtr, "m_cGridItem"[/B][/COLOR]
        m_lRowCount = UBound(m_cGridItem) + 1
        LoadArray = True
    End If

End Function

Còn vấn đề EnumArray, hãy chuyển lên những gì tốt hơn, dễ dàng hơn cho hiệu quả như:

Mã:
create a VB 2003 project. add a class
 Public Class Foo
    Public Enum MyEnum
        FirstElement
        NextElement
        NextElement2
        NextElement3
        NextElement4
    End Enum
     Private _EnumArray As New ArrayList
    Public Property EnumArray() As ArrayList
        Get
            Return _EnumArray
        End Get
        Set(ByVal Value As ArrayList)
            _EnumArray = Value
        End Set
    End Property
End Class

  
 on another class create a method and add this code to the method:
         Dim x As New Foo
        x.EnumArray.Add(Foo.MyEnum.FirstElement)
TuanVNUNI đã viết:
Còn vấn đề lập trình đối tượng, tạo lớp Class thừa kế lớp mẹ

Em tạm thể hiện mục đích của mình với ví dụ dưới đây.
Mã:
'---------------------------------

Class1 = Object
   DoSomething
End

Class2 = Object(Class1) 'Tạo trên lớp Class1 - thừa kế lớp Class1
   DoSomething Override
End

'---------------------------------

Sub Class1.DoSomething
    MsgBox "Class1"
End Sub

Sub Class2.DoSomething
   [B]Inherited[/B] 'Thừa kế việc làm của Class1.DoSomething
   '//Do something...
    MsgBox "Class2"
End Sub
Trong VB6 em không làm được điều trên. Nếu anh biết thì có thể cho một ví dụ đơn giản không?
Về vấn đề thừa kế 1 đối tượng trong VB, Tuân tìm hiểu thêm về khái niệm Implements trong VB nhé. Mình ko thể tìm hộ về ví dụ này được.

Hơn nữa, kể cả việc VB có hỗ trợ Inheritance, Polymorphism,... đi chăng nữa thì tôi cũng xin nhắc lại là VB is not truly OOP language nên đừng thắc mắc về chuyện OOP nữa.

Vấn đề nói đến dotNET, ý tôi muốn nói là giờ ko còn là lúc tìm hiểu mấy thứ để so sánh giữa Delphi, VC, VB nữa vì không còn ai làm công việc đó cả. Hãy đưa tính hiệu quả lên trên cao. Có rất nhiều ứng dụng trên thế giới để làm cái to hơn cái A-Excel mà Tuân đang viết rất nhiều bằng VB mà KHÔNG CẦN PHẢI SỬ DỤNG NHỮNG THỨ mà Tuân đang hỏi ở trên. Đó là ý chính mà mình muốn nói ở đây (và là nguyên nhân để nói ko cần phải so sánh mấy ngôn ngữ đó làm gì). Và mình ko muốn đưa ra những vấn đề so sánh giữa các ngôn ngữ lập trình là vì Ý ĐÓ chứ không phải là nói VB làm như các ngôn ngữ khác (chắc Tuân vẫn đang nhầm cách mà mình muốn nói). Về sau, người ta lập trình ko còn khó khăn nữa. Hãy thử download file video demo này để xem tương lai chúng ta có thể viết ứng dụng như thế nào trên công cụ lập trình mới này.

Nhưng mà Tuân ơi, mấy vụ này thực sự chả để làm gì đâu. Tập chung vào chất lượng và tính năng của phần mềm đi. Độ dày và chiều sâu, tính mở của tài liệu thiết kế, tài liệu nghiệp vụ, tài liệu sử dụng, tính năng thuận tiện của người dùng, v.v....

Vậy thế thôi nhé, tớ ko tham gia vụ này nữa. (Vì tính chuyên nghiệp về lập trình lại ko thể hiện ở mấy cái này)

Attached file là hình ảnh 1 cái Grid viết trên VB với 10 triệu items được load trong có 0,0015s. Cái Grid này vừa đẹp, hỗ trợ rất nhiều theme hiện đại, sử dụng công nghệ Virtual Grid rất mạnh (hơn tất cả các Grid nổi tiếng khác có trên thị trường có sử dụng công nghệ Virtual Grid), Unicode Support. Còn rất nhiều những người ở tầm đó họ làm ra cái khác biệt vẫn chỉ bằng VB mà thôi.

Nhưng với tôi, mấy cái đó chả nói lên được gì nhiều. Chỉ làm cho mấy ông giám đốc công ty PM họ cười thôi. Họ bảo, đem cái đó ra thị trường mà cạnh tranh.
 

File đính kèm

  • 10tr_records.jpg
    10tr_records.jpg
    91.9 KB · Đọc: 106
Lần chỉnh sửa cuối:
Cảm ơn anh!
Em chỉ muốn hỏi để biết về khả năng của ngôn ngữ mà thôi chứ không có ý đi sâu về kỹ thuật. Theo đoạn code của anh, em chưa biết cái vụ EnumArray của em có làm được trên VB6 không? Nếu có thì nó cũng là thủ thuật rồi.

Về tính hiệu quả mà từ lâu em chỉ dùng ngôn ngữ VB6 khi viết các Macro trong Office mà thôi (vì không có lựa chọn khác). Hiện nay em đang dùng Delphi (cho phép lập trình trên WIN32 và .NET) để làm các ứng dụng, như chương trình Kiểm phiếu theo đặt hàng em chỉ làm chưa đến 1 tuần là xong v1.0 và cho dùng thử. Khi nghiên cứu .NET, em thấy Delphi cũng gần như vậy về cách tiếp cận đối tượng có lẽ là do ảnh hưởng của Anders Hejlsberg.
 
Lần chỉnh sửa cuối:
các bác cao thủ quá, em faỉ học nữa để hiểu vấn đề
 
Web KT
Back
Top Bottom