etch666
etch666
关注数: 16
粉丝数: 35
发帖数: 1,520
关注贴吧数: 3
纯c面向对象 Introduction There are numerous examples that demonstrate how to use/create COM/OLE/ActiveX components. But these examples typically use Microsoft Foundation Classes (MFC), .NET, C#, WTL, or at least ATL, because those frameworks have pre-fabricated "wrappers" to give you some boilerplate code. Unfortunately, these frameworks tend to hide all of the low level details from a programmer, so you never really do learn how to use COM components per se. Rather, you learn how to use a particular framework riding on top of COM. If you're trying to use plain C, without MFC, WTL, .NET, ATL, C#, or even any C++ code at all, then there is a dearth of examples and information on how to deal with COM objects. This is the first in a series of articles that will examine how to utilize COM in plain C, without any frameworks. With standard Win32 controls such as a Static, Edit, Listbox, Combobox, etc., you obtain a handle to the control (i.e., an HWND) and pass messages (via SendMessage) to it in order to manipulate it. Also, the control passes messages back to you (i.e., by putting them in your own message queue, and you fetch them with GetMessage) when it wants to inform you of something or give you some data. Not so with an OLE/COM object. You don't pass messages back and forth. Instead, the COM object gives you some pointers to certain functions that you can call to manipulate the object. For example, one of Internet Explorer's objects will give you a pointer to a function you can call to cause the browser to load and display a web page in one of your windows. One of Office's objects will give you a pointer to a function you can call to load a document. And if the COM object needs to notify you of something or pass data to you, then you will be required to write certain functions in your program, and provide (to the COM object) pointers to those functions so the object can call those functions when needed. In other words, you need to create your own COM object(s) inside your program. Most of the real hassle in C will involve defining your own COM object. To do this, you'll need to know the minute details about a COM object -- stuff that most of the pre-fabricated frameworks hide from you, but which we'll examine in this series. In conclusion, you call functions in the COM object to manipulate it, and it calls functions in your program to notify you of things or pass you data or interact with your program in some way. This scheme is analogous to calling functions in a DLL, but as if the DLL is also able to call functions inside your C program -- sort of like with a "callback". But unlike with a DLL, you don't use LoadLibrary() and GetProcAddress() to obtain the pointers to the COM object's functions. As we'll soon discover, you instead use a different operating system function to get a pointer to an object, and then use that object to obtain pointers to its functions. A COM object and its VTable Before we can learn how to use a COM object, we first need to learn what it is. And the best way to do that is to create our own COM object. But before we do that, let's examine a C struct data type. As a C programmer, you should be quite familiar with struct. Here's an example definition of a simple struct (called "IExample") that contains two members -- a DWORD (accessed via the member name "count"), and an 80 char array (accessed via the member name "buffer"). struct IExample { DWORD count; char buffer[80]; };Let's use a typedef to make it easier to work with: typedef struct { DWORD count; char buffer[80]; } IExample;And here's an example of allocating an instance of the above struct (error checking omitted), and initializing its members: IExample * example; example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample)); example->count = 1; example->buffer[0] = 0;Did you know that a struct can store a pointer to some function? Hopefully, you did, but here's an example. Let's say we have a function which is passed a char pointer, and returns a long. Here's our function: long SetString(char * str) { return(0); }Now we want to store a pointer to this function inside IExample. Here's how we define IExample, adding a member ("SetString") to store a pointer to the above function (and I'll use a typedef to make this more readable): typedef long SetStringPtr(char *); typedef struct { SetStringPtr * SetString; DWORD count; char buffer[80]; } IExample;And here's how we store a pointer to SetString inside our allocated IExample, and then call SetString using that pointer: example->SetString = SetString; long value = example->SetString("Some text");OK, maybe we want to store pointers to two functions. Here's a second function: long GetString(char *buffer, long length) { return(0); }Let's re-define IExample, adding another member ("GetString") to store a pointer to this second function: typedef long GetStringPtr(char *, long); typedef struct { SetStringPtr * SetString; GetStringPtr * GetString; DWORD count; char buffer[80]; } IExample;And here we initialize this member: example->GetString = GetString;But let's say we don't want to store the function pointers directly inside of IExample. Instead, we'd rather have an array of function pointers. For example, let's define a second struct whose sole purpose is to store our two function pointers. We'll call this a IExampleVtbl struct, and define it as so: typedef struct { SetStringPtr * SetString; GetStringPtr * GetString; } IExampleVtbl;Now, we'll store a pointer to the above array inside of IExample. We'll add a new member called "lpVtbl" for that purpose (and of course, we'll remove the SetString and GetString members since they've been moved to the IExampleVtbl struct): typedef struct { IExampleVtbl * lpVtbl; DWORD count; char buffer[80]; } IExample;So here's an example of allocating and initializing a IExample (and of course, a IExampleVtbl): // Since the contents of IExample_Vtbl will never change, we'll // just declare it static and initialize it that way. It can // be reused for lots of instances of IExample. static const IExampleVtbl IExample_Vtbl = {SetString, GetString}; IExample * example; // Create (allocate) a IExample struct. example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample)); // Initialize the IExample (ie, store a pointer to // IExample_Vtbl in it). example->lpVtbl = &IExample_Vtbl; example->count = 1; example->buffer[0] = 0;And to call our functions, we do: char buffer[80]; example->lpVtbl->SetString("Some text"); example->lpVtbl->GetString(buffer, sizeof(buffer));One more thing. Let's say we've decided that our functions may need to access the "count" and "buffer" members of the struct used to call them. So, what we'll do is always pass a pointer to that struct as the first argument. Let's rewrite our functions to accommodate this: typedef long SetStringPtr(IExample *, char *); typedef long GetStringPtr(IExample *, char *, long); long SetString(IExample *this, char * str) { DWORD i; // Let's copy the passed str to IExample's buffer i = lstrlen(str); if (i > 79) i = 79; CopyMemory(this->buffer, str, i); this->buffer[i] = 0; return(0); } long GetString(IExample *this, char *buffer, long length) { DWORD i; // Let's copy IExample's buffer to the passed buffer i = lstrlen(this->buffer); --length; if (i > length) i = length; CopyMemory(buffer, this->buffer, i); buffer[i] = 0; return(0); }And let's pass a pointer to the IExample struct when calling its functions: example->lpVtbl->SetString(example, "Some text"); example->lpVtbl->GetString(example, buffer, sizeof(buffer));If you've ever used C++, you may be thinking "Wait a minute. This seems strangely familiar." It should. What we've done above is to recreate a C++ class, using plain C. The IExample struct is really a C++ class (one that doesn't inherit from any other class). A C++ class is really nothing more than a struct whose first member is always a pointer to an array -- an array that contains pointers to all the functions inside of that class. And the first argument passed to each function is always a pointer to the class (i.e., struct) itself. (This is referred to as the hidden "this" pointer.) At its simplest, a COM object is really just a C++ class. You're thinking "Wow! IExample is now a COM object? That's all there is to it?? That was easy!" Hold on. IExample is getting closer, but there's much more to it. It's not that easy. If it were, this wouldn't be a "Microsoft technology", now would it? First of all, let's introduce some COM technobabble. You see that array of pointers above -- the IExampleVtbl struct? COM documentation refers to that as an interface or VTable. One requirement of a COM object is that the first three members of our VTable (i.e., our IExampleVtbl struct) must be called QueryInterface, AddRef, and Release. And of course, we have to write those three functions. Microsoft has already determined what arguments must be passed to these functions, what they must return, and what calling convention they use. We'll need to #include some Microsoft include files (that either ship with your C compiler, or you download the Microsoft SDK). We'll re-define our IExampleVtbl struct as so: #include <windows.h> #include <objbase.h> #include <INITGUID.H> typedef HRESULT STDMETHODCALLTYPE QueryInterfacePtr(IExample *, REFIID, void **); typedef ULONG STDMETHODCALLTYPE AddRefPtr(IExample *); typedef ULONG STDMETHODCALLTYPE ReleasePtr(IExample *); typedef struct { // First 3 members must be called QueryInterface, AddRef, and Release QueryInterfacePtr *QueryInterface; AddRefPtr *AddRef; ReleasePtr *Release; SetStringPtr *SetString; GetStringPtr *GetString; } IExampleVtbl;Let's examine that typedef for QueryInterface. First of all, the function returns an HRESULT. This is defined simply as a long. Next, it uses STDMETHODCALLTYPE. This means that arguments are not passed in registers, but rather, on the stack. And this also determines who does cleanup of the stack. In fact, for a COM object, we should make sure that all of our functions are declared with STDMETHODCALLTYPE, and return a long (HRESULT). The first argument passed to QueryInterface is a pointer to the object used to call the function. Aren't we turning IExample into a COM object? Yes, and that's what we're going to pass for this argument. (Remember we decided that the first argument we pass to any of our functions will be a pointer to the struct used to call that function? COM is simply enforcing, and relying upon, this design.) Later, we'll examine what a REFIID is, and also talk about what that third argument to QueryInterface is for. But for now, note that AddRef and Release also are passed that same pointer to our struct we use to call them. OK, before we forget, let's add HRESULT STDMETHODCALLTYPE to SetString and GetString: typedef HRESULT STDMETHODCALLTYPE SetStringPtr(IExample *, char *); typedef HRESULT STDMETHODCALLTYPE GetStringPtr(IExample *, char *, long); HRESULT STDMETHODCALLTYPE SetString(IExample *this, char * str) { ... return(0); } HRESULT STDMETHODCALLTYPE GetString(IExample *this, char *buffer, long value) { ... return(0); }In conclusion, a COM object is basically a C++ class. A C++ class is just a struct that always starts with a pointer to its VTable (an array of function pointers). And the first three pointers in the VTable will always be named QueryInterface, AddRef, and Release. What additional functions may be in its VTable, and what the name of their pointers are, depends upon what type of object it is. (You determine what other functions you want to add to your COM object.) For example, Internet Explorer's browser object will undoubtedly have different functions than some object that plays music. But all COM objects begin with a pointer to their VTable, and the first three VTable pointers are to the object's QueryInterface, AddRef, and Release functions. The first argument passed to an object's function is a pointer to the object (struct) itself. That is the law. Obey it.
纯c面向对象 Introduction There are numerous examples that demonstrate how to use/create COM/OLE/ActiveX components. But these examples typically use Microsoft Foundation Classes (MFC), .NET, C#, WTL, or at least ATL, because those frameworks have pre-fabricated "wrappers" to give you some boilerplate code. Unfortunately, these frameworks tend to hide all of the low level details from a programmer, so you never really do learn how to use COM components per se. Rather, you learn how to use a particular framework riding on top of COM. If you're trying to use plain C, without MFC, WTL, .NET, ATL, C#, or even any C++ code at all, then there is a dearth of examples and information on how to deal with COM objects. This is the first in a series of articles that will examine how to utilize COM in plain C, without any frameworks. With standard Win32 controls such as a Static, Edit, Listbox, Combobox, etc., you obtain a handle to the control (i.e., an HWND) and pass messages (via SendMessage) to it in order to manipulate it. Also, the control passes messages back to you (i.e., by putting them in your own message queue, and you fetch them with GetMessage) when it wants to inform you of something or give you some data. Not so with an OLE/COM object. You don't pass messages back and forth. Instead, the COM object gives you some pointers to certain functions that you can call to manipulate the object. For example, one of Internet Explorer's objects will give you a pointer to a function you can call to cause the browser to load and display a web page in one of your windows. One of Office's objects will give you a pointer to a function you can call to load a document. And if the COM object needs to notify you of something or pass data to you, then you will be required to write certain functions in your program, and provide (to the COM object) pointers to those functions so the object can call those functions when needed. In other words, you need to create your own COM object(s) inside your program. Most of the real hassle in C will involve defining your own COM object. To do this, you'll need to know the minute details about a COM object -- stuff that most of the pre-fabricated frameworks hide from you, but which we'll examine in this series. In conclusion, you call functions in the COM object to manipulate it, and it calls functions in your program to notify you of things or pass you data or interact with your program in some way. This scheme is analogous to calling functions in a DLL, but as if the DLL is also able to call functions inside your C program -- sort of like with a "callback". But unlike with a DLL, you don't use LoadLibrary() and GetProcAddress() to obtain the pointers to the COM object's functions. As we'll soon discover, you instead use a different operating system function to get a pointer to an object, and then use that object to obtain pointers to its functions. A COM object and its VTable Before we can learn how to use a COM object, we first need to learn what it is. And the best way to do that is to create our own COM object. But before we do that, let's examine a C struct data type. As a C programmer, you should be quite familiar with struct. Here's an example definition of a simple struct (called "IExample") that contains two members -- a DWORD (accessed via the member name "count"), and an 80 char array (accessed via the member name "buffer"). struct IExample { DWORD count; char buffer[80]; };Let's use a typedef to make it easier to work with: typedef struct { DWORD count; char buffer[80]; } IExample;And here's an example of allocating an instance of the above struct (error checking omitted), and initializing its members: IExample * example; example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample)); example->count = 1; example->buffer[0] = 0;Did you know that a struct can store a pointer to some function? Hopefully, you did, but here's an example. Let's say we have a function which is passed a char pointer, and returns a long. Here's our function: long SetString(char * str) { return(0); }Now we want to store a pointer to this function inside IExample. Here's how we define IExample, adding a member ("SetString") to store a pointer to the above function (and I'll use a typedef to make this more readable): typedef long SetStringPtr(char *); typedef struct { SetStringPtr * SetString; DWORD count; char buffer[80]; } IExample;And here's how we store a pointer to SetString inside our allocated IExample, and then call SetString using that pointer: example->SetString = SetString; long value = example->SetString("Some text");OK, maybe we want to store pointers to two functions. Here's a second function: long GetString(char *buffer, long length) { return(0); }Let's re-define IExample, adding another member ("GetString") to store a pointer to this second function: typedef long GetStringPtr(char *, long); typedef struct { SetStringPtr * SetString; GetStringPtr * GetString; DWORD count; char buffer[80]; } IExample;And here we initialize this member: example->GetString = GetString;But let's say we don't want to store the function pointers directly inside of IExample. Instead, we'd rather have an array of function pointers. For example, let's define a second struct whose sole purpose is to store our two function pointers. We'll call this a IExampleVtbl struct, and define it as so: typedef struct { SetStringPtr * SetString; GetStringPtr * GetString; } IExampleVtbl;Now, we'll store a pointer to the above array inside of IExample. We'll add a new member called "lpVtbl" for that purpose (and of course, we'll remove the SetString and GetString members since they've been moved to the IExampleVtbl struct): typedef struct { IExampleVtbl * lpVtbl; DWORD count; char buffer[80]; } IExample;So here's an example of allocating and initializing a IExample (and of course, a IExampleVtbl): // Since the contents of IExample_Vtbl will never change, we'll // just declare it static and initialize it that way. It can // be reused for lots of instances of IExample. static const IExampleVtbl IExample_Vtbl = {SetString, GetString}; IExample * example; // Create (allocate) a IExample struct. example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample)); // Initialize the IExample (ie, store a pointer to // IExample_Vtbl in it). example->lpVtbl = &IExample_Vtbl; example->count = 1; example->buffer[0] = 0;And to call our functions, we do: char buffer[80]; example->lpVtbl->SetString("Some text"); example->lpVtbl->GetString(buffer, sizeof(buffer));One more thing. Let's say we've decided that our functions may need to access the "count" and "buffer" members of the struct used to call them. So, what we'll do is always pass a pointer to that struct as the first argument. Let's rewrite our functions to accommodate this: typedef long SetStringPtr(IExample *, char *); typedef long GetStringPtr(IExample *, char *, long); long SetString(IExample *this, char * str) { DWORD i; // Let's copy the passed str to IExample's buffer i = lstrlen(str); if (i > 79) i = 79; CopyMemory(this->buffer, str, i); this->buffer[i] = 0; return(0); } long GetString(IExample *this, char *buffer, long length) { DWORD i; // Let's copy IExample's buffer to the passed buffer i = lstrlen(this->buffer); --length; if (i > length) i = length; CopyMemory(buffer, this->buffer, i); buffer[i] = 0; return(0); }And let's pass a pointer to the IExample struct when calling its functions: example->lpVtbl->SetString(example, "Some text"); example->lpVtbl->GetString(example, buffer, sizeof(buffer));If you've ever used C++, you may be thinking "Wait a minute. This seems strangely familiar." It should. What we've done above is to recreate a C++ class, using plain C. The IExample struct is really a C++ class (one that doesn't inherit from any other class). A C++ class is really nothing more than a struct whose first member is always a pointer to an array -- an array that contains pointers to all the functions inside of that class. And the first argument passed to each function is always a pointer to the class (i.e., struct) itself. (This is referred to as the hidden "this" pointer.) At its simplest, a COM object is really just a C++ class. You're thinking "Wow! IExample is now a COM object? That's all there is to it?? That was easy!" Hold on. IExample is getting closer, but there's much more to it. It's not that easy. If it were, this wouldn't be a "Microsoft technology", now would it? First of all, let's introduce some COM technobabble. You see that array of pointers above -- the IExampleVtbl struct? COM documentation refers to that as an interface or VTable. One requirement of a COM object is that the first three members of our VTable (i.e., our IExampleVtbl struct) must be called QueryInterface, AddRef, and Release. And of course, we have to write those three functions. Microsoft has already determined what arguments must be passed to these functions, what they must return, and what calling convention they use. We'll need to #include some Microsoft include files (that either ship with your C compiler, or you download the Microsoft SDK). We'll re-define our IExampleVtbl struct as so: #include <windows.h> #include <objbase.h> #include <INITGUID.H> typedef HRESULT STDMETHODCALLTYPE QueryInterfacePtr(IExample *, REFIID, void **); typedef ULONG STDMETHODCALLTYPE AddRefPtr(IExample *); typedef ULONG STDMETHODCALLTYPE ReleasePtr(IExample *); typedef struct { // First 3 members must be called QueryInterface, AddRef, and Release QueryInterfacePtr *QueryInterface; AddRefPtr *AddRef; ReleasePtr *Release; SetStringPtr *SetString; GetStringPtr *GetString; } IExampleVtbl;Let's examine that typedef for QueryInterface. First of all, the function returns an HRESULT. This is defined simply as a long. Next, it uses STDMETHODCALLTYPE. This means that arguments are not passed in registers, but rather, on the stack. And this also determines who does cleanup of the stack. In fact, for a COM object, we should make sure that all of our functions are declared with STDMETHODCALLTYPE, and return a long (HRESULT). The first argument passed to QueryInterface is a pointer to the object used to call the function. Aren't we turning IExample into a COM object? Yes, and that's what we're going to pass for this argument. (Remember we decided that the first argument we pass to any of our functions will be a pointer to the struct used to call that function? COM is simply enforcing, and relying upon, this design.) Later, we'll examine what a REFIID is, and also talk about what that third argument to QueryInterface is for. But for now, note that AddRef and Release also are passed that same pointer to our struct we use to call them. OK, before we forget, let's add HRESULT STDMETHODCALLTYPE to SetString and GetString: typedef HRESULT STDMETHODCALLTYPE SetStringPtr(IExample *, char *); typedef HRESULT STDMETHODCALLTYPE GetStringPtr(IExample *, char *, long); HRESULT STDMETHODCALLTYPE SetString(IExample *this, char * str) { ... return(0); } HRESULT STDMETHODCALLTYPE GetString(IExample *this, char *buffer, long value) { ... return(0); }In conclusion, a COM object is basically a C++ class. A C++ class is just a struct that always starts with a pointer to its VTable (an array of function pointers). And the first three pointers in the VTable will always be named QueryInterface, AddRef, and Release. What additional functions may be in its VTable, and what the name of their pointers are, depends upon what type of object it is. (You determine what other functions you want to add to your COM object.) For example, Internet Explorer's browser object will undoubtedly have different functions than some object that plays music. But all COM objects begin with a pointer to their VTable, and the first three VTable pointers are to the object's QueryInterface, AddRef, and Release functions. The first argument passed to an object's function is a pointer to the object (struct) itself. That is the law. Obey it.
纯c面向对象 Introduction There are numerous examples that demonstrate how to use/create COM/OLE/ActiveX components. But these examples typically use Microsoft Foundation Classes (MFC), .NET, C#, WTL, or at least ATL, because those frameworks have pre-fabricated "wrappers" to give you some boilerplate code. Unfortunately, these frameworks tend to hide all of the low level details from a programmer, so you never really do learn how to use COM components per se. Rather, you learn how to use a particular framework riding on top of COM. If you're trying to use plain C, without MFC, WTL, .NET, ATL, C#, or even any C++ code at all, then there is a dearth of examples and information on how to deal with COM objects. This is the first in a series of articles that will examine how to utilize COM in plain C, without any frameworks. With standard Win32 controls such as a Static, Edit, Listbox, Combobox, etc., you obtain a handle to the control (i.e., an HWND) and pass messages (via SendMessage) to it in order to manipulate it. Also, the control passes messages back to you (i.e., by putting them in your own message queue, and you fetch them with GetMessage) when it wants to inform you of something or give you some data. Not so with an OLE/COM object. You don't pass messages back and forth. Instead, the COM object gives you some pointers to certain functions that you can call to manipulate the object. For example, one of Internet Explorer's objects will give you a pointer to a function you can call to cause the browser to load and display a web page in one of your windows. One of Office's objects will give you a pointer to a function you can call to load a document. And if the COM object needs to notify you of something or pass data to you, then you will be required to write certain functions in your program, and provide (to the COM object) pointers to those functions so the object can call those functions when needed. In other words, you need to create your own COM object(s) inside your program. Most of the real hassle in C will involve defining your own COM object. To do this, you'll need to know the minute details about a COM object -- stuff that most of the pre-fabricated frameworks hide from you, but which we'll examine in this series. In conclusion, you call functions in the COM object to manipulate it, and it calls functions in your program to notify you of things or pass you data or interact with your program in some way. This scheme is analogous to calling functions in a DLL, but as if the DLL is also able to call functions inside your C program -- sort of like with a "callback". But unlike with a DLL, you don't use LoadLibrary() and GetProcAddress() to obtain the pointers to the COM object's functions. As we'll soon discover, you instead use a different operating system function to get a pointer to an object, and then use that object to obtain pointers to its functions. A COM object and its VTable Before we can learn how to use a COM object, we first need to learn what it is. And the best way to do that is to create our own COM object. But before we do that, let's examine a C struct data type. As a C programmer, you should be quite familiar with struct. Here's an example definition of a simple struct (called "IExample") that contains two members -- a DWORD (accessed via the member name "count"), and an 80 char array (accessed via the member name "buffer"). struct IExample { DWORD count; char buffer[80];}; Let's use a typedef to make it easier to work with: typedef struct { DWORD count; char buffer[80];} IExample; And here's an example of allocating an instance of the above struct (error checking omitted), and initializing its members: IExample * example;example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample));example->count = 1;example->buffer[0] = 0; Did you know that a struct can store a pointer to some function? Hopefully, you did, but here's an example. Let's say we have a function which is passed a char pointer, and returns a long. Here's our function: long SetString(char * str){ return(0);} Now we want to store a pointer to this function inside IExample. Here's how we define IExample, adding a member ("SetString") to store a pointer to the above function (and I'll use a typedef to make this more readable): typedef long SetStringPtr(char *);typedef struct { SetStringPtr * SetString; DWORD count; char buffer[80];} IExample; And here's how we store a pointer to SetString inside our allocated IExample, and then call SetString using that pointer: example->SetString = SetString;long value = example->SetString("Some text"); OK, maybe we want to store pointers to two functions. Here's a second function: long GetString(char *buffer, long length){ return(0);} Let's re-define IExample, adding another member ("GetString") to store a pointer to this second function: typedef long GetStringPtr(char *, long);typedef struct { SetStringPtr * SetString; GetStringPtr * GetString; DWORD count; char buffer[80];} IExample; And here we initialize this member: example->GetString = GetString; But let's say we don't want to store the function pointers directly inside of IExample. Instead, we'd rather have an array of function pointers. For example, let's define a second struct whose sole purpose is to store our two function pointers. We'll call this a IExampleVtbl struct, and define it as so: typedef struct { SetStringPtr * SetString; GetStringPtr * GetString;} IExampleVtbl; Now, we'll store a pointer to the above array inside of IExample. We'll add a new member called "lpVtbl" for that purpose (and of course, we'll remove the SetString and GetString members since they've been moved to the IExampleVtbl struct): typedef struct { IExampleVtbl * lpVtbl; DWORD count; char buffer[80];} IExample; So here's an example of allocating and initializing a IExample (and of course, a IExampleVtbl): // Since the contents of IExample_Vtbl will never change, we'll// just declare it static and initialize it that way. It can// be reused for lots of instances of IExample.static const IExampleVtbl IExample_Vtbl = {SetString, GetString};IExample * example;// Create (allocate) a IExample struct.example = (IExample *)GlobalAlloc(GMEM_FIXED, sizeof(IExample));// Initialize the IExample (ie, store a pointer to// IExample_Vtbl in it).example->lpVtbl = &IExample_Vtbl;example->count = 1;example->buffer[0] = 0; And to call our functions, we do: char buffer[80];example->lpVtbl->SetString("Some text");example->lpVtbl->GetString(buffer, sizeof(buffer)); One more thing. Let's say we've decided that our functions may need to access the "count" and "buffer" members of the struct used to call them. So, what we'll do is always pass a pointer to that struct as the first argument. Let's rewrite our functions to accommodate this: typedef long SetStringPtr(IExample *, char *);typedef long GetStringPtr(IExample *, char *, long);long SetString(IExample *this, char * str){ DWORD i; // Let's copy the passed str to IExample's buffer i = lstrlen(str); if (i > 79) i = 79; CopyMemory(this->buffer, str, i); this->buffer[i] = 0; return(0);}long GetString(IExample *this, char *buffer, long length){ DWORD i; // Let's copy IExample's buffer to the passed buffer i = lstrlen(this->buffer); --length; if (i > length) i = length; CopyMemory(buffer, this->buffer, i); buffer[i] = 0; return(0);} And let's pass a pointer to the IExample struct when calling its functions: example->lpVtbl->SetString(example, "Some text");example->lpVtbl->GetString(example, buffer, sizeof(buffer)); If you've ever used C++, you may be thinking "Wait a minute. This seems strangely familiar." It should. What we've done above is to recreate a C++ class, using plain C. The IExample struct is really a C++ class (one that doesn't inherit from any other class). A C++ class is really nothing more than a struct whose first member is always a pointer to an array -- an array that contains pointers to all the functions inside of that class. And the first argument passed to each function is always a pointer to the class (i.e., struct) itself. (This is referred to as the hidden "this" pointer.) At its simplest, a COM object is really just a C++ class. You're thinking "Wow! IExample is now a COM object? That's all there is to it?? That was easy!" Hold on. IExample is getting closer, but there's much more to it. It's not that easy. If it were, this wouldn't be a "Microsoft technology", now would it? First of all, let's introduce some COM technobabble. You see that array of pointers above -- the IExampleVtbl struct? COM documentation refers to that as an interface or VTable. One requirement of a COM object is that the first three members of our VTable (i.e., our IExampleVtbl struct) must be called QueryInterface, AddRef, and Release. And of course, we have to write those three functions. Microsoft has already determined what arguments must be passed to these functions, what they must return, and what calling convention they use. We'll need to #include some Microsoft include files (that either ship with your C compiler, or you download the Microsoft SDK). We'll re-define our IExampleVtbl struct as so: #include #include <objbase.h>#include typedef HRESULT STDMETHODCALLTYPE QueryInterfacePtr(IExample *, REFIID, void **);typedef ULONG STDMETHODCALLTYPE AddRefPtr(IExample *);typedef ULONG STDMETHODCALLTYPE ReleasePtr(IExample *);typedef struct { // First 3 members must be called QueryInterface, AddRef, and Release QueryInterfacePtr *QueryInterface; AddRefPtr *AddRef; ReleasePtr *Release; SetStringPtr *SetString; GetStringPtr *GetString;} IExampleVtbl; Let's examine that typedef for QueryInterface. First of all, the function returns an HRESULT. This is defined simply as a long. Next, it uses STDMETHODCALLTYPE. This means that arguments are not passed in registers, but rather, on the stack. And this also determines who does cleanup of the stack. In fact, for a COM object, we should make sure that all of our functions are declared with STDMETHODCALLTYPE, and return a long (HRESULT). The first argument passed to QueryInterface is a pointer to the object used to call the function. Aren't we turning IExample into a COM object? Yes, and that's what we're going to pass for this argument. (Remember we decided that the first argument we pass to any of our functions will be a pointer to the struct used to call that function? COM is simply enforcing, and relying upon, this design.) Later, we'll examine what a REFIID is, and also talk about what that third argument to QueryInterface is for. But for now, note that AddRef and Release also are passed that same pointer to our struct we use to call them. OK, before we forget, let's add HRESULT STDMETHODCALLTYPE to SetString and GetString: typedef HRESULT STDMETHODCALLTYPE SetStringPtr(IExample *, char *);typedef HRESULT STDMETHODCALLTYPE GetStringPtr(IExample *, char *, long);HRESULT STDMETHODCALLTYPE SetString(IExample *this, char * str){ ... return(0);}HRESULT STDMETHODCALLTYPE GetString(IExample *this, char *buffer, long value){ ... return(0);} In conclusion, a COM object is basically a C++ class. A C++ class is just a struct that always starts with a pointer to its VTable (an array of function pointers). And the first three pointers in the VTable will always be named QueryInterface, AddRef, and Release. What additional functions may be in its VTable, and what the name of their pointers are, depends upon what type of object it is. (You determine what other functions you want to add to your COM object.) For example, Internet Explorer's browser object will undoubtedly have different functions than some object that plays music. But all COM objects begin with a pointer to their VTable, and the first three VTable pointers are to the object's QueryInterface, AddRef, and Release functions. The first argument passed to an object's function is a pointer to the object (struct) itself. That is the law. Obey it.
看KolibriOS源码 能提高汇编水平^_^
websvn.kolibrios.org/listing.php?repname=Kolibri+OS真好看^_^ websvn.kolibrios.org/listing.php?repname=Kolibri+OS 真好看o(^_^)o
认识C-- #ifndef AUTOBUILD #include "lang.h--" #endif #define MEMSIZE 0x100000 #include "..\lib\kolibri.h" #include "..\lib\strings.h" #include "..\lib\mem.h" #include "..\lib\file_system.h" #include "..\lib\dll.h" #include "..\lib\gui.h" #include "..\lib\obj\iconv.h" #include "..\lib\obj\box_lib.h" #include "..\lib\obj\proc_lib.h" #include "..\lib\obj\libio_lib.h" //#include "..\lib\obj\wword.h" #ifdef LANG_RUS ?define T_FILE "Файл" ?define T_TYPE "Тип" ?define T_SIZE "Размер" ?define MENU1 "Файл" ?define MENU1_SUBMENU1 "Открыть" ?define MENU1_SUBMENU2 "Закрыть" ?define MENU1_SUBMENU3 "Свойства" ?define MENU1_SUBMENU4 "Выход" ?define MENU2 "Кодировка" ?define MENU2_SUBMENU1 "UTF-8" ?define MENU2_SUBMENU2 "KOI8-RU" ?define MENU2_SUBMENU3 "CP1251" ?define MENU2_SUBMENU4 "CP1252" ?define MENU2_SUBMENU5 "ISO8859-5" ?define MENU2_SUBMENU6 "CP866" ?define ERROR_LOAD_BOX_LIB "Ошибка при загрузке библиотеки - box_lib.obj" ?define ERROR_LOAD_LIBIO "Ошибка при загрузке библиотеки - libio.obj" ?define ERROR_LOAD_PROC_LIB "Ошибка при загрузке библиотеки - proc_lib.obj" #else ?define T_FILE "File" ?define T_TYPE "Type" ?define T_SIZE "Size" ?define MENU1 "File" ?define MENU1_SUBMENU1 "Open" ?define MENU1_SUBMENU2 "Close" ?define MENU1_SUBMENU3 "Properties" ?define MENU1_SUBMENU4 "Exit" ?define MENU2 "Encoding" ?define MENU2_SUBMENU1 "UTF-8" ?define MENU2_SUBMENU2 "KOI8-RU" ?define MENU2_SUBMENU3 "CP1251" ?define MENU2_SUBMENU4 "CP1252" ?define MENU2_SUBMENU5 "ISO8859-5" ?define MENU2_SUBMENU6 "CP866" ?define ERROR_LOAD_BOX_LIB "Error while loading library - box_lib.obj" ?define ERROR_LOAD_LIBIO "Error while loading library - libio.obj" ?define ERROR_LOAD_PROC_LIB "Error while loading library - proc_lib.obj" #endif #ifdef LANG_RUS struct menu1_text_struct { char menu[5]; char sub_menu1[8]; char sub_menu2[8]; //char sub_menu3[9]; char sub_menu4[6]; byte end; }; struct menu2_text_struct { char menu[10]; char sub_menu1[6]; char sub_menu2[8]; char sub_menu3[7]; char sub_menu4[7]; char sub_menu5[10]; char sub_menu6[6]; byte end; }; #else struct menu1_text_struct { char menu[5]; char sub_menu1[5]; char sub_menu2[6]; //char sub_menu3[11]; char sub_menu4[5]; byte end; }; struct menu2_text_struct { char menu[9]; char sub_menu1[6]; char sub_menu2[8]; char sub_menu3[7]; char sub_menu4[7]; char sub_menu5[10]; char sub_menu6[6]; byte end; }; #endif #define TITLE "Calypte v0.15" #define TOPPANELH 19 #define BOTPANELH 10 #define WIN_W 600 #define WIN_H 400 proc_info Form; byte active_properties = 0; int encoding; dword properties_window; #include "include\properties.h" struct filter { dword size; char ext1[4]; //char ext2[4]; //char ext3[4]; //char ext4[4]; byte end; }; filter filter2; menu1_text_struct menu1_text_area1; menu2_text_struct menu2_text_area2; char win_title[4096] = "Calypte v0.15"; int cur_row=0, read=0, pos=0, row_num=0, col_count=0, row_count=0; dword old_width,old_height; proc_info pr_inf; char communication_area_name[] = "FFFFFFFF_open_dialog"; byte plugin_path[4096]; char default_dir[] = "/rd/1"; char open_dialog_path[] = "/rd/1/File managers/opendial"; //opendial byte openfile_path[2048]; byte filename_area[4096]; opendialog o_dialog = {0, #pr_inf, #communication_area_name, 0, #plugin_path, #default_dir, #open_dialog_path, #draw_window, 0, #openfile_path, #filename_area, #filter2, 420, 200, 320, 120}; dword bufpointer; dword bufsize; dword draw_sruct; menu_data menudata1 = {0, 40, 2, 15, 2, #menu1_text_area1.menu, #menu1_text_area1.sub_menu1, #menu1_text_area1.end, 0, 0, 80, 2, 100, 18, 0xEEEEEE, 0xFF, 0xEEEEEE, 0, 0, 0, #Form, 0, 0, 0, 16, 0, 0, 0x00CC00, 0, 0xFFFFFF, 0, 8, 0, 0}; menu_data menudata2 = {0, 70, 44, 15, 2, #menu2_text_area2.menu, #menu2_text_area2.sub_menu1, #menu2_text_area2.end, 0, 0, 80, 44, 100, 18, 0xEEEEEE, 0xFF, 0xEEEEEE, 0, 0, 0, #Form, 0, 0, 0, 16, 0, 0, 0x00CC00, 0, 0xFFFFFF, 0, 8, 0, 0}; void main() { int id; strcpy(#filter2.ext1, "TXT"); //strcpy(#filter2.ext2, "ASM"); //strcpy(#filter2.ext3, "INC\0"); //strcpy(#filter2.ext4, "\0"); filter2.size = 8; filter2.end = 0; strcpy(#menu1_text_area1.menu, MENU1); strcpy(#menu1_text_area1.sub_menu1, MENU1_SUBMENU1); strcpy(#menu1_text_area1.sub_menu2, MENU1_SUBMENU2); //strcpy(#menu1_text_area1.sub_menu3, MENU1_SUBMENU3); strcpy(#menu1_text_area1.sub_menu4, MENU1_SUBMENU4); menu1_text_area1.end = 0; strcpy(#menu2_text_area2.menu, MENU2); strcpy(#menu2_text_area2.sub_menu1, MENU2_SUBMENU1); strcpy(#menu2_text_area2.sub_menu2, MENU2_SUBMENU2); strcpy(#menu2_text_area2.sub_menu3, MENU2_SUBMENU3); strcpy(#menu2_text_area2.sub_menu4, MENU2_SUBMENU4); strcpy(#menu2_text_area2.sub_menu5, MENU2_SUBMENU5); strcpy(#menu2_text_area2.sub_menu6, MENU2_SUBMENU6); menu2_text_area2.end = 0; //mem_Init(); load_dll(boxlib, #box_lib_init,0); load_dll(libio, #libio_init,1); load_dll(iconv_lib, #iconv_open,0); load_dll(Proc_lib, #OpenDialog_init,0); OpenDialog_init stdcall (#o_dialog); SetEventMask(0x27); loop() { switch(WaitEvent()) { case evMouse: menu_bar_mouse stdcall (#menudata1); menu_bar_mouse stdcall (#menudata2); if (menudata1.click==1) { switch(menudata1.cursor_out) { case 1: OpenDialog_start stdcall (#o_dialog); OpenFile(#openfile_path); Prepare(); draw_window(); break; case 2: read = 0; strcpy(#win_title, TITLE); FreeBuf(); draw_window(); break; case 3: if (!active_properties) { SwitchToAnotherThread(); properties_window = CreateThread(#properties_dialog, #properties_stak+4092); break; } else { ActivateWindow(GetProcessSlot(properties_window)); } break; case 4: ExitProcess(); } } if (menudata2.click==1) { encoding = menudata2.cursor_out - 1; OpenFile(#openfile_path); Prepare(); draw_window(); } break; case evButton: id=GetButtonID(); if (id==1) || (id==10) ExitProcess(); break; case evKey: GetKeys(); if (TestBit(key_modifier, 2)) { switch(key_scancode) { case 024: //Ctrl+O OpenDialog_start stdcall (#o_dialog); OpenFile(#openfile_path); Prepare(); draw_window(); break; } break; } switch (key_scancode) { if (Form.status_window>2) break; case SCAN_CODE_HOME: cur_row = 0; DrawText(); break; case SCAN_CODE_END: cur_row = row_num - row_count - 1; DrawText(); break; case SCAN_CODE_UP: if (!cur_row) break; else cur_row = cur_row-1; DrawText(); break; case SCAN_CODE_DOWN: if (cur_row+row_count>=row_num) break; cur_row = cur_row+1; DrawText(); break; case SCAN_CODE_PGUP: if (!cur_row) break; if (cur_rowrow_num) break; cur_row = cur_row+row_count; DrawText(); break; } break; case evReDraw: draw_window(); break; } } } void draw_window() { system.color.get(); DefineAndDrawWindow(GetScreenWidth()-WIN_W/2,GetScreenHeight()-WIN_H/2,WIN_W,WIN_H,0x73,0xFFFFFF,#win_title); GetProcessInfo(#Form, SelfInfo); DrawBar(0, 0, Form.cwidth, TOPPANELH, system.color.work); DrawBar(0, Form.cheight-BOTPANELH, Form.cwidth, BOTPANELH, system.color.work); menudata1.bckg_col = system.color.work; menudata2.bckg_col = system.color.work; menu_bar_draw stdcall (#menudata1); menu_bar_draw stdcall (#menudata2); if (old_width!=Form.width) || (old_height!=Form.height) { old_width = Form.width; old_height = Form.height; col_count = Form.cwidth/6; row_count = Form.cheight-BOTPANELH-TOPPANELH-2; row_count = row_count/10; if (read==1) Prepare(); } if (read==1) { DrawText(); } else DrawBar(0, TOPPANELH, Form.cwidth, Form.cheight-BOTPANELH-TOPPANELH, 0xFFFFFF); } void OpenFile(dword path) { strcpy(#win_title, TITLE); strcat(#win_title, " - "); strcat(#win_title, path); file_size stdcall (path); bufsize = EBX; if (bufsize) { mem_Free(bufpointer); bufpointer = mem_Alloc(bufsize); ReadFile(0, bufsize, bufpointer, path); read=1; } if (encoding!=CH_CP866) ChangeCharset(charsets[encoding], "CP866", bufpointer); } void FreeBuf() { int i; for (i=0; i=bufsize-1) break; } pos=0; } void DrawText() { int i, top, num_line; if (row_num
浏览器C--源代码 求参考 //KolibriOS browser source code //HTML Viewer in C-- //Copyright 2007-2013 by Veliant & Leency //Asper, lev, Lrz, Barsuk, Nable... //home icon - rachel fu, GPL licence #ifndef AUTOBUILD #include "lang.h--" #endif //libraries #define MEMSIZE 1060000 #include "..\lib\gui.h" #include "..\lib\draw_buf.h" #include "..\lib\list_box.h" #include "..\lib\cursor.h" #include "..\lib\collection.h" #include "..\lib\font.h" #include "..\lib\menu.h" //*.obj libraries #include "..\lib\obj\box_lib.h" #include "..\lib\obj\libio_lib.h" #include "..\lib\obj\libimg_lib.h" #include "..\lib\obj\http.h" #include "..\lib\obj\iconv.h" //useful patterns #include "..\lib\patterns\libimg_load_skin.h" #include "..\lib\patterns\history.h" #include "..\lib\patterns\http_downloader.h" char homepage[] = FROM "html\\homepage.htm"; #ifdef LANG_RUS char version[]=" Текстовый браузер 1.48"; ?define IMAGES_CACHE_CLEARED "Кэш картинок очищен" ?define T_LAST_SLIDE "Это последний слайд" char loading[] = "Загрузка страницы...<br>"; char page_not_found[] = FROM "html\page_not_found_ru.htm"; char accept_language[]= "Accept-Language: ru\n"; char rmb_menu[] = "Посмотреть исходник Редактировать исходник История Очистить кэш картинок Менеджер загрузок"; #else char version[]=" Text-based Browser 1.48"; ?define IMAGES_CACHE_CLEARED "Images cache cleared" ?define T_LAST_SLIDE "This slide is the last" char loading[] = "Loading...<br>"; char page_not_found[] = FROM "html\page_not_found_en.htm"; char accept_language[]= "Accept-Language: en\n"; char rmb_menu[] = "View source Edit source History Free image cache Download Manager"; #endif #define URL_SERVICE_HISTORY "WebView://history" #define URL_SERVICE_HOME "WebView://home" #define URL_SERVICE_SOURCE "WebView://source:" proc_info Form; //char search_path[]="http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fnigma.ru%2Findex.php%3Fs%3D&urlrefer=7ed5453cc63fc058d9b2fe505dc75095"; int redirected = 0; char stak[4096]; int action_buf; dword http_transfer = 0; dword http_buffer; dword TOOLBAR_H = 33; dword STATUSBAR_H = 15; dword col_bg; dword panel_color; dword border_color; progress_bar wv_progress_bar; byte souce_mode = false; enum { BACK_BUTTON=1000, FORWARD_BUTTON, REFRESH_BUTTON, GOTOURL_BUTTON, SANDWICH_BUTTON }; enum { VIEW_SOURCE=1100, EDIT_SOURCE, VIEW_HISTORY, FREE_IMG_CACHE, DOWNLOAD_MANAGER }; #include "..\TWB\TWB.c" #include "history.h" #include "show_src.h" #include "download_manager.h" char editURL[sizeof(URL)]; int mouse_twb; edit_box address_box = {250,56,34,0xffffff,0x94AECE,0xffffff,0xffffff,0,sizeof(URL),#editURL,#mouse_twb,2,19,19}; void main() { dword btn; int half_scroll_size; int scroll_used=0, show_menu; CursorPointer.Load(#CursorFile); load_dll(boxlib, #box_lib_init,0); load_dll(libio, #libio_init,1); load_dll(libimg, #libimg_init,1); load_dll(libHTTP, #http_lib_init,1); load_dll(iconv_lib, #iconv_open,0); Libimg_LoadImage(#skin, abspath("wv_skin.png")); SetSkinColors(); CreateDir("/tmp0/1/downloads"); if (param) strcpy(#URL, #param); else strcpy(#URL, URL_SERVICE_HOME); WB1.DrawBuf.zoom = 1; WB1.list.SetFont(8, 14, 10011000b); WB1.list.no_selection = true; label.init(DEFAULT_FONT); SetEventMask(0xa7); BEGIN_LOOP_APPLICATION: WaitEventTimeout(2); switch(EAX & 0xFF) { CASE evMouse: if (!CheckActiveProcess(Form.ID)) break; edit_box_mouse stdcall (#address_box); mouse.get(); if (WB1.list.MouseOver(mouse.x, mouse.y)) { PageLinks.Hover(mouse.x, WB1.list.first*WB1.list.item_h + mouse.y, link_color_inactive, link_color_active, bg_color); if (bufsize) && (mouse.pkm) && (mouse.up) { menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); break; } if (WB1.list.MouseScroll(mouse.vert)) WB1.DrawPage(); } scrollbar_v_mouse (#scroll_wv); if (WB1.list.first != scroll_wv.position) { WB1.list.first = scroll_wv.position; WB1.DrawPage(); break; } break; case evButton: btn=GetButtonID(); if (btn==1) ExitProcess(); Scan(btn); break; case evKey: GetKeys(); if (address_box.flags & 0b10) { if (key_ascii == ASCII_KEY_ENTER) Scan(key_scancode); else if (key_ascii != 0x0d) && (key_ascii != 183) && (key_ascii != 184) {EAX = key_ascii << 8; edit_box_key stdcall(#address_box);} } else { Scan(key_scancode); } break; case evReDraw: if (menu.list.cur_y) { Scan(menu.list.cur_y); menu.list.cur_y = 0; } DefineAndDrawWindow(GetScreenWidth()-800/2,GetScreenHeight()-600/2,800,600,0x73,col_bg,0,0); GetProcessInfo(#Form, SelfInfo); if (Form.status_window>2) { DrawTitle(#header); break; } if (Form.height<120) { MoveSize(OLD,OLD,OLD,120); break; } if (Form.width<280) { MoveSize(OLD,OLD,280,OLD); break; } Draw_Window(); break; case evNetwork: if (http_transfer > 0) { http_receive stdcall (http_transfer); $push EAX ESI = http_transfer; wv_progress_bar.max = ESI.http_msg.content_length; if (wv_progress_bar.value != ESI.http_msg.content_received) { wv_progress_bar.value = ESI.http_msg.content_received; DrawProgress(); } $pop EAX if (EAX == 0) { ESI = http_transfer; // Handle redirects if (ESI.http_msg.status >= 300) && (ESI.http_msg.status < 400) { redirected++; if (redirected<=5) { http_find_header_field stdcall (http_transfer, "location\0"); if (EAX!=0) { ESI = EAX; EDI = #URL; do { $lodsb; $stosb; } while (AL != 0) && (AL != 13) && (AL != 10)); DSBYTE[EDI-1]='\0'; } } else { notify("Too many redirects"); StopLoading(); break; } } else { redirected = 0; } // Loading the page is complete, free resources if (redirected>0) { http_free stdcall (http_transfer); http_transfer=0; GetAbsoluteURL(#URL); history.back(); strcpy(#editURL, #URL); DrawEditBoxWebView(); OpenPage(); } else { history.add(#URL); ESI = http_transfer; bufpointer = ESI.http_msg.content_ptr; bufsize = ESI.http_msg.content_received; http_free stdcall (http_transfer); http_transfer=0; SetPageDefaults(); ShowPage(); } } } } goto BEGIN_LOOP_APPLICATION; } void SetElementSizes() { address_box.top = TOOLBAR_H/2-7; address_box.width = Form.cwidth - address_box.left - 25 - 22; WB1.list.SetSizes(0, TOOLBAR_H, Form.width - 10 - scroll_wv.size_x / WB1.DrawBuf.zoom, Form.cheight - TOOLBAR_H - STATUSBAR_H, WB1.list.font_h + WB1.DrawBuf.zoom + WB1.DrawBuf.zoom * WB1.DrawBuf.zoom); WB1.list.wheel_size = 7; WB1.list.column_max = WB1.list.w - scroll_wv.size_x / WB1.list.font_w; WB1.list.visible = WB1.list.h - 5 / WB1.list.item_h; if (WB1.list.w!=WB1.DrawBuf.bufw) { WB1.DrawBuf.Init(WB1.list.x, WB1.list.y, WB1.list.w, WB1.list.h * 30); Scan(REFRESH_BUTTON); } } void Draw_Window() { int list__w, list__h; DrawBar(0,0, Form.cwidth,TOOLBAR_H-2, panel_color); DrawBar(0,TOOLBAR_H-2, Form.cwidth,1, 0xD7D0D3); DrawBar(0,TOOLBAR_H-1, Form.cwidth,1, border_color); SetElementSizes(); DrawRectangle(address_box.left-3, address_box.top-3, address_box.width+5, 20,border_color); DefineButton(address_box.left-50, address_box.top-2, 23, skin.h-2, BACK_BUTTON+BT_HIDE, 0); DefineButton(address_box.left-26, address_box.top-2, 23, skin.h-2, FORWARD_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, address_box.left-51, address_box.top-3, 48, skin.h, 3, 0); DefineButton(address_box.left+address_box.width+1, address_box.top-3, 16, skin.h-1, REFRESH_BUTTON+BT_HIDE+BT_NOFRAME, 0); DefineButton(Form.cwidth-24, address_box.top-3, 19, skin.h-1, SANDWICH_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, Form.cwidth-22, address_box.top-3, 16, skin.h, 85, 0); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,STATUSBAR_H, col_bg); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,1, border_color); if (!header) OpenPage(); else { WB1.DrawPage(); DrawEditBoxWebView(); } DrawRectangle(scroll_wv.start_x, scroll_wv.start_y, scroll_wv.size_x, scroll_wv.size_y-1, scroll_wv.bckg_col); DrawProgress(); /* list__w = 200; list__h = 200; label.raw_size = 0; label.write_buf(10,10, list__w, list__h, 0xFFFFFF, 0, 11, "Hello World!"); label.write_buf(10,23, list__w, list__h, 0xFFFFFF, 0xFF00FF, 12, "How are you?"); label.write_buf(11,40, list__w, list__h, 0xFFFFFF, 0x2E74BB, 15, "Fine"); label.apply_smooth(); label.show_buf(0,0); */ } void Scan(dword id__) { action_buf=0; if (WB1.list.ProcessKey(id__)) WB1.DrawPage(); else switch (id__) { case SCAN_CODE_BS: case BACK_BUTTON: if (history.back()) { strcpy(#URL, history.current()); OpenPage(); } return; case FORWARD_BUTTON: if (history.forward()) { strcpy(#URL, history.current()); OpenPage(); } return; case GOTOURL_BUTTON: case SCAN_CODE_ENTER: if (!strncmp(#editURL,"http:",5)) || (editURL[0]=='/') || (!strncmp(#editURL,"WebView:",9)) { strcpy(#URL, #editURL); } else { strlcpy(#URL,"http://",7); strcat(#URL, #editURL); } OpenPage(); return; case 063: //F5 IF(address_box.flags & 0b10) return; case REFRESH_BUTTON: if (http_transfer > 0) { StopLoading(); Draw_Window(); } else OpenPage(); return; case SANDWICH_BUTTON: mouse.y = TOOLBAR_H-6; mouse.x = Form.cwidth - 167; menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); return; case VIEW_SOURCE: WB1.list.first = 0; ShowSource(); WB1.LoadInternalPage(bufpointer, bufsize); break; case EDIT_SOURCE: if (!strncmp(#URL,"http:",5)) { WriteFile(bufsize, bufpointer, "/tmp0/1/WebView_tmp.htm"); if (!EAX) RunProgram("/rd/1/tinypad", "/tmp0/1/WebView_tmp.htm"); } else RunProgram("/rd/1/tinypad", #URL); return; case FREE_IMG_CACHE: ImgCache.Free(); notify(IMAGES_CACHE_CLEARED); WB1.DrawPage(); return; case VIEW_HISTORY: strcpy(#URL, URL_SERVICE_HISTORY); OpenPage(); return; case DOWNLOAD_MANAGER: if (!downloader_opened) { downloader_edit = NULL; CreateThread(#Downloader,#downloader_stak+4092); } return; } } void StopLoading() { if (http_transfer) { EAX = http_transfer; EAX = EAX.http_msg.content_ptr; // get pointer to data $push EAX // save it on the stack http_free stdcall (http_transfer); // abort connection $pop EAX free(EAX); // free data http_transfer=0; bufsize = 0; bufpointer = free(bufpointer); } wv_progress_bar.value = 0; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 52, 0); } void SetPageDefaults() { strcpy(#header, #version); WB1.list.count = WB1.list.first = 0; stroka = 0; cur_encoding = CH_NULL; if (o_bufpointer) o_bufpointer = free(o_bufpointer); anchor_line_num=WB1.list.first; anchor[0]='|'; } void OpenPage() { StopLoading(); souce_mode = false; strcpy(#editURL, #URL); history.add(#URL); if (!strncmp(#URL,"WebView:",8)) { SetPageDefaults(); if (!strcmp(#URL, URL_SERVICE_HOME)) WB1.LoadInternalPage(#homepage, sizeof(homepage)); else if (!strcmp(#URL, URL_SERVICE_HISTORY)) ShowHistory(); DrawEditBoxWebView(); return; } if (!strncmp(#URL,"http:",5)) { img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 131, 0); http_get stdcall (#URL, 0, 0, #accept_language); http_transfer = EAX; if (!http_transfer) { StopLoading(); bufsize = 0; bufpointer = free(bufpointer); ShowPage(); return; } } else { file_size stdcall (#URL); bufsize = EBX; if (bufsize) { free(bufpointer); bufpointer = malloc(bufsize); SetPageDefaults(); ReadFile(0, bufsize, bufpointer, #URL); } ShowPage(); } } DrawEditBoxWebView() { DrawWideRectangle(address_box.left-2, address_box.top-2, address_box.width+3, 19, 2, address_box.color); address_box.size = address_box.pos = address_box.shift = address_box.shift_old = strlen(#editURL); address_box.offset = 0; edit_box_draw stdcall(#address_box); if (http_transfer > 0) EAX = 131; else EAX = 52; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, EAX, 0); } void ShowPage() { DrawEditBoxWebView(); if (!bufsize) { if (http_transfer) WB1.LoadInternalPage(#loading, sizeof(loading)); else WB1.LoadInternalPage(#page_not_found, sizeof(page_not_found)); } else { WB1.Prepare(); } //if (!header) strcpy(#header, #version); if (!strcmp(#version, #header)) DrawTitle(#header); } byte UrlExtIs(dword ext) { if (!strcmpi(#URL + strlen(#URL) - strlen(ext), ext)) return true; return false; } int SetSkinColors() { dword image_data; image_data = DSDWORD[skin.image+24]; col_bg = DSDWORD[image_data]; panel_color = DSDWORD[skin.w*4*4 + image_data]; border_color = DSDWORD[skin.w*4*7 + image_data]; wv_progress_bar.progress_color = DSDWORD[skin.w*4*10 + image_data]; $and col_bg, 0x00ffffff $and panel_color, 0x00ffffff $and border_color, 0x00ffffff $and wv_progress_bar.progress_color, 0x00ffffff } void DrawProgress() { unsigned long btn; if (http_transfer == 0) return; if (wv_progress_bar.max) btn = address_box.width*wv_progress_bar.value/wv_progress_bar.max; else btn = 30; DrawBar(address_box.left-2, address_box.top+15, btn, 2, wv_progress_bar.progress_color); } void ClickLink() { if (http_transfer > 0) { StopLoading(); history.back(); } strcpy(#URL, PageLinks.GetURL(PageLinks.active)); //#1 if (URL[0] == '#') { strcpy(#anchor, #URL+strrchr(#URL, '#')); strcpy(#URL, history.current()); WB1.list.first=WB1.list.count-WB1.list.visible; ShowPage(); return; } //liner.ru#1 if (strrchr(#URL, '#')!=-1) { strcpy(#anchor, #URL+strrchr(#URL, '#')); URL[strrchr(#URL, '#')-1] = 0x00; } GetAbsoluteURL(#URL); if (UrlExtIs(".png")==1) || (UrlExtIs(".gif")==1) || (UrlExtIs(".jpg")==1) || (UrlExtIs(".zip")==1) || (UrlExtIs(".kex")==1) || (UrlExtIs(".7z")==1) || (UrlExtIs("netcfg")==1) { //notify(#URL); if (!strncmp(#URL,"http://", 7)) { strcpy(#downloader_edit, #URL); CreateThread(#Downloader,#downloader_stak+4092); } else RunProgram("@open", #URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } if (!strncmp(#URL,"mailto:", 7)) { notify(#URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } OpenPage(); return; } stop:
有人听说过C--麽 ? 我baidu了1下 wiki: en.wikipedia.org/wiki/C-- GITHUB: github.com/nrnrnr/qc--
C--是啥 ? 我baidu了1下 //KolibriOS browser source code //HTML Viewer in C-- //Copyright 2007-2013 by Veliant & Leency //Asper, lev, Lrz, Barsuk, Nable... //home icon - rachel fu, GPL licence #ifndef AUTOBUILD #include "lang.h--" #endif //libraries #define MEMSIZE 1060000 #include "..\lib\gui.h" #include "..\lib\draw_buf.h" #include "..\lib\list_box.h" #include "..\lib\cursor.h" #include "..\lib\collection.h" #include "..\lib\font.h" #include "..\lib\menu.h" //*.obj libraries #include "..\lib\obj\box_lib.h" #include "..\lib\obj\libio_lib.h" #include "..\lib\obj\libimg_lib.h" #include "..\lib\obj\http.h" #include "..\lib\obj\iconv.h" //useful patterns #include "..\lib\patterns\libimg_load_skin.h" #include "..\lib\patterns\history.h" #include "..\lib\patterns\http_downloader.h" char homepage[] = FROM "html\\homepage.htm"; #ifdef LANG_RUS char version[]=" Текстовый браузер 1.48"; ?define IMAGES_CACHE_CLEARED "Кэш картинок очищен" ?define T_LAST_SLIDE "Это последний слайд" char loading[] = "Загрузка страницы...<br>"; char page_not_found[] = FROM "html\page_not_found_ru.htm"; char accept_language[]= "Accept-Language: ru\n"; char rmb_menu[] = "Посмотреть исходник Редактировать исходник История Очистить кэш картинок Менеджер загрузок"; #else char version[]=" Text-based Browser 1.48"; ?define IMAGES_CACHE_CLEARED "Images cache cleared" ?define T_LAST_SLIDE "This slide is the last" char loading[] = "Loading...<br>"; char page_not_found[] = FROM "html\page_not_found_en.htm"; char accept_language[]= "Accept-Language: en\n"; char rmb_menu[] = "View source Edit source History Free image cache Download Manager"; #endif #define URL_SERVICE_HISTORY "WebView://history" #define URL_SERVICE_HOME "WebView://home" #define URL_SERVICE_SOURCE "WebView://source:" proc_info Form; //char search_path[]="http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fnigma.ru%2Findex.php%3Fs%3D&urlrefer=7ed5453cc63fc058d9b2fe505dc75095"; int redirected = 0; char stak[4096]; int action_buf; dword http_transfer = 0; dword http_buffer; dword TOOLBAR_H = 33; dword STATUSBAR_H = 15; dword col_bg; dword panel_color; dword border_color; progress_bar wv_progress_bar; byte souce_mode = false; enum { BACK_BUTTON=1000, FORWARD_BUTTON, REFRESH_BUTTON, GOTOURL_BUTTON, SANDWICH_BUTTON }; enum { VIEW_SOURCE=1100, EDIT_SOURCE, VIEW_HISTORY, FREE_IMG_CACHE, DOWNLOAD_MANAGER }; #include "..\TWB\TWB.c" #include "history.h" #include "show_src.h" #include "download_manager.h" char editURL[sizeof(URL)]; int mouse_twb; edit_box address_box = {250,56,34,0xffffff,0x94AECE,0xffffff,0xffffff,0,sizeof(URL),#editURL,#mouse_twb,2,19,19}; void main() { dword btn; int half_scroll_size; int scroll_used=0, show_menu; CursorPointer.Load(#CursorFile); load_dll(boxlib, #box_lib_init,0); load_dll(libio, #libio_init,1); load_dll(libimg, #libimg_init,1); load_dll(libHTTP, #http_lib_init,1); load_dll(iconv_lib, #iconv_open,0); Libimg_LoadImage(#skin, abspath("wv_skin.png")); SetSkinColors(); CreateDir("/tmp0/1/downloads"); if (param) strcpy(#URL, #param); else strcpy(#URL, URL_SERVICE_HOME); WB1.DrawBuf.zoom = 1; WB1.list.SetFont(8, 14, 10011000b); WB1.list.no_selection = true; label.init(DEFAULT_FONT); SetEventMask(0xa7); BEGIN_LOOP_APPLICATION: WaitEventTimeout(2); switch(EAX & 0xFF) { CASE evMouse: if (!CheckActiveProcess(Form.ID)) break; edit_box_mouse stdcall (#address_box); mouse.get(); if (WB1.list.MouseOver(mouse.x, mouse.y)) { PageLinks.Hover(mouse.x, WB1.list.first*WB1.list.item_h + mouse.y, link_color_inactive, link_color_active, bg_color); if (bufsize) && (mouse.pkm) && (mouse.up) { menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); break; } if (WB1.list.MouseScroll(mouse.vert)) WB1.DrawPage(); } scrollbar_v_mouse (#scroll_wv); if (WB1.list.first != scroll_wv.position) { WB1.list.first = scroll_wv.position; WB1.DrawPage(); break; } break; case evButton: btn=GetButtonID(); if (btn==1) ExitProcess(); Scan(btn); break; case evKey: GetKeys(); if (address_box.flags & 0b10) { if (key_ascii == ASCII_KEY_ENTER) Scan(key_scancode); else if (key_ascii != 0x0d) && (key_ascii != 183) && (key_ascii != 184) {EAX = key_ascii << 8; edit_box_key stdcall(#address_box);} } else { Scan(key_scancode); } break; case evReDraw: if (menu.list.cur_y) { Scan(menu.list.cur_y); menu.list.cur_y = 0; } DefineAndDrawWindow(GetScreenWidth()-800/2,GetScreenHeight()-600/2,800,600,0x73,col_bg,0,0); GetProcessInfo(#Form, SelfInfo); if (Form.status_window>2) { DrawTitle(#header); break; } if (Form.height<120) { MoveSize(OLD,OLD,OLD,120); break; } if (Form.width<280) { MoveSize(OLD,OLD,280,OLD); break; } Draw_Window(); break; case evNetwork: if (http_transfer > 0) { http_receive stdcall (http_transfer); $push EAX ESI = http_transfer; wv_progress_bar.max = ESI.http_msg.content_length; if (wv_progress_bar.value != ESI.http_msg.content_received) { wv_progress_bar.value = ESI.http_msg.content_received; DrawProgress(); } $pop EAX if (EAX == 0) { ESI = http_transfer; // Handle redirects if (ESI.http_msg.status >= 300) && (ESI.http_msg.status < 400) { redirected++; if (redirected<=5) { http_find_header_field stdcall (http_transfer, "location\0"); if (EAX!=0) { ESI = EAX; EDI = #URL; do { $lodsb; $stosb; } while (AL != 0) && (AL != 13) && (AL != 10)); DSBYTE[EDI-1]='\0'; } } else { notify("Too many redirects"); StopLoading(); break; } } else { redirected = 0; } // Loading the page is complete, free resources if (redirected>0) { http_free stdcall (http_transfer); http_transfer=0; GetAbsoluteURL(#URL); history.back(); strcpy(#editURL, #URL); DrawEditBoxWebView(); OpenPage(); } else { history.add(#URL); ESI = http_transfer; bufpointer = ESI.http_msg.content_ptr; bufsize = ESI.http_msg.content_received; http_free stdcall (http_transfer); http_transfer=0; SetPageDefaults(); ShowPage(); } } } } goto BEGIN_LOOP_APPLICATION; } void SetElementSizes() { address_box.top = TOOLBAR_H/2-7; address_box.width = Form.cwidth - address_box.left - 25 - 22; WB1.list.SetSizes(0, TOOLBAR_H, Form.width - 10 - scroll_wv.size_x / WB1.DrawBuf.zoom, Form.cheight - TOOLBAR_H - STATUSBAR_H, WB1.list.font_h + WB1.DrawBuf.zoom + WB1.DrawBuf.zoom * WB1.DrawBuf.zoom); WB1.list.wheel_size = 7; WB1.list.column_max = WB1.list.w - scroll_wv.size_x / WB1.list.font_w; WB1.list.visible = WB1.list.h - 5 / WB1.list.item_h; if (WB1.list.w!=WB1.DrawBuf.bufw) { WB1.DrawBuf.Init(WB1.list.x, WB1.list.y, WB1.list.w, WB1.list.h * 30); Scan(REFRESH_BUTTON); } } void Draw_Window() { int list__w, list__h; DrawBar(0,0, Form.cwidth,TOOLBAR_H-2, panel_color); DrawBar(0,TOOLBAR_H-2, Form.cwidth,1, 0xD7D0D3); DrawBar(0,TOOLBAR_H-1, Form.cwidth,1, border_color); SetElementSizes(); DrawRectangle(address_box.left-3, address_box.top-3, address_box.width+5, 20,border_color); DefineButton(address_box.left-50, address_box.top-2, 23, skin.h-2, BACK_BUTTON+BT_HIDE, 0); DefineButton(address_box.left-26, address_box.top-2, 23, skin.h-2, FORWARD_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, address_box.left-51, address_box.top-3, 48, skin.h, 3, 0); DefineButton(address_box.left+address_box.width+1, address_box.top-3, 16, skin.h-1, REFRESH_BUTTON+BT_HIDE+BT_NOFRAME, 0); DefineButton(Form.cwidth-24, address_box.top-3, 19, skin.h-1, SANDWICH_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, Form.cwidth-22, address_box.top-3, 16, skin.h, 85, 0); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,STATUSBAR_H, col_bg); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,1, border_color); if (!header) OpenPage(); else { WB1.DrawPage(); DrawEditBoxWebView(); } DrawRectangle(scroll_wv.start_x, scroll_wv.start_y, scroll_wv.size_x, scroll_wv.size_y-1, scroll_wv.bckg_col); DrawProgress(); /* list__w = 200; list__h = 200; label.raw_size = 0; label.write_buf(10,10, list__w, list__h, 0xFFFFFF, 0, 11, "Hello World!"); label.write_buf(10,23, list__w, list__h, 0xFFFFFF, 0xFF00FF, 12, "How are you?"); label.write_buf(11,40, list__w, list__h, 0xFFFFFF, 0x2E74BB, 15, "Fine"); label.apply_smooth(); label.show_buf(0,0); */ } void Scan(dword id__) { action_buf=0; if (WB1.list.ProcessKey(id__)) WB1.DrawPage(); else switch (id__) { case SCAN_CODE_BS: case BACK_BUTTON: if (history.back()) { strcpy(#URL, history.current()); OpenPage(); } return; case FORWARD_BUTTON: if (history.forward()) { strcpy(#URL, history.current()); OpenPage(); } return; case GOTOURL_BUTTON: case SCAN_CODE_ENTER: if (!strncmp(#editURL,"http:",5)) || (editURL[0]=='/') || (!strncmp(#editURL,"WebView:",9)) { strcpy(#URL, #editURL); } else { strlcpy(#URL,"http://",7); strcat(#URL, #editURL); } OpenPage(); return; case 063: //F5 IF(address_box.flags & 0b10) return; case REFRESH_BUTTON: if (http_transfer > 0) { StopLoading(); Draw_Window(); } else OpenPage(); return; case SANDWICH_BUTTON: mouse.y = TOOLBAR_H-6; mouse.x = Form.cwidth - 167; menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); return; case VIEW_SOURCE: WB1.list.first = 0; ShowSource(); WB1.LoadInternalPage(bufpointer, bufsize); break; case EDIT_SOURCE: if (!strncmp(#URL,"http:",5)) { WriteFile(bufsize, bufpointer, "/tmp0/1/WebView_tmp.htm"); if (!EAX) RunProgram("/rd/1/tinypad", "/tmp0/1/WebView_tmp.htm"); } else RunProgram("/rd/1/tinypad", #URL); return; case FREE_IMG_CACHE: ImgCache.Free(); notify(IMAGES_CACHE_CLEARED); WB1.DrawPage(); return; case VIEW_HISTORY: strcpy(#URL, URL_SERVICE_HISTORY); OpenPage(); return; case DOWNLOAD_MANAGER: if (!downloader_opened) { downloader_edit = NULL; CreateThread(#Downloader,#downloader_stak+4092); } return; } } void StopLoading() { if (http_transfer) { EAX = http_transfer; EAX = EAX.http_msg.content_ptr; // get pointer to data $push EAX // save it on the stack http_free stdcall (http_transfer); // abort connection $pop EAX free(EAX); // free data http_transfer=0; bufsize = 0; bufpointer = free(bufpointer); } wv_progress_bar.value = 0; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 52, 0); } void SetPageDefaults() { strcpy(#header, #version); WB1.list.count = WB1.list.first = 0; stroka = 0; cur_encoding = CH_NULL; if (o_bufpointer) o_bufpointer = free(o_bufpointer); anchor_line_num=WB1.list.first; anchor[0]='|'; } void OpenPage() { StopLoading(); souce_mode = false; strcpy(#editURL, #URL); history.add(#URL); if (!strncmp(#URL,"WebView:",8)) { SetPageDefaults(); if (!strcmp(#URL, URL_SERVICE_HOME)) WB1.LoadInternalPage(#homepage, sizeof(homepage)); else if (!strcmp(#URL, URL_SERVICE_HISTORY)) ShowHistory(); DrawEditBoxWebView(); return; } if (!strncmp(#URL,"http:",5)) { img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 131, 0); http_get stdcall (#URL, 0, 0, #accept_language); http_transfer = EAX; if (!http_transfer) { StopLoading(); bufsize = 0; bufpointer = free(bufpointer); ShowPage(); return; } } else { file_size stdcall (#URL); bufsize = EBX; if (bufsize) { free(bufpointer); bufpointer = malloc(bufsize); SetPageDefaults(); ReadFile(0, bufsize, bufpointer, #URL); } ShowPage(); } } DrawEditBoxWebView() { DrawWideRectangle(address_box.left-2, address_box.top-2, address_box.width+3, 19, 2, address_box.color); address_box.size = address_box.pos = address_box.shift = address_box.shift_old = strlen(#editURL); address_box.offset = 0; edit_box_draw stdcall(#address_box); if (http_transfer > 0) EAX = 131; else EAX = 52; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, EAX, 0); } void ShowPage() { DrawEditBoxWebView(); if (!bufsize) { if (http_transfer) WB1.LoadInternalPage(#loading, sizeof(loading)); else WB1.LoadInternalPage(#page_not_found, sizeof(page_not_found)); } else { WB1.Prepare(); } //if (!header) strcpy(#header, #version); if (!strcmp(#version, #header)) DrawTitle(#header); } byte UrlExtIs(dword ext) { if (!strcmpi(#URL + strlen(#URL) - strlen(ext), ext)) return true; return false; } int SetSkinColors() { dword image_data; image_data = DSDWORD[skin.image+24]; col_bg = DSDWORD[image_data]; panel_color = DSDWORD[skin.w*4*4 + image_data]; border_color = DSDWORD[skin.w*4*7 + image_data]; wv_progress_bar.progress_color = DSDWORD[skin.w*4*10 + image_data]; $and col_bg, 0x00ffffff $and panel_color, 0x00ffffff $and border_color, 0x00ffffff $and wv_progress_bar.progress_color, 0x00ffffff } void DrawProgress() { unsigned long btn; if (http_transfer == 0) return; if (wv_progress_bar.max) btn = address_box.width*wv_progress_bar.value/wv_progress_bar.max; else btn = 30; DrawBar(address_box.left-2, address_box.top+15, btn, 2, wv_progress_bar.progress_color); } void ClickLink() { if (http_transfer > 0) { StopLoading(); history.back(); } strcpy(#URL, PageLinks.GetURL(PageLinks.active)); //#1 if (URL[0] == '#') { strcpy(#anchor, #URL+strrchr(#URL, '#')); strcpy(#URL, history.current()); WB1.list.first=WB1.list.count-WB1.list.visible; ShowPage(); return; } //liner.ru#1 if (strrchr(#URL, '#')!=-1) { strcpy(#anchor, #URL+strrchr(#URL, '#')); URL[strrchr(#URL, '#')-1] = 0x00; } GetAbsoluteURL(#URL); if (UrlExtIs(".png")==1) || (UrlExtIs(".gif")==1) || (UrlExtIs(".jpg")==1) || (UrlExtIs(".zip")==1) || (UrlExtIs(".kex")==1) || (UrlExtIs(".7z")==1) || (UrlExtIs("netcfg")==1) { //notify(#URL); if (!strncmp(#URL,"http://", 7)) { strcpy(#downloader_edit, #URL); CreateThread(#Downloader,#downloader_stak+4092); } else RunProgram("@open", #URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } if (!strncmp(#URL,"mailto:", 7)) { notify(#URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } OpenPage(); return; } stop:
c--是可移植汇编 ? 求本吧开辟相关位置.. wiki: en.wikipedia.org/wiki/C-- 网站URL: cs.tufts.edu/~nr/c--/index.html GITHUB: github.com/nrnrnr/qc--
大神来鉴定下C--哒语法 感觉是x86汇编与C哒结合体.. //KolibriOS browser source code //HTML Viewer in C-- //Copyright 2007-2013 by Veliant & Leency //Asper, lev, Lrz, Barsuk, Nable... //home icon - rachel fu, GPL licence #ifndef AUTOBUILD #include "lang.h--" #endif //libraries #define MEMSIZE 1060000 #include "..\lib\gui.h" #include "..\lib\draw_buf.h" #include "..\lib\list_box.h" #include "..\lib\cursor.h" #include "..\lib\collection.h" #include "..\lib\font.h" #include "..\lib\menu.h" //*.obj libraries #include "..\lib\obj\box_lib.h" #include "..\lib\obj\libio_lib.h" #include "..\lib\obj\libimg_lib.h" #include "..\lib\obj\http.h" #include "..\lib\obj\iconv.h" //useful patterns #include "..\lib\patterns\libimg_load_skin.h" #include "..\lib\patterns\history.h" #include "..\lib\patterns\http_downloader.h" char homepage[] = FROM "html\\homepage.htm"; #ifdef LANG_RUS char version[]=" Текстовый браузер 1.48"; ?define IMAGES_CACHE_CLEARED "Кэш картинок очищен" ?define T_LAST_SLIDE "Это последний слайд" char loading[] = "Загрузка страницы...<br>"; char page_not_found[] = FROM "html\page_not_found_ru.htm"; char accept_language[]= "Accept-Language: ru\n"; char rmb_menu[] = "Посмотреть исходник Редактировать исходник История Очистить кэш картинок Менеджер загрузок"; #else char version[]=" Text-based Browser 1.48"; ?define IMAGES_CACHE_CLEARED "Images cache cleared" ?define T_LAST_SLIDE "This slide is the last" char loading[] = "Loading...<br>"; char page_not_found[] = FROM "html\page_not_found_en.htm"; char accept_language[]= "Accept-Language: en\n"; char rmb_menu[] = "View source Edit source History Free image cache Download Manager"; #endif #define URL_SERVICE_HISTORY "WebView://history" #define URL_SERVICE_HOME "WebView://home" #define URL_SERVICE_SOURCE "WebView://source:" proc_info Form; //char search_path[]="http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fnigma.ru%2Findex.php%3Fs%3D&urlrefer=7ed5453cc63fc058d9b2fe505dc75095"; int redirected = 0; char stak[4096]; int action_buf; dword http_transfer = 0; dword http_buffer; dword TOOLBAR_H = 33; dword STATUSBAR_H = 15; dword col_bg; dword panel_color; dword border_color; progress_bar wv_progress_bar; byte souce_mode = false; enum { BACK_BUTTON=1000, FORWARD_BUTTON, REFRESH_BUTTON, GOTOURL_BUTTON, SANDWICH_BUTTON }; enum { VIEW_SOURCE=1100, EDIT_SOURCE, VIEW_HISTORY, FREE_IMG_CACHE, DOWNLOAD_MANAGER }; #include "..\TWB\TWB.c" #include "history.h" #include "show_src.h" #include "download_manager.h" char editURL[sizeof(URL)]; int mouse_twb; edit_box address_box = {250,56,34,0xffffff,0x94AECE,0xffffff,0xffffff,0,sizeof(URL),#editURL,#mouse_twb,2,19,19}; void main() { dword btn; int half_scroll_size; int scroll_used=0, show_menu; CursorPointer.Load(#CursorFile); load_dll(boxlib, #box_lib_init,0); load_dll(libio, #libio_init,1); load_dll(libimg, #libimg_init,1); load_dll(libHTTP, #http_lib_init,1); load_dll(iconv_lib, #iconv_open,0); Libimg_LoadImage(#skin, abspath("wv_skin.png")); SetSkinColors(); CreateDir("/tmp0/1/downloads"); if (param) strcpy(#URL, #param); else strcpy(#URL, URL_SERVICE_HOME); WB1.DrawBuf.zoom = 1; WB1.list.SetFont(8, 14, 10011000b); WB1.list.no_selection = true; label.init(DEFAULT_FONT); SetEventMask(0xa7); BEGIN_LOOP_APPLICATION: WaitEventTimeout(2); switch(EAX & 0xFF) { CASE evMouse: if (!CheckActiveProcess(Form.ID)) break; edit_box_mouse stdcall (#address_box); mouse.get(); if (WB1.list.MouseOver(mouse.x, mouse.y)) { PageLinks.Hover(mouse.x, WB1.list.first*WB1.list.item_h + mouse.y, link_color_inactive, link_color_active, bg_color); if (bufsize) && (mouse.pkm) && (mouse.up) { menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); break; } if (WB1.list.MouseScroll(mouse.vert)) WB1.DrawPage(); } scrollbar_v_mouse (#scroll_wv); if (WB1.list.first != scroll_wv.position) { WB1.list.first = scroll_wv.position; WB1.DrawPage(); break; } break; case evButton: btn=GetButtonID(); if (btn==1) ExitProcess(); Scan(btn); break; case evKey: GetKeys(); if (address_box.flags & 0b10) { if (key_ascii == ASCII_KEY_ENTER) Scan(key_scancode); else if (key_ascii != 0x0d) && (key_ascii != 183) && (key_ascii != 184) {EAX = key_ascii << 8; edit_box_key stdcall(#address_box);} } else { Scan(key_scancode); } break; case evReDraw: if (menu.list.cur_y) { Scan(menu.list.cur_y); menu.list.cur_y = 0; } DefineAndDrawWindow(GetScreenWidth()-800/2,GetScreenHeight()-600/2,800,600,0x73,col_bg,0,0); GetProcessInfo(#Form, SelfInfo); if (Form.status_window>2) { DrawTitle(#header); break; } if (Form.height<120) { MoveSize(OLD,OLD,OLD,120); break; } if (Form.width<280) { MoveSize(OLD,OLD,280,OLD); break; } Draw_Window(); break; case evNetwork: if (http_transfer > 0) { http_receive stdcall (http_transfer); $push EAX ESI = http_transfer; wv_progress_bar.max = ESI.http_msg.content_length; if (wv_progress_bar.value != ESI.http_msg.content_received) { wv_progress_bar.value = ESI.http_msg.content_received; DrawProgress(); } $pop EAX if (EAX == 0) { ESI = http_transfer; // Handle redirects if (ESI.http_msg.status >= 300) && (ESI.http_msg.status < 400) { redirected++; if (redirected<=5) { http_find_header_field stdcall (http_transfer, "location\0"); if (EAX!=0) { ESI = EAX; EDI = #URL; do { $lodsb; $stosb; } while (AL != 0) && (AL != 13) && (AL != 10)); DSBYTE[EDI-1]='\0'; } } else { notify("Too many redirects"); StopLoading(); break; } } else { redirected = 0; } // Loading the page is complete, free resources if (redirected>0) { http_free stdcall (http_transfer); http_transfer=0; GetAbsoluteURL(#URL); history.back(); strcpy(#editURL, #URL); DrawEditBoxWebView(); OpenPage(); } else { history.add(#URL); ESI = http_transfer; bufpointer = ESI.http_msg.content_ptr; bufsize = ESI.http_msg.content_received; http_free stdcall (http_transfer); http_transfer=0; SetPageDefaults(); ShowPage(); } } } } goto BEGIN_LOOP_APPLICATION; } void SetElementSizes() { address_box.top = TOOLBAR_H/2-7; address_box.width = Form.cwidth - address_box.left - 25 - 22; WB1.list.SetSizes(0, TOOLBAR_H, Form.width - 10 - scroll_wv.size_x / WB1.DrawBuf.zoom, Form.cheight - TOOLBAR_H - STATUSBAR_H, WB1.list.font_h + WB1.DrawBuf.zoom + WB1.DrawBuf.zoom * WB1.DrawBuf.zoom); WB1.list.wheel_size = 7; WB1.list.column_max = WB1.list.w - scroll_wv.size_x / WB1.list.font_w; WB1.list.visible = WB1.list.h - 5 / WB1.list.item_h; if (WB1.list.w!=WB1.DrawBuf.bufw) { WB1.DrawBuf.Init(WB1.list.x, WB1.list.y, WB1.list.w, WB1.list.h * 30); Scan(REFRESH_BUTTON); } } void Draw_Window() { int list__w, list__h; DrawBar(0,0, Form.cwidth,TOOLBAR_H-2, panel_color); DrawBar(0,TOOLBAR_H-2, Form.cwidth,1, 0xD7D0D3); DrawBar(0,TOOLBAR_H-1, Form.cwidth,1, border_color); SetElementSizes(); DrawRectangle(address_box.left-3, address_box.top-3, address_box.width+5, 20,border_color); DefineButton(address_box.left-50, address_box.top-2, 23, skin.h-2, BACK_BUTTON+BT_HIDE, 0); DefineButton(address_box.left-26, address_box.top-2, 23, skin.h-2, FORWARD_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, address_box.left-51, address_box.top-3, 48, skin.h, 3, 0); DefineButton(address_box.left+address_box.width+1, address_box.top-3, 16, skin.h-1, REFRESH_BUTTON+BT_HIDE+BT_NOFRAME, 0); DefineButton(Form.cwidth-24, address_box.top-3, 19, skin.h-1, SANDWICH_BUTTON+BT_HIDE, 0); img_draw stdcall(skin.image, Form.cwidth-22, address_box.top-3, 16, skin.h, 85, 0); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,STATUSBAR_H, col_bg); DrawBar(0,Form.cheight - STATUSBAR_H, Form.cwidth,1, border_color); if (!header) OpenPage(); else { WB1.DrawPage(); DrawEditBoxWebView(); } DrawRectangle(scroll_wv.start_x, scroll_wv.start_y, scroll_wv.size_x, scroll_wv.size_y-1, scroll_wv.bckg_col); DrawProgress(); /* list__w = 200; list__h = 200; label.raw_size = 0; label.write_buf(10,10, list__w, list__h, 0xFFFFFF, 0, 11, "Hello World!"); label.write_buf(10,23, list__w, list__h, 0xFFFFFF, 0xFF00FF, 12, "How are you?"); label.write_buf(11,40, list__w, list__h, 0xFFFFFF, 0x2E74BB, 15, "Fine"); label.apply_smooth(); label.show_buf(0,0); */ } void Scan(dword id__) { action_buf=0; if (WB1.list.ProcessKey(id__)) WB1.DrawPage(); else switch (id__) { case SCAN_CODE_BS: case BACK_BUTTON: if (history.back()) { strcpy(#URL, history.current()); OpenPage(); } return; case FORWARD_BUTTON: if (history.forward()) { strcpy(#URL, history.current()); OpenPage(); } return; case GOTOURL_BUTTON: case SCAN_CODE_ENTER: if (!strncmp(#editURL,"http:",5)) || (editURL[0]=='/') || (!strncmp(#editURL,"WebView:",9)) { strcpy(#URL, #editURL); } else { strlcpy(#URL,"http://",7); strcat(#URL, #editURL); } OpenPage(); return; case 063: //F5 IF(address_box.flags & 0b10) return; case REFRESH_BUTTON: if (http_transfer > 0) { StopLoading(); Draw_Window(); } else OpenPage(); return; case SANDWICH_BUTTON: mouse.y = TOOLBAR_H-6; mouse.x = Form.cwidth - 167; menu.show(Form.left+mouse.x-6,Form.top+mouse.y+skin_height+3, 180, #rmb_menu, VIEW_SOURCE); return; case VIEW_SOURCE: WB1.list.first = 0; ShowSource(); WB1.LoadInternalPage(bufpointer, bufsize); break; case EDIT_SOURCE: if (!strncmp(#URL,"http:",5)) { WriteFile(bufsize, bufpointer, "/tmp0/1/WebView_tmp.htm"); if (!EAX) RunProgram("/rd/1/tinypad", "/tmp0/1/WebView_tmp.htm"); } else RunProgram("/rd/1/tinypad", #URL); return; case FREE_IMG_CACHE: ImgCache.Free(); notify(IMAGES_CACHE_CLEARED); WB1.DrawPage(); return; case VIEW_HISTORY: strcpy(#URL, URL_SERVICE_HISTORY); OpenPage(); return; case DOWNLOAD_MANAGER: if (!downloader_opened) { downloader_edit = NULL; CreateThread(#Downloader,#downloader_stak+4092); } return; } } void StopLoading() { if (http_transfer) { EAX = http_transfer; EAX = EAX.http_msg.content_ptr; // get pointer to data $push EAX // save it on the stack http_free stdcall (http_transfer); // abort connection $pop EAX free(EAX); // free data http_transfer=0; bufsize = 0; bufpointer = free(bufpointer); } wv_progress_bar.value = 0; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 52, 0); } void SetPageDefaults() { strcpy(#header, #version); WB1.list.count = WB1.list.first = 0; stroka = 0; cur_encoding = CH_NULL; if (o_bufpointer) o_bufpointer = free(o_bufpointer); anchor_line_num=WB1.list.first; anchor[0]='|'; } void OpenPage() { StopLoading(); souce_mode = false; strcpy(#editURL, #URL); history.add(#URL); if (!strncmp(#URL,"WebView:",8)) { SetPageDefaults(); if (!strcmp(#URL, URL_SERVICE_HOME)) WB1.LoadInternalPage(#homepage, sizeof(homepage)); else if (!strcmp(#URL, URL_SERVICE_HISTORY)) ShowHistory(); DrawEditBoxWebView(); return; } if (!strncmp(#URL,"http:",5)) { img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, 131, 0); http_get stdcall (#URL, 0, 0, #accept_language); http_transfer = EAX; if (!http_transfer) { StopLoading(); bufsize = 0; bufpointer = free(bufpointer); ShowPage(); return; } } else { file_size stdcall (#URL); bufsize = EBX; if (bufsize) { free(bufpointer); bufpointer = malloc(bufsize); SetPageDefaults(); ReadFile(0, bufsize, bufpointer, #URL); } ShowPage(); } } DrawEditBoxWebView() { DrawWideRectangle(address_box.left-2, address_box.top-2, address_box.width+3, 19, 2, address_box.color); address_box.size = address_box.pos = address_box.shift = address_box.shift_old = strlen(#editURL); address_box.offset = 0; edit_box_draw stdcall(#address_box); if (http_transfer > 0) EAX = 131; else EAX = 52; img_draw stdcall(skin.image, address_box.left+address_box.width+1, address_box.top-3, 17, skin.h, EAX, 0); } void ShowPage() { DrawEditBoxWebView(); if (!bufsize) { if (http_transfer) WB1.LoadInternalPage(#loading, sizeof(loading)); else WB1.LoadInternalPage(#page_not_found, sizeof(page_not_found)); } else { WB1.Prepare(); } //if (!header) strcpy(#header, #version); if (!strcmp(#version, #header)) DrawTitle(#header); } byte UrlExtIs(dword ext) { if (!strcmpi(#URL + strlen(#URL) - strlen(ext), ext)) return true; return false; } int SetSkinColors() { dword image_data; image_data = DSDWORD[skin.image+24]; col_bg = DSDWORD[image_data]; panel_color = DSDWORD[skin.w*4*4 + image_data]; border_color = DSDWORD[skin.w*4*7 + image_data]; wv_progress_bar.progress_color = DSDWORD[skin.w*4*10 + image_data]; $and col_bg, 0x00ffffff $and panel_color, 0x00ffffff $and border_color, 0x00ffffff $and wv_progress_bar.progress_color, 0x00ffffff } void DrawProgress() { unsigned long btn; if (http_transfer == 0) return; if (wv_progress_bar.max) btn = address_box.width*wv_progress_bar.value/wv_progress_bar.max; else btn = 30; DrawBar(address_box.left-2, address_box.top+15, btn, 2, wv_progress_bar.progress_color); } void ClickLink() { if (http_transfer > 0) { StopLoading(); history.back(); } strcpy(#URL, PageLinks.GetURL(PageLinks.active)); //#1 if (URL[0] == '#') { strcpy(#anchor, #URL+strrchr(#URL, '#')); strcpy(#URL, history.current()); WB1.list.first=WB1.list.count-WB1.list.visible; ShowPage(); return; } //liner.ru#1 if (strrchr(#URL, '#')!=-1) { strcpy(#anchor, #URL+strrchr(#URL, '#')); URL[strrchr(#URL, '#')-1] = 0x00; } GetAbsoluteURL(#URL); if (UrlExtIs(".png")==1) || (UrlExtIs(".gif")==1) || (UrlExtIs(".jpg")==1) || (UrlExtIs(".zip")==1) || (UrlExtIs(".kex")==1) || (UrlExtIs(".7z")==1) || (UrlExtIs("netcfg")==1) { //notify(#URL); if (!strncmp(#URL,"http://", 7)) { strcpy(#downloader_edit, #URL); CreateThread(#Downloader,#downloader_stak+4092); } else RunProgram("@open", #URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } if (!strncmp(#URL,"mailto:", 7)) { notify(#URL); strcpy(#editURL, history.current()); strcpy(#URL, history.current()); return; } OpenPage(); return; } stop:
freescale哒PowerPC汇编
arm thumb16位汇编
萌萌新求汇编dll范例
萌萌新求问 ReactOS能运行 sciTE文本编辑器吗(类似于Notepad+) ? 求科普..
萌萌新求问 哪些汇编哒编译器能生成dll ? 求科普.. 萌萌新求问 哪些汇编哒编译器能生成dll ? 求科普..
1个flash浏览器插件ActiveX ocx文件竟有70000多个子程序.. 1个flash浏览器插件ActiveX ocx文件竟有70000多个子程序..
1个flash浏览器插件ActiveX ocx文件竟有70000多个子程序.. 1个flash浏览器插件ActiveX ocx文件竟有70000多个子程序..
萌萌新求问用HLA怎样生成循环链表 求教大神
有大神知道如何用纯c生成ocx吗?求科普.. vxdev.com/docs/vx55man/vxworks/guide/ 真好看 o(^_^)o c与c++哒极致使用 值得一看
有大神知道如何用纯c生成ocx吗?求科普..
新手求问 emacs可以在vxworks x86上用吗
vxdev.com/docs/vx55man/vxworks/guide/ 真好看 vxdev.com/docs/vx55man/vxworks/guide/ 真好看
有高手1起来做游戏吗o(^_^)o
大神求51 c程序
强烈要求引入arm哒汇编o(^_^)o 与时俱进!
贪吃蛇snake
有高手1起来做游戏吗 ?
有高手来1起做游戏吗 o(^_^)o
求问 怎样不通过c++操作内存dc
萌萌新求问
刚才那个要管理信息系统哒装gtk
刚才那个要dos局域网聊天哒装cygwin
萌萌新求问 gcc之类哒c编译器支持内嵌汇编_asm{ 吗 ?
64位汇编怎样实现人物移动sprite动画
求剪贴板clipboard64位汇编代码
神奇海螺新人求问 gcc之类哒c编译器有没有inline功能?
新人求问 gcc之类哒c编译器有没有inline功能?
lightSpark代码怎么都是c++ 求c代码版
有人评测一下 [鱼糕] 稀 喵臣秀赖 么 ? ^_^ ^_^
求助 猫大战怎么玩呀 应该先按 哪里 ? ^_^
求助 [誉] 甲斐姬 和谁是 大笑脸 ? ^_^
请教 勇猛果敢 这个技能 应该传授给 风 可喵才藏 吗 ? ^_^
求实测。勇猛果敢 真的有 策士+猫足 效果吗 ? ^_^
雅虎服 萌萌新求购 勇猛果敢 4.0风喵小太郎。。^_^
求助 ねこ武将说破 。。 ^_^
才貌双全 这个技能怎么样 ^_^ 。。
求助 ねこ武将说破。。 ^_^
求信喵日服地址 萌萌新被自己蠢哭了 百度找不到答案
求信喵日服地址 萌萌新被自己蠢哭了 百度找不到答案
信喵日服联动winning post求助^_^。。
求助^_^ねこ武将说破
求助^_^猫武将说破。。
萌萌新求问信喵日服联动winning post^_^。。
萌萌新求问信喵日服联动^_^。。
系统又给新人我送了只萌萌哒 c千姬^_^图在2楼。。
请教 ReactOS 支持Google Chrome 浏览器吗 ? ^_^ 请教 ReactOS 支持Google Chrome 浏览器吗 ? ^_^
请教 这个任务怎么做^_^图在2楼。。
宝卡有爱党系列 之 宁宁 图在2楼^_^
日服超有爱的 水 浓姬^_^图在2楼 嘻 ^_^
首页
1
2
下一页