AutoHotkey Community

It is currently May 25th, 2012, 10:50 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: July 9th, 2007, 6:57 pm 
I tried to make DHTMLEDiT control using your EASY COM.
I managed to make poor one.(expecting a lot of criticism)
It's absolutely crude but at least I can edit html in WYSIWYG way.
Image

But the problem is that some method is working only in my main script(Test_DHTmlEdit.ahk) not from the DE_control.ahk.
I put comments in the script where there are problems.
And when I made GUI I used Sean's AtlAX kind Functions.
They are great functions so can you consider adding these functions?
To add those functions I had to include "Cohelper.ahk", it's not a problem for me, but the problem is your function name and cohelper's function name conflict specifically "CreateObject".
So I had to Edit the original cohelper.ahk(just removed only createObject function).

DownLoad All Packed File
http://blogfile.paran.com/BLOG_387244/200707/1184002338_DhtmlEdit_Test.zip

including easycom.dll, easycom.ahk, cohelper_ed.ahk(only CreateObject removed), DE_control.ahk, and test demo script)


DE_control.ahk


Code:
; it can be used to display and edit html in a visual way.(WYSIWYG)
; it's only my try to understand COM, not intended for final use 'cause easycom is still under development.
; Of course, they are working but I really hope that somebody has these functions wrapped.
; ill-structured and still a lot left to do.


;        Command IDs

DECMD_BOLD =                      5000
DECMD_COPY =                      5002
DECMD_CUT =                       5003
DECMD_DELETE =                    5004
DECMD_DELETECELLS =               5005
DECMD_DELETECOLS =                5006
DECMD_DELETEROWS =                5007
DECMD_FINDTEXT =                  5008
DECMD_FONT =                      5009
DECMD_GETBACKCOLOR =              5010
DECMD_GETBLOCKFMT =               5011
DECMD_GETBLOCKFMTNAMES =          5012
DECMD_GETFONTNAME =               5013
DECMD_GETFONTSIZE =               5014
DECMD_GETFORECOLOR =              5015
DECMD_HYPERLINK =                 5016
DECMD_IMAGE =                     5017
DECMD_INDENT =                    5018
DECMD_INSERTCELL =                5019
DECMD_INSERTCOL =                 5020
DECMD_INSERTROW =                 5021
DECMD_INSERTTABLE =               5022
DECMD_ITALIC =                    5023
DECMD_JUSTIFYCENTER =             5024
DECMD_JUSTIFYLEFT =               5025
DECMD_JUSTIFYRIGHT =              5026
DECMD_LOCK_ELEMENT =              5027
DECMD_MAKE_ABSOLUTE =             5028
DECMD_MERGECELLS =                5029
DECMD_ORDERLIST =                 5030
DECMD_OUTDENT =                   5031
DECMD_PASTE =                     5032
DECMD_REDO =                      5033
DECMD_REMOVEFORMAT =              5034
DECMD_SELECTALL =                 5035
DECMD_SEND_BACKWARD =             5036
DECMD_BRING_FORWARD =             5037
DECMD_SEND_BELOW_TEXT =           5038
DECMD_BRING_ABOVE_TEXT =          5039
DECMD_SEND_TO_BACK =              5040
DECMD_BRING_TO_FRONT =            5041
DECMD_SETBACKCOLOR =              5042
DECMD_SETBLOCKFMT =               5043
DECMD_SETFONTNAME =               5044
DECMD_SETFONTSIZE =               5045
DECMD_SETFORECOLOR =              5046
DECMD_SPLITCELL =                 5047
DECMD_UNDERLINE =                 5048
DECMD_UNDO =                      5049
DECMD_UNLINK =                    5050
DECMD_UNORDERLIST =               5051
DECMD_PROPERTIES =                5052


;   Enums


;OLECMDEXECOPT 

OLECMDEXECOPT_DODEFAULT =         0
OLECMDEXECOPT_PROMPTUSER =        1
OLECMDEXECOPT_DONTPROMPTUSER =    2

; DHTMLEDITCMDF

DECMDF_NOTSUPPORTED =             0
DECMDF_DISABLED =                 1
DECMDF_ENABLED =                  3
DECMDF_LATCHED =                  7
DECMDF_NINCHED =                  11

; DHTMLEDITAPPEARANCE

DEAPPEARANCE_FLAT =               0
DEAPPEARANCE_3D =                 1

; OLE_TRISTATE
OLE_TRISTATE_UNCHECKED =          0
OLE_TRISTATE_CHECKED =            1
OLE_TRISTATE_GRAY =               2


; Error Return Values
;

DE_E_INVALIDARG =                 0x5
DE_E_ACCESS_DENIED =              0x46
DE_E_PATH_NOT_FOUND =             0x80070003
DE_E_FILE_NOT_FOUND =             0x80070002
DE_E_UNEXPECTED =                 0x8000ffff
DE_E_DISK_FULL =                  0x80070027
DE_E_NOTSUPPORTED =               0x80040100
DE_E_FILTER_FRAMESET =            0x80100001
DE_E_FILTER_SERVERSCRIPT =        0x80100002
DE_E_FILTER_MULTIPLETAGS =        0x80100004
DE_E_FILTER_SCRIPTLISTING =       0x80100008
DE_E_FILTER_SCRIPTLABEL =         0x80100010
DE_E_FILTER_SCRIPTTEXTAREA =      0x80100020
DE_E_FILTER_SCRIPTSELECT =        0x80100040
DE_E_URL_SYNTAX =                 0x800401E4
DE_E_INVALID_URL =                0x800C0002
DE_E_NO_SESSION =                 0x800C0003
DE_E_CANNOT_CONNECT =             0x800C0004
DE_E_RESOURCE_NOT_FOUND =         0x800C0005
DE_E_OBJECT_NOT_FOUND =           0x800C0006
DE_E_DATA_NOT_AVAILABLE =         0x800C0007
DE_E_DOWNLOAD_FAILURE =           0x800C0008
DE_E_AUTHENTICATION_REQUIRED =    0x800C0009
DE_E_NO_VALID_MEDIA =             0x800C000A
DE_E_CONNECTION_TIMEOUT =         0x800C000B
DE_E_INVALID_REQUEST =            0x800C000C
DE_E_UNKNOWN_PROTOCOL =           0x800C000D
DE_E_SECURITY_PROBLEM =           0x800C000E
DE_E_CANNOT_LOAD_DATA =           0x800C000F
DE_E_CANNOT_INSTANTIATE_OBJECT =  0x800C0010
DE_E_REDIRECT_FAILED =            0x800C0014
DE_E_REDIRECT_TO_DIR =            0x800C0015
DE_E_CANNOT_LOCK_REQUEST =        0x800C0016

LoadEasyCOM()



; ------------------------- General functions ---------------------------------------------------------------

DE_Add(hWnd, x, y, w, h)
{
   AtlAxWinInit()
   Return AtlAxGetControl( AtlAxCreateContainer(hWnd, x, y, w, h, "DhtmlEdit.DhtmlEdit") )
}

DE_Move(pwb, x, y, w, h)
{
   WinMove, % "ahk_id " . GetHostWindow(pwb), , x, y, w, h
}

DE_BrowseMode(pDHtmlEdit)     ; toggle between Edit mode and View mode.
{
   iret := InvokeS(pDhtmlEdit, "Browsemode")
   if iret = 0
      iret := InvokeS(pDhtmlEdit, "Browsemode=", 1)
   Else
      iret := InvokeS(pDhtmlEdit, "Browsemode=", 0)
}


DE_LoadUrl(pDhtmlEdit, url)                 ;Load url(e.g. "http://www.autohotkey.com") and ready to edit in a WYSIWIG way
{
   iRet := InvokeS(pDhtmlEdit, "LoadUrl()", url)   
}

DE_NewDocument(pDhtmlEdit)                 ;clear current document and open blank html document
{
   iRet := InvokeS(pDhtmlEdit, "NewDocument()")   
}


DE_LoadDocument(pDhtmlEdit, FileDir, prompt = "Load Html File")   ;open file dialog and last parameter is prompt string.
{
   iRet := InvokeS(pDhtmlEdit, "LoadDocument()", FileDir)   
}

DE_SaveDocument(pDhtmlEdit, Filedir)        ;save contents in html.
{
   iRet := InvokeS(pDhtmlEdit, "SaveDocument()", FileDir)
}


DE_GetDocumentHtml(pDHtmlEdit)      ;get and return DOCUMENT'S htmlcode
{
   iret := InvokeS(pDhtmlEdit, "DocumentHtml")
   return iret
}

DE_SetDocumentHtml(pDHtmlEdit, sHtml)   ;set document's htmlcode
{
   iret := InvokeS(pDhtmlEdit, "DocumentHtml=", sHtml)
}

DE_Refresh(pDhtmlEdit)   ;open file dialog and last parameter is prompt string.
{
   iRet := InvokeS(pDhtmlEdit, "Refresh()")   
}

; --- WYSIWYG Edit functions ----------------------------------------------------------------------------------------------


; Set property --> use ExecCommand(), Command ID
; Get Propery --> use QueryStatus(), command ID

DE_SetBOLD(pDhtmlEdit)         ; toggle selections bold/normal
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_BOLD)
}

DE_SetUnderline(pDHtmlEdit)  ; toggle selections underline
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_UNDERLINE)
}

DE_SetItalic(pDHtmlEdit)  ; toggle selections italic
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_ITALIC)
}

DE_SetForeColor(pDHtmlEdit, sColor)    ; set font color string, e.g. "#55A0FF", "55A0FF", "Blue", "Red"
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_SETFORECOLOR, OLECMDEXECOPT_DODEFAULT, sColor)

}

DE_SetHyperLink(pDHtmlEdit)    ; insert hyperlink property in selection
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_HYPERLINK, OLECMDEXECOPT_DODEFAULT, "")

}

DE_SetImage(pDHtmlEdit)    ; insert image in selection
{
   iret := InvokeS(pDhtmlEdit, "ExecCommand()", DECMD_IMAGE, OLECMDEXECOPT_DODEFAULT, "")
}




; --------- USING DOM ------------------------------------------------------------------------------------------

; it's just from the Dhtml SDK, I don't know at all about DOM.
; maybe we need to load MSHTML.DLL to acess DOM, I don't know.

DE_DOM(pDHtmlEdit)
{
   iret := InvokeS(pDhtmlEdit, "DOM")
   return iret
}

;How can I invoke this? I can invoke DOM like above, but not selection below.
;        sel = DHTMLEdit.DOM.selection (from SDK)
; As far as I know, if we wanna play with html source, we have to acess DOM.



GetHostWindow(pwb)
{
   GUID4String(IID_IOleWindow, "{00000114-0000-0000-C000-000000000046}")
   DllCall(VTable(pwb, 0), "Uint", pwb, "str", IID_IOleWindow, "UintP", pow)
   DllCall(VTable(pow, 3), "Uint", pow, "UintP", hWnd)
   DllCall(VTable(pow, 2), "Uint", pow)
   Return DllCall("GetParent", "Uint", hWnd)
}


AtlAxWinInit()
{
   If !DllCall("GetModuleHandle", "str", "atl")
       DllCall("LoadLibrary"    , "str", "atl")
   Return DllCall("atl\AtlAxWinInit")
}

AtlAxWinTerm()
{
   If hModule := DllCall("GetModuleHandle", "str", "atl")
      DllCall("FreeLibrary", "Uint", hModule)
}

AtlAxGetControl(hWnd)
{
   DllCall("atl\AtlAxGetControl", "Uint", hWnd, "UintP", punk)
   pdsp := QueryInterface(punk, IID_IDispatch := "{00020400-0000-0000-C000-000000000046}")
   Release(punk)
   Return  pdsp
}

AtlAxAttachControl(pdsp, hWnd)
{
   punk := QueryInterface(pdsp, IID_IUnknown := "{00000000-0000-0000-C000-000000000046}")
   DllCall("atl\AtlAxAttachControl", "Uint", punk, "Uint", hWnd, "Uint", 0)
   Release(punk)
}

AtlAxCreateContainer(hWnd, x, y, w, h, sName = "")
{
   pName := sName ? &sName : 0
   AtlAxWin := "AtlAxWin"
   Return DllCall("CreateWindowEx", "Uint", 0x200, "Uint", &AtlAxWin, "Uint", pName, "Uint",0x10000000|0x40000000|0x04000000, "int", x, "int", y, "int", w, "int", h, "Uint", hWnd, "Uint", 0, "Uint", 0, "Uint", 0)
}



Test_demo(same with the above screenshot)



Code:
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

#Include easycom.ahk
#include cohelper_ed.ahk   
; poor way of avoiding the conflicts of the same function name, but I need to use AltAX kind functions.
; it's Sean's cohleper.ahk except I removed only CreateObject functions
; until .. implements AltxWin related functions in his easycom.dll
#include DE_Control.ahk

LoadEasyCOM()
CoInitialize()


Gui, +Resize +LastFound
Gui, Add, Button, x0 y0 gSetBold, Bold
Gui, Add, Button, xp+40 gSetItalic,italic
Gui, Add, Button, xp+50 gSetUnderLine, underline
gui, Add, Button, xp+75 gSetBlue, Blue
Gui, Add, Button, xp+40 gSetImageLink, Image
Gui, Add, Button, xp+50 gSetHyperLink, Link
Gui, Add, Button, xp+50 gLoadUrl, LoadURL
Gui, Add, Button, xp+70 gGetDocument, GetHtml
gui, add, button, xp+70 gSetDocument, SetHtml
Gui, Add, button, xp+70 gSaveDocument, SaveHtml
Gui, Add, button, xp+80 gBrowseMode, BrowseMode Toggle
Gui, add, button, xp+140 gNewDocument, New

Gui, Show, w800 h600 Center, DhtmlEdit_Test
hWnd := WinExist()

;DE_ADD(hWnd, 0, 25, 800, 575)
;DEdit := GetActiveObject("DhtmlEdit.DhtmlEdit")

AtlAxWinInit()

DEdit := CreateObject("DhtmlEdit.DhtmlEdit")
;AtlAxAttachControl(DEdit, hWnd)
hContainerCtrl := AtlAxCreateContainer(hWnd, 0, 25, 800, 575)
AtlAxAttachControl(DEdit, hContainerCtrl)
gosub, SetDocument

Return


SetBold:
iret := InvokeS(DEdit, "ExecCommand()", DECMD_BOLD)
;DE_SetBold(DEdit)  <---- I don't know why it's not working. It's the same function.

Return

SetItalic:

iret := InvokeS(DEdit, "ExecCommand()", DECMD_ITALIC)
;DE_SetItalic(DEdit) <---- I don't know why it's not working. It's the same function.

Return

SetBlue:


iret := InvokeS(DEdit, "ExecCommand()", DECMD_SETFORECOLOR, OLECMDEXECOPT_DODEFAULT, "Blue")

;DE_SetForeColor(DEdit, "0000FF") <-------- I don't know why it's not working
;DE_SetForeColor(pDHtmlEdit, "Blue") ; possible way
;DE_SetForeColor(pDHtmlEdit, "#0000FF") ; also possible


Return


SetUnderline:

iret := InvokeS(DEdit, "ExecCommand()", DECMD_UNDERLINE)
;DE_SetUnderline(DEdit) <-------I don't know why it's not working. It's the same function.

Return

SetImageLink:

iret := InvokeS(DEdit, "ExecCommand()", DECMD_IMAGE, OLECMDEXECOPT_DODEFAULT, "")
;DE_SetImage(DEdit) <-------I don't know why it's not working. It's the same function.

Return

SetHyperLink:

iret := InvokeS(DEdit, "ExecCommand()", DECMD_HYPERLINK, OLECMDEXECOPT_DODEFAULT, "")
;DE_SetHyperLink(DEdit) <-------I don't know why it's not working. It's the same function.

Return

LoadUrl:
url := "http://www.autohotkey.com"
DE_LoadUrl(DEdit, url)
Return

NewDocument:
DE_NewDocument(DEdit)
Return

SaveDocument:

Filedir = %A_ScriptDir%\DhtmlEdit_%A_Now%.htm
DE_SaveDocument(DEdit, FileDir)

Return

GetDocument:

msgbox, % DE_GetDocumentHtml(DEdit)

Return

SetDocument:

htmlcode =
(
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html; charset=ISO-8859-1"
 http-equiv="content-type">
  <title></title>
</head>
<body
 style="COLOR: rgb(0,0,0); BACKGROUND-COLOR: rgb(255,204,51)" alink   
 ="#ee0000" link="#0000ee" vlink="#551a8b">
<P>
<big style="FONT-FAMILY: Verdana"><big><EM><STRONG>Forgive</STRONG></EM> my <span
 style="FONT-WEIGHT: bold; COLOR: rgb(51,51,255)"  >poor</span> coding style! Yes?
</big></big></P>
<P><BIG style="FONT-FAMILY: Verdana"><BIG>This File is Edited with
<STRONG>DhtmlEdit_Demo</STRONG>
  .<br>
<br></P></BIG></BIG>
<ul style="FONT-FAMILY: Verdana">
  <li><STRONG><U>First List</U></STRONG>
  <li><FONT color=blue>second List</FONT>
  <li><A href="http://www.autohotkey.com">what
  now?(</A>click then go to AutohotKey)</li>
</ul>
<br style="FONT-FAMILY: Verdana">
<table
 style="WIDTH: 440px; FONT-FAMILY: Verdana; HEIGHT: 52px; TEXT-ALIGN: left"
 border="1" cellpadding="2" cellspacing="2">
  <tbody>
    <tr>
      <td>This is a table<br>
and &nbsp;the right image is directly from AutoHotKey Forum.</td>
      <td><A href="http://www.autohotkey.com"><img style="WIDTH: 228px; HEIGHT: 133px"
 alt="image cannot be loaed for some reason"
 src="http://www.autohotkey.com/docs/images/AutoHotkey_logo.gif"></A></td>
    </tr>
  </tbody>
</table>
</body>
</html>
)


DE_SetDocumentHtml(DEdit, htmlcode)
htmlcode =


Return


BrowseMode:

DE_BrowseMode(DEdit)

Return


GuiSize:

DE_Move(DEdit, 0, 25, A_GuiWidth, A_GuiHeight)


Return



GuiClose:
Gui, %A_Gui%:Destroy
ReleaseObject(DEdit)
UnloadEasyCOM()
AtlAxWinTerm()
CoUninitialize()
ExitApp


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 9th, 2007, 7:06 pm 
Once I used your easycom, now I could understand a little bit about Sean's script, so I directly used his codes in major functions(e.g. IE_move() --> DE_Move(), thanks, Sean)
But sitll it's painful. :lol:
And erictheturtle, I hope I'm not interruping your hard work!
Thanks.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 9th, 2007, 8:47 pm 
Another thought, If you make atlax functions in your easycom.dll, you can make CreateObjectGUI Wrapper function in easycom.ahk.

for example: (it's just an idea, I'm sure you will come up with better ways

Code:
CreateObjectGUI(ProgID, parentwindowhandle,  x, y, w, h)
{   
   pObj := CreateObject(ProgID)
   hContainerCtrl := AtlAxCreateContainer(parentwindowhandle, x, y, w, h)
   AtlAxAttachControl(pObj, hContainerCtrl)
   return pObj ; I don't know how to return two return values -_-;
   return hContainerCtrl   
}


if not, I hope you implement those other functions(like gethostwindow, etc. in Easycom.ahk we need to control COM GUI Control.)


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 9th, 2007, 9:29 pm 
Offline

Joined: June 27th, 2007, 9:07 pm
Posts: 101
Location: California
ABCYourWay wrote:
make atlax functions in your easycom.dll

I hadn't ever thought about COM controls before. I don't know anything about them, so I don't know how difficult it would be. I guess I have some reading to do...

ABCYourWay wrote:
But the problem is that some method is working only in my main script(Test_DHTmlEdit.ahk) not from the DE_control.ahk.

Try adding "global", or "local <local variables>" in the first line of those wrapper functions and giving it another try :)

ABCYourWay wrote:
I hope I'm not interruping your hard work!

Certainly not. It is good to see easycom being tested in an actual program. Thank you for taking the time to do so and for sharing the results!

ABCYourWay wrote:
but the problem is your function name and cohelper's function name conflict specifically "CreateObject".

Hmm, I wonder how much Sean's scripts and Easycom will be used together. We may need to find a naming compromise.

Sean wrote:
it may better be named to Invoke, and the original Invoke to other.

You have a point there. My first thought is to rename Invoke() to InvokeT() -- "invoke with Types". Or maybe InvokeEx?

Sean wrote:
BTW, I think the invokekind flags can be combined/grouped ... there could be some rare cases where Method and PropertyGet have the same name.

I finally broke down and made a simple COM object using Visual Basic 6 to test these crazy situations. When I tried creating a Method and a Property with the same name, it wouldn't compile and gave me an error. So at least Visual Basic created objects wouldn't be a problem. I wonder if it's possible to do in C++ (but it seems too much work to try).

In any case, I am a little concerned about combining the INVOKEKIND flags, since I've never read anywhere that you can do it.

tfcahm wrote:
Why not combine CreateObject and CreateObjectCLSID ... GetObject/GetObjectCLSID

Seems reasonable. I'll let the wrapper take care of distinguishing ProgID and CLSID and calling the proper dll function for now. If no problems are found, then this task can eventually be moved into the DLL instead.

tfcahm wrote:
BookCAT ... FastTrack Scheduler, TopStyle, and SnagIt have ByRef BSTRs and Nero

Thanks tfcahm. I actually have Nero so I may be able to use that API for testing.

_________________
-m35


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 9th, 2007, 9:37 pm 
Offline

Joined: March 16th, 2005, 10:33 pm
Posts: 968
Location: Frisia
Great stuff!

I still don't understand the half of it, but this looks very promising. 8)

_________________
Image mirror 1mirror 2mirror 3ahk4.me • PM or Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 2:19 am 
Offline

Joined: June 27th, 2007, 9:07 pm
Posts: 101
Location: California
Alright, I finally figured out how VT_BYREF parameters work.

When you pass an argument as VT_BYREF, it must be EXACTLY the same data type as the method/property expects. There's no automatic coercion for VT_BYREF arguments.

The current EasyCOM design can't accommodate for proper VT_BYREF handling (due to its simplified data types), so I've got some core changes to make. I won't bore you with my incoherent rambling of the details. :)

In related news, I also feel it would be best to do away with using the COM_* data types in wrapper function calls, and instead use the familiar DllCall() type strings (e.g. "Int", "Short", "Float", etc...).

Finally, I realized that there needs to be one more Invoke() function to handle ByRef arguments:
Code:
InvokeByref(ObjectHandle, MemberName
      , type1=0, ByRef arg1=0
      , type2=0, ByRef arg2=0
      , type3=0, ByRef arg3=0
      , type4=0, ByRef arg4=0
      , type5=0, ByRef arg5=0
      , type6=0, ByRef arg6=0
      , type7=0, ByRef arg7=0
      , type8=0, ByRef arg8=0
      , type9=0, ByRef arg9=0)
{
...
}


This function requires arguments to be passed ByRef (so no literal values allowed). After the function call, any variables passed as a pointer (e.g. "Int*") will be updated.

Here is a fictional example:
Code:
objFictional := CreateObject("SomeLib.FictionalObject")
sArg1 := "Passed by value string" ; must pass as a variable due to ByRef
iArg2 := 15 ; Also must pass as a variable due to ByRef
iArg3 := 10
InvokeByref(objFictional, "FictionalMethod()"
         , "Str", sArg1
         , "Int", iArg2
         , "Int*", iArg3)
Msgbox % iArg3 ; iArg3 will have the new value
; sArg1 and iArg2 are not changed because they were not passed as a pointer


I'm sure all these changes will take me many days to complete.

Why am I mentioning all this? Well I thought people would like to know how the development is going. I apologize if all this doesn't make sense. I'm sure things will make more sense once it has all been implemented, and lots of new examples are provided.

_________________
-m35


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 2:57 am 
Offline
User avatar

Joined: December 29th, 2004, 1:28 pm
Posts: 2541
Thanks for the update and for the initial beta release to play with :) .


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 6:02 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
erictheturtle wrote:
You have a point there. My first thought is to rename Invoke() to InvokeT() -- "invoke with Types". Or maybe InvokeEx?

I added an example code in COM Helper thread as Extra Invoke() where I used the name Invoke_(), but I'm expecting lots of complaining with it. That's OK as I'll keep them for private use only.
I like the name InvokeEx().

Quote:
I finally broke down and made a simple COM object using Visual Basic 6 to test these crazy situations. When I tried creating a Method and a Property with the same name, it wouldn't compile and gave me an error. So at least Visual Basic created objects wouldn't be a problem. I wonder if it's possible to do in C++ (but it seems too much work to try).

That sounds like a good news. So, it would be really rare, if not null.

Quote:
In any case, I am a little concerned about combining the INVOKEKIND flags, since I've never read anywhere that you can do it.

Unfortunately, I'm not aware of any documentation either. It's all based on my own tests. Although now I'm pretty confident about it, I admit there exists a risk of breaking something.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 7:17 am 
erictheturtle, you're right. The contants used in funtions should be global.(e.g CMDID)
Now it's working now, thanks.

For now, Last question!

When I wanna have more delicate handlling of the html source,
I have to acess DOM

Such as

- Getting the contents of the selection
- Identifying the selection the mouse is pointing to
- Programmatically moving the insertion point

Below is the javascript code. How do I Invoke this with easycom?
Code:
function ShowSelection(){
   sel = DHTMLEdit.DOM.selection;
   if ( "Text" == sel.type ){
      range = sel.createRange();
      alert( range.htmlText );
   }
   else
      alert( "No text selected" );
}



I can invoke DOM, but how "DOM.selection"? And "Sel.type"?
What I mean is I can only invoke [b]one-level deep property or method,[/b]
But how can I invoke a series of properties or methods like these?

Code:
 DHtmlObject.DOM.selection.Type
DHTMLObject.DOM.selection.createRange
DHTMLObject.DOM.body.createTextRange()


Anybody?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 10:56 am 
I translated the javascript above to AHK
But do I have to invoke every method and property.

Code:
GetSelection(pDhtmlEdit)
{
   pDOM := InvokeS(pDhtmlEdit, "DOM")
   sel := InvokeS(pDOM, "selection")
   seltype := InvokeS(sel, "type")
   msgbox, %seltype%
   pRange := invokeS(sel, "CreateRange()")
   selectedtext := invokeS(pRange, "htmltext")
   msgbox, %selectedtext%
}


It's working but how about inventing a special operator like DOT
I don't know if this question should go to Chris.
Anyway, it's just for convenience.
Although it's not easy to code, the fact that I can do whatever with COM really please me.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 12:56 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
ABCYourWay wrote:
how about inventing a special operator like DOT
How 'bout a parsing loop? Untested example:
Code:
; usage:
seltype := InvokeObj(pDhtmlEdit, "DOM.selection.type")
; translates to
obj := pDhtmlEdit
obj := InvokeS(obj, "DOM")          ; pDom := InvokeS(pDhtmlEdit, "DOM")
obj := InvokeS(obj, "selection")    ; sel := InvokeS(pDom, "selection")
obj := InvokeS(obj, "type")         ; seltype := InvokeS(sel, "type")
seltype := obj

InvokeObj(ObjectHandle, MemberString) {
    Loop, Parse, MemberString, .
        ObjectHandle := InvokeS(ObjectHandle, A_LoopField)
    return ObjectHandle
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 1:59 pm 
Offline

Joined: June 27th, 2007, 9:07 pm
Posts: 101
Location: California
Sean wrote:
Quote:
In any case, I am a little concerned about combining the INVOKEKIND flags, since I've never read anywhere that you can do it.

Unfortunately, I'm not aware of any documentation either. It's all based on my own tests. Although now I'm pretty confident about it, I admit there exists a risk of breaking something.

There is the alternative to first Invoke the member name as a Method, and if it fails (DISP_E_MEMBERNOTFOUND), then try Invoking it again as a Property. Doing this should have the same effect. However I'm still a little worried there is a COM object out there that will somehow have a Method and a PropertyGet with the same name.

Along the same lines, when I made that Visual Basic class, I was able to create a "Property Let" and a "Property Set" with the same name, however it had to have the same parameter or it wouldn't compile. I'm not quite sure what that means...

lexikos wrote:
How 'bout a parsing loop?

Thanks for the example lexikos. I have known that having a function like that would probably be useful. It seems EasyCOM is easy(er), but nothing is quite as easy as Visual Basic or JavaScript :(

Almost makes me wonder if it would be better to implement [edit] Windows Scripting Host in AHK so you can create strings of Visual Basic or Javascript and execute them.
Code:
sFileName := "test.txt"
sCode = Set objFSO = CreateObject("Scripting.FileSystemObject")`n
sCode .= objFSO.FileExists(%sFileName%)
RunVBCode(sCode)

But I'm not sure if that would even work, but I think it's worth looking into. It is clear that the AHK syntax is very not conducive to COM type programming. So maybe using another language inside AHK would be a better solution.

To a lesser extreme, creating our own little quasi-scripting language specifically for COM could help make things easier...or add confusion? :)
It's already begun with "Method()" and "PropertySet=". Now we're adding "." dot notation for delimiters. It makes me think about a function like this
Code:
iCol := "A"
objExcelApp := CreateObject("Excel.Application")
PowerInvoke(objExcelApp,".Workbooks.Add().ActiveSheet.Cells(int 1, str ",iCol,").Value= int 100")

It becomes a little language all of its own..

Anyway, just throwing these ideas out there. I'll be considering these options because I think they may be a better way to go to actually make EasyCOM easy.

_________________
-m35


Last edited by erictheturtle on July 10th, 2007, 5:21 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 2:07 pm 
Yeah, but as lexikos presented a nice example,
it could be solved in Wrapper-function level(not in esaycom.dll, but in easycom.ahk)
That way, you can rest a little bit more. :D


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 10th, 2007, 9:50 pm 
Offline

Joined: June 27th, 2007, 9:07 pm
Posts: 101
Location: California
Before delving in and tearing easycom apart again, I thought I should update the files with the latest.
easycom.dll - v0.0.1.62
easycom.ahk - v0.002
testcom.ahk - for easycom.ahk v0.002

These files are still in BETA stage (actually, more like ALPHA stage, but whatever).

I'm pretty certain easycom.dll has some memory leaks, and I've gotten it to consistently crash under some circumstances.

Also a note about the new function CreateObjectFromDll().
It uses the amazing code provided by Elias on CodeProject and made testing my custom VB dll class so very easy.

In regards to my previous post
I wrote:
Almost makes me wonder if it would be better to implement Windows Scripting Host in AHK so you can create strings of Visual Basic or Javascript and execute them.

For testing, I put together a script that does just that. It behaves like the 'Immediate' pane in the Visual Basic 6 and Visual Basic for Applications IDE. In case you're not familiar with it, it works something like this:
Code:
x = 1
?x   ' prints 1
Set fso = CreateObject("Scripting.FileSystemObject")
?fso.FolderExists("C:\Windows")   ' prints 1 (true)

Note: Needs the new versions of the files posted above.
Code:
#NoEnv
#NoTrayIcon
#Include easycom.ahk

; Setup GUI
Gui, Font,, Courier New
Gui, Add, Edit, r1 -WantReturn -Wrap w500 vVBString
Gui, Add, Button, Default, Eval
Gui, Add, Edit, -Wrap r5 w500 ReadOnly vEvalResult
Gui, Show, , Visual Basic Read-Eval-Print-Loop (REPL)

LoadEasyCOM()

; Setup Microsoft Script Control
objMSC := CreateObject("MSScriptControl.ScriptControl")
Invoke(objMSC, "Language=", "VBScript")
Invoke(objMSC, "AllowUI=", True)
Invoke(objMSC, "UseSafeSubset=", False)

Return ; end of script start

ButtonEval:
   Gui, Submit, NoHide
   ; Check if the statement should be evaluated
   ; with Eval() or ExecuteStatement()
   StringLeft sChar1, VBString, 1
   If (sChar1 = "?") ; Use Eval() if first character is a question mark
   {
      StringTrimLeft, VBString, VBString, 1 ; remove '?'
      sEval := Method1StringNoExit(objMSC, "Eval", VBString)
      GuiControl, , EvalResult, %sEval%`n%EvalResult%
   }
   else ; Otherwise use ExecuteStatement()
   {
      Method1StringNoExit(objMSC, "ExecuteStatement", VBString)
   }
   
   ; Reset the input box
   GuiControl, , VBString,
   GuiControl, Focus, VBString
   
   Return

GuiClose:
   ;ReleaseObject(objMSC)
   ;UnloadEasyCOM()
   ExitApp
   
   
;; This function is like Invoke() but only calls methods,
;; accepts only one string argument, and doesn't exit the script on error.
Method1StringNoExit(iObjPtr, sMethod, s)
{
   global EASYCOM_DLL, COM_STR, COM_METHOD
   
   iErr := DllCall(EASYCOM_DLL . "\BeginMemberCall", "int", -1)
   If (iErr <> 1) ; Error during call!
   {
      Msgbox % "Error beginning member call`n"
            . DllCall(EASYCOM_DLL . "\GetErrorDescription", "str")
      DllCall(EASYCOM_DLL . "\EndMemberCall")
      Return
   }
   iErr := DllCall(EASYCOM_DLL . "\AddArgument"
               , "int", COM_STR
               , str, s)
   If (iErr <> 1) ; Error during call!
   {
      Msgbox % "Error adding argument`n"
            . DllCall(EASYCOM_DLL . "\GetErrorDescription", "str")
      DllCall(EASYCOM_DLL . "\EndMemberCall")
      Return
   }
   iType := DllCall(EASYCOM_DLL . "\Invoke"
               , "int", iObjPtr
               , "str", sMethod
               , "int", COM_METHOD)
   If (iType < 1) ; Error during call!
   {
      ; If an exception
      If (DllCall(EASYCOM_DLL . "\GetComErrorCode", "uint") = 0x80020009)
         Msgbox % __GetExceptionInfo()
      Else
         Msgbox % "Error in calling " . sMethod . "`n"
            . DllCall(EASYCOM_DLL . "\GetErrorDescription", "str")
      DllCall(EASYCOM_DLL . "\EndMemberCall")
      Return
   }
   If (iType = 1)
      Return ; Nothing was returned
   
   iPtr := DllCall(EASYCOM_DLL . "\GetReturn")
   If (iPtr = 0)
      Return ; NULL pointer was returned

   sAHKType := __COMRetToAHKType(iType)
   xVal := DllCall(EASYCOM_DLL . "\GetReturn", %sAHKType%)
   
   DllCall(EASYCOM_DLL . "\EndMemberCall")
   Return xVal
}

Seems like it could be a very real (and probably better) alternative to EasyCOM...

_________________
-m35


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 11th, 2007, 1:45 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
erictheturtle wrote:
I finally broke down and made a simple COM object using Visual Basic 6 to test these crazy situations. When I tried creating a Method and a Property with the same name, it wouldn't compile and gave me an error. So at least Visual Basic created objects wouldn't be a problem. I wonder if it's possible to do in C++ (but it seems too much work to try).

On second thought, I became suspicious that these functions are complied with Names at all, even with the ordinal numbers.
Relative addresses in the module would be enough with them.
I reckon the names are stored only in TypeLib as convenience means to bridge between the client and the server.
So, the process would be:
Name -> dispID -> InvKind -> (unique) Address


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 25 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group