In C/C++, a long integer is a four-byte integer value. If you study the valid values for the 'vt' member of a VARIANT (type of variant), you'll notice that the values for four-byte integer are 'VT_I4' (signed four-byte integer) and 'VT_UI4' (unsigned four-byte integer). I'm not sure how VB and C# let you set the variant type, but C++ has a '_variant_t' class that wraps VARIANT and has assignment operators that set it for you, or you can simply set it yourself. In C++, a long integer variable is declared as: long lMyVariable = 0 ; In IDL, you use the "long" keyword, as in these examples: [id(65), helpstring("Load an account from the database for a specific EMS/ambulance run.")] HRESULT LoadForRun( [in] long lAmbRunID, [out] long* plAccountID) ; [id(43), helpstring("Get the first condition indicator for an EMS/ambulance run.")] HRESULT GetFirstConditionIndicator( [out, string] BSTR* pbstrConditionIndicator, [out] long* plConditionIndicatorID) ; Notice that the parameters are of type "BSTR" and "long" (the asterisk, of course, means that a given parameter is actually a pointer to a BSTR or a long). Scott :)
Scott Holt
Posts
-
dual interface -
dual interfaceWell, actually, I never said that. You are absolutely correct - you CAN represent BSTR and long integer in a VARIANT. BUT...you don't have to. You can pass a BSTR (or long integer) between a COM client and a COM server without first putting it into a VARIANT. I think a lot of COM programmers, to keep things simple and consistent, probably just use VARIANTs for everything. Scott :)
-
dual interfaceYes, the VARIANT data type IS "automation-compatible". In fact, the last time I checked, all parameters to the IDispatch interface HAD to be VARIANT. Thus, your phrase "means if a data type could be represented by VARIANT, it is automation compatible" is TRUE. I am not sure where you found something that indicates that a VARIANT is not an ole automation data type, but I think what you found is in error. There are other data types that can be marshalled between a COM client and a COM server, but you must use VARIANT with the IDispatch interface. Now, in the early days, "automation" was referred to as "OLE automation", where the acronym "OLE" meant "Object Linking and Embedding". This was a phrase that Microsoft used to describe its early techonologies for allowing their Office applications to work with each other. "OLE automation" was the precursor to COM. Later on, the VB team at Microsoft created the IDispatch interface, "OLE automation" bcame the foundation for "ActiveX" controls, people dropped the acronym "OLE" and simply started referring to "OLE automation" as just "automation", and the VB folks defined "automation" as meaning "a COM component that supports the IDispatch interface". These days, however, "automation" is generally accepted to mean simply "a software component that adheres to the COM specification", even if it does not support IDispatch. (Remember, a COM component does not have to support IDispatch.) Now, if you have ever programmed in VB, you know that you can use a variable without first declaring it. When you do this, VB automatically creates a variable of type...VARIANT. From the outset, VB is designed to be very flexible with regard to its data types, and because VB was both a compiled language AND a scripted language, the VARIANT data type was very convenient for passing data between software components that were bound at run-time (as with VB script). So, you can see why VARIANT is so important to the IDispatch interface. The VB folks at Microsoft had a strong influence on COM and the IDispatch interface. They were also very interested in the use of ActiveX controls (COM components) in VB form applications, and web-based applications using VB script. So, the moral of the story is: VARIANT is an "automation-compatible" data type, and is in fact probably the most commonly used data type for passing data between COM components. Now, there are other "automation" data types, for example BSTR. You can pass a BSTR between a COM client and a COM server. The "
-
dual interface- Well, not necessarily: for example, automation directly supports BSTR (b-strings) and 4-byte integer values (known as long integers in C++), BUT...to keep things more simple, I would recommend just using VARIANT for all of your parameters, as you suggest. If you study the VARIANT data type closely, you'll see that the VARIANT structure itself actually can hold many other data types. Its up to you to figure out what a VARIANT contains by looking at the '.vt' member of the structure. Also, if you're writing in VB, VB can automatically convert from VARIANT to other data types for you. I believe C# can do this also, although I haven't really dabbled in C# yet. If you're writing in C++, you can use the _variant_t class which provides many conversion operators (I use _variant_t all the time in my C++ code). 2) I wouldn't necessarily recommend using a custom data type through the IDispatch interface unless your ready to write "custom marshalling" routines. "Marshaling" is the process of packaging up your function calls and parameters, then passing them across process boundaries, and possibly even across machine boundaries if you are going to have a client on one machine invoke a COM server on another machine (which is another really cool thing to do with COM). Microsoft provides COM components that can performing the marshalling for you based on the information you have in your IDL. Is there a way you can take your custom data type and make it "look" like a standard type? For example, could your custom data type be type cast as a long integer (vt = VT_I4) and placed into a VARIANT for the function call? And then when the server gets the parameter value, it can type cast it again into whatever you need it to be? Scott
-
dual interfaceYes, on point number 1...You ONLY have to support IDispatch if you want scripting languages or other languages that use late binding to be able to use to your COM server component. Of course, this is very often the case these days with so many COM components being written to plug into web sites and be called from VB script, Java script, etc. I'm sorry I should have made this more clear. So, you CAN have a COM component publicly available that does NOT support IDispatch, but it will need to be linked with the client program at compile (build) time. On point 2: YES, all parameter/return values MUST be automation compatible. Basically, this means that everything must be VARIANT, BSTR, long integer, etc. Why? Because COM is a defined standard that all programming languages that wish to be COM compliant must adhere to if they wish to interface with each other, and IDispatch is a defined interface within the standard. If you wish to use much of the automation linkage already put into place by Microsoft, and the COM subsystem (also implemented by Microsoft via Windows), you'll have to adhere to the standards of the subsystem components. For example, of you try to pass a "C-style" string from a C++ program to a VB program through a COM interface, the VB program will probably crash because it doesn't "understand" the structure of a C-style string. Incidentally, I had to read two or three books on COM and diligently work the examples before I got it figured out. I tried using ATL and the Visual Studio wizards to create my COM components, but quickly gave up on this because it was very inflexible when I wanted to make additions or changes to my COM classes. I ended up hand-building, from scratch, all of my COM components, but now I have a library of components for use in my applications. Scott :)
-
dual interfaceOn point 1: I rarely implement dual interfaces because I develop COM servers and COM clients as part of a package application, and my client components always have "up front" knowledge of what the server can do. So, I typically do not implement the IDispatch interface. This results in a little less complexity in my application and improved performance. My belief is that you should only implement IDispatch if a) you are developing a COM component that you are going to make publicly available to other developers so that they might use it in their applications, or b) your COM component needs to be used by a scripting language, for example VBScript within a web page, in which case you must implement IDispatch so that the VBScript can bind to your COM component at run time (late binding). The application that I support is all written in C++ (no scripting languages) and contains no components that are intended to be available for use by other developers outside my company. On point 2: You are correct, the client should always call "QueryInterface" to get a pointer to the desired interface exported by a server, then call the methods of that interface via the pointer. Since the methods of the interface are all defined as virtual functions in C++, you are implicitly invoking the methods through the virtual function table. (Of course, virtual functions are intrinsic to the C++ language and existed long before COM was created.) :)
-
dual interface;) ;) Actually, "dual interface" refers to a COM class's ability to have its methods bound at compile time OR at run-time. Generally, all COM classes implement "custom" interfaces - after all, they do things that are specific to defined set of requirements, and are thus "custom". The COM class's methods are bound at compile time into a virtual function table, or VTABLE. For a program (client) to invoke the COM class's methods, it must have "knowledge" of the methods exported by the COM component at the time the client program itself is compiled into executable form. For applications where the COM object (server) and the client program are designed and built together, the client can easily have such "knowledge". I often develop COM servers and clients simultaneously, and my client programs have "intimate" knowledge of the names of the methods exported by the COM server. But what about client programs that want to use a COM server's methods at RUN TIME, but do not necessarily know the names and other properties of the methods exported by the COM server? This situation arises very often for scripting languages where the executable code is built "on the fly". The process whereby a client program "discovers" and uses the methods exported by a COM server is called "Run-time" binding, also known as "late" binding. This process allows scripting languages to identify what interfaces (methods) a COM class supports at run time, long AFTER the COM class has been compiled into executable code. This is done through QueryInterface and the IDispatch method. Thus, a COM class must support the IDispatch interface if it wants to allow client programs to bind to its methods at run-time. A COM class that supports IDispatch is thus said to be "dual interface" - a client program with "intimate" knowledge of its method's names and parameters can bind to it a compile time, OR the client can bind to its methods at run time via QueryInterface and IDispatch. Incidentally, "IDispatch" is aptly named because it is a method that "dispatches" a function call to the proper method within the COM server.
-
Date/time functions in SQL Server 2005Do you have SQL Server Help? Start by looking at the help for functions GETDATE() and DATEPART(). Then follow other related links from there. Scott
-
Pop Up loading messageGood! I'm sorry, I should have been more clear that I thought the LAST thing you would do is reset the focus, making sure it was done after the child window was destroyed. Windows will attempt to set the focus using its own internal (and often misundertood) logic when it shuts down a window. And, or course, God only knows what MFC is doing. Scott :)
-
How to start an application on another system?OK, you can do what you suggest but it is a little different than what I was thinking. I see two basic ways to do this, both of which are perfectly reasonable: 1 - Use a COM server and client, as we have already discussed. 2 - Use a SERVICE program running on the server, which is continually listening to a specific port for incoming connections using Windows sockets. Your statement above indicates that you are thinking in terms of the second approach. Let me clarify the first approach a little. A COM server typically only resides in memory when a client has requested its service, and therefore has a REFERENCE to the COM server. When the client closes down, it releases the reference to the COM server, and when the COM server realizes that there are no "open" references to it, it shuts itself down. This is typical behavior in the COM world. This is OK, because with the proper registry entries on both the server and client machines, the Windows COM system will automatically locate and launch the COM server when a client requests its services. It seemed to me that your client would simply invoke the server, getting a pointer to the server's interface, then invoking an interface function that would launch a specific program on the server. Because the Windows COM system handles launching the COM server, you don't need to worry about whether the COM server is always on and always "listening" for incoming client requests. It will get started up as soon as a client requests one of its interfaces. Now, for approach number two...I have done this type of thing as well, using a SERVICE program, which is NOT the same thing as a COM server. Not too long ago, I wrote a service program that I set up to start every time the operating system was started. These programs show up in the "Services" program under "Administrative Utilities" in the control panel. There are a number of articles that discuss how to write a service program. In my case, my service program was designed to "listen" on a user-selectable port for incoming socket connections. When a connection was established, it would spin off a thread to process bi-directional communications between the service program and the client. This was all done using the WinSock API. In this case, the service program was always running and listening for incoming connections. I wish I could help you more, but it seems to me you will need to first decide which of the above approaches you wish to take (or yet another approach if someone else has made any add
-
Pop Up loading messageOK, my bad...you're evidently using MFC, which provides its own "flavor" of 'GetFocus()'. Try the following: CWnd* pwndSaveFocus = GetFocus() ; ... SetFocus(pwndSaveFocus) ; The difference is that 'GetFocus()' and 'SetFocus()' from the MFC classes operate on an instance of the 'CWnd' class. The code I originally gave you is bare-bones Windows API, and operates on window handles (HWND). The 'CWnd' class in MFC actually encapsulates HWNDs. Alternatively, you could force the use of the Windows API functions by using the scoping operator to go "outside" the MFC scope to the global scope, as follows: HWND hwndSaveFocus = ::GetFocus() ; ... ::SetFocus(hwndSaveFocus) ; The '::' at the beginning of each of the above statements forces the compiler to bypass the MFC functions and map directly to the Windows API. Hope this gets you a little closer. Scott
-
Pop Up loading messageOK, hang on, let me check the API documentaiton....be right back
-
help~~~,how to connect [modified]I'm not an expert on MySQL, but based on my experience with SQL Server I would suggest finding out what ports MySQL uses to listen for incoming connections and respond to clients. If these ports are being blocked by a firewall on either the client computer or the server, you won't be able to connect. Try turning off any firewalls (temporarily) and see what happens. Scott
-
Background text color in RichEditCtrlTry a couple of things: 1 - use the following message: ::SendMessage( m_hwndText, //Handle to edit control. EM_SETBKGNDCOLOR, 0, clrBackground) ; //e.g., ULONG clrBackground = RGB(255, 0, 0) ; 2 - Also, I seem to remember some time ago having to first put some text into a rich edit before I could change the background. You first have to select the text using CHARRANGE, then use CHARFOMAT2 to format the text. I have a vague recollection of putting a single space character into the rich edit to get it to work, but you may not have to. Scott
-
How to achive application load balancing in win32 applicationI don't know that you can perform load-balancing as directly as you want to. However, the Windows API offers the 'CreateThread()' and 'SetThreadPriority()' functions, which allow you to create a thread and set its priority. For example, we can create a thread and set its priority to LOW, in which case the operating system will AUTOMATICALLY schedule the thread for execution in such a way that other, higher priority threads will receive more CPU cycles. This is probably the best way to handle this anyway, as the operating system can allocate CPU cycles more efficiently that you could. In your example, the disk writer thread would be given a low priority. As other tasks are invoked, such as user interface actions, Windows will automatically suspend the desk writer thread and give priority to the user interface. Check out the documentation on 'CreateThread()' and 'setThreadPriority()' for a better description. Scott
-
Changing RichEdit fontMy understanding of how to use the rich edit is that you have to first select the text for which you wish to change the font. I found the following code in a program that I wrote some time ago: CHARRANGE CharRange ; CHARFORMAT2 CharFormat ; // To format the text just written, we must select it. ::SendMessage( m_hwndThis, EM_SETSEL, 0, CharRange.cpMax) ; //'cpMax' set to LAST character position. // Set up the character formatting structure. CharFormat.cbSize = sizeof(CharFormat) ; CharFormat.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC ; CharFormat.dwEffects = (bBold) ? CFE_BOLD : 0 | (bItalic) ? CFE_ITALIC : 0 ; CharFormat.yHeight = 0 ; CharFormat.yOffset = 0 ; CharFormat.crTextColor = clrFG ; //Previously set CharFormat.bCharSet = DEFAULT_CHARSET ; CharFormat.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE ; memset(CharFormat.szFaceName, 0, 1) ; _tcscpy((_TCHAR*)&CharFormat.szFaceName, _T("Arial")) ; // Format the text just written. ::SendMessage( m_hwndThis, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&CharFormat) ; Don't know if this will help, but maybe it will give you some ideas where to continue. Scott
-
Pop Up loading messageSetting the style to "Child" does not work because, when you disable a window, Windows will automatically disable its child windows as well. When you used SetFocus, did you do it as follows: HWND hwndSaveFocus = GetFocus() ; ... (display dialog and delete when done) ... SetFocus(hwndsaveFocus) ; Scott
-
custom menu item command idsLook up WM_USER in the help text. This is a #defined constant in the Windows header files that is always equal to the highest Windows message ID. Thus, you can safely define your own IDs starting at WM_USER + 1. Beware, however, that some Windows common controls use IDs above WM_USER, so what I have done use WM_USER + 1000, + 1001, + 1002, etc., and I have not had any problems. Scott
-
SHGetFolderLocation() function gives compile time error.Try it like this: #define _WIN32_IE 0x0500 #include "stdafx.h" #include "shlobj.h" If you want, you can put _WIN32_IE=0x500 into the PreProcessor Definitions on the Project Properties page Scott
-
How to start an application on another system?Just an idea, and probably not what you want to hear, but if I were going to do this, I would create a COM server, register it on PC2, and use it to start a separate console application on PC2. Then, I would set up my console application on PC1 to act as a COM client, remotely instantiating the COM server on PC2. When it creates the (remote) COM server, the creation process itself could indicate the the COM server is to launch the PCS console application. With this framework, you could even set up the COM server on PC2 such that you could tell it which of serveral console applications you would like it to start. Of course, this all presumes that you understand how to build COM servers and clients. This isn't too bad if your using C# or VB.net with VS 2005. Much harder if your using straight C++. Scott :)