Excel自动化在Haskell中导致分段错误

52

我可以使用以下脚本启动Excel。但是在ghci(7.4.1)中,当我运行它时,会出现分段错误。

我不知道该从哪里查找了。如果我删除该行,则不会出现此错误。

workSheets <- workBook #  propertyGet_0 "Worksheets"

这里是代码。可能我忘记了什么。我在这里阅读了com.hs的源代码(链接),但它并没有给我任何线索。

import System.Win32.Com 
import System.Win32.Com.Automation
--
-- createObjectExcel 
-- coming from Automation.hs and com.hs
--

iidIDispatch_unsafe  = mkIID "{00020400-0000-0000-C000-000000000046}"

createObjExl :: IO (IDispatch ()) 
createObjExl = do
    clsidExcel <- clsidFromProgID "Excel.Application"
    pExl <- coCreateInstance clsidExcel  Nothing LocalProcess iidIDispatch_unsafe
    return pExl


fichierTest2 = "E:/Programmation/haskell/Com/qos1.xls"

main = coRun $ do 
    pExl <- createObjExl
    workBooks <- pExl #  propertyGet_0 "Workbooks"
    workBook <- workBooks #  propertyGet_1 "Open" fichierTest2
    workSheets <- workBook #  propertyGet_0 "Worksheets"

    workBooks # method_1_0 "Close" (0::Int)
    pExl # method_0_0 "Quit"

    mapM release [workSheets,workBook, workBooks, pExl]

在Gonzalez的建议下,我尝试进行调试,但没有发现任何信息。我在ghci中手动尝试了代码,似乎罪犯是release函数。

当我在ghci中输入这些内容时,我得到了段错误:

*Main> coInitialize
*Main> pExl <- createObjExl
*Main> release pExl
0

现在如果我按下“pExl”,我就有了一个引用。那么它不应该被设置为 Null 吗?

*Main> pExl
<interface pointer = 0x020844cc>

*Main> coUnInitialize
*Main> :q
leaving Ghci
Segmentation Fault/access violation ...

3
简略查看代码表明有罪的函数可能是primInvokeMethod,它执行所有原始内存操作。您可以使用ghci调试工具,缩小源代码中触发分段错误的位置以及导致失败的参数。我没有Windows机器,所以无法自行测试。 - Gabriella Gonzalez
1
你能在 GHC 中尝试一下吗?(即编译后) - Don Stewart
1
它与GHC有效地配合工作。而且不需要像“mapM release [workSheets,workBook, workBooks, pExl]”这样的发布,因为它是垃圾回收的。在mkiid中也有一个问题。我将在Reddit上发布一个完全可行的示例。 - jinkou2 jinkou2
在调用Worksheets方法之前,您是否实际测试了workBook不为null?这似乎是最明显的测试,因为如果它为null,我想您会得到您正在看到的行为。 - Gary McGill
PS. WorkbookS.Close方法不需要参数,但是你似乎传递了一些东西。我通常会使用带有参数的Workbook.Close方法。 - Gary McGill
1
主要原因是ghci是多线程的,而com包调用了OleInitialize。OleInitialize指定了单线程COM模型。我相信这是失败的主要原因。使用单线程标志编译的包应该可以正常工作。 - Yogesh Sajanikar
1个回答

1
你可能正在静态函数内调用workSheets方法。尝试将其移出来。
或者,你是否尝试明确声明“Worksheets”的数据类型? WorkSheets :: Int -> Int 或(应该是什么类型)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接