将静态 windows 库转换为 dll
Posted
技术标签:
【中文标题】将静态 windows 库转换为 dll【英文标题】:Convert static windows library to dll 【发布时间】:2009-05-10 11:50:23 【问题描述】:我有一个包含一堆静态*lib
文件的库,我希望从JNA
(一个允许从JAVA 代码动态调用`dll's 的Java 库)访问它们,所以有没有办法神奇地将静态库更改为dll?
代码是使用 Visual Studio 编译的(希望是相关的),我也有相应的头文件。
我无权访问源代码,我也想只使用免费(如啤酒)工具来完成它。
【问题讨论】:
你至少有库头文件吗? 是的,我确实有头文件。 只有静态库文件有点不寻常。您确定没有可用的 DLL 吗?图书馆是从哪里来的? 嗯,我没有找到。这是一些光谱设备,图书馆很旧(从2000年开始)。 【参考方案1】:我不知道有任何工具会自动执行此操作,但该过程是创建一个 DLL 项目并将您的库添加到项目中。对于头文件中的每个函数:
int SomeLibFunc( int x, int y );
您需要在 DLL 中创建和导出您自己的函数;
int MyFunc( int x, int y )
return SomLibFunc( x, y );
这个过程非常机械化,您可以使用 perl 之类的东西敲出一个脚本来创建 DLL 源文件。
【讨论】:
好吧,我做了一堂课。我将把它小化并在这个问题的某个地方发布。 您可以简单地将 .def 文件添加到项目中,而不是将函数与 MyFunc 一起使用。这将为您显式导出符号。不过要注意名称篡改。见msdn.microsoft.com/en-us/library/d91k01sh(VS.80).aspx【参考方案2】:假设您无权访问源代码,您可以简单地创建一个包装 DLL,将您需要的函数导出并委托给静态库。
【讨论】:
有什么办法可以自动完成(这个库很大)还是我必须手动完成? 我不知道有这种方法,但是通过一些脚本,您可能可以轻松生成所有内容。 如果您使用的是.lib,那么您可能有一个头文件。一点点正则表达式处理,您应该能够提取函数定义,然后使用它们来构造包装函数。听起来像是一个下午的好小项目。还不如同时自动生成.def文件...【参考方案3】:我按照 anon 的建议做了,我做了一个自动转换器(有人建议在声明之前放置 _ddlspec(export) 并使用此标头编译 dll 就可以了——好吧它没有——也许我做错了什么——我'm Plain Old Java Programmer ;)):
它基本上是解析头文件并转:
SADENTRY SadLoadedMidFiles( HMEM, USHORT usMaxMidFiles, VOID * );
到:
__declspec(dllexport) SADENTRY DLL_WRAPPER_SadLoadedMidFiles(HMEM param0,
USHORT usMaxMidFiles, VOID* param2)
return SadLoadedMidFiles(param0, usMaxMidFiles, param2);
这是代码(很可能是它的 Regexp 滥用,但它有效),gui 部分取决于 MigLayout:
package cx.ath.jbzdak.diesIrae.util.wrappergen;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import static java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Displays a window. In this window you have to specify two things:
* <p/>
* 1. Name of header file that you want to process.
* <p/>
* 2. Name of output files extension will be added automatically. We will override any existing files.
*
* <p/>
* Dependencies: MigLayout
* <p/>
* Actual wrapper generation is done inside WrapperGen class.
* <p/>
* KNOWN ISSUES:
* <p/>
* 1. Ignores preprocessor so may extract finction names that are inside <code>#if false</code>.
* <p/>
* 2. Ignores comments
* <p/>
* 3. May fail to parse werid parameter syntax. . .
*
* Created by IntelliJ IDEA.
* User: Jacek Bzdak
*/
public class WrapperGenerator
public static final Charset charset = Charset.forName("UTF-8");
WrapperGen generator = new WrapperGen();
// GUI CODE:
File origHeader, targetHeader, targetCpp;
JTextField newHeaderFileName;
JFrame wrapperGeneratorFrame;
wrapperGeneratorFrame = new JFrame();
wrapperGeneratorFrame.setTitle("Zamknij mnie!"); //Wrapper generator
wrapperGeneratorFrame.setLayout( new MigLayout("wrap 2, fillx", "[fill,min!]"));
wrapperGeneratorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener buttonListener = new ActionListener()
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter()
@Override
public boolean accept(File f)
return f.isDirectory() || f.getName().matches(".*\\.h(?:pp)?");
@Override
public String getDescription()
return "Header files";
);
fileChooser.setCurrentDirectory(new File("C:\\Documents and Settings\\jb\\My Documents\\Visual Studio 2008\\Projects\\dll\\dll"));
public void actionPerformed(ActionEvent e)
if(JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(wrapperGeneratorFrame))
origHeader = fileChooser.getSelectedFile();
;
wrapperGeneratorFrame.add(new JLabel("Original header file"));
JButton jButton = new JButton("Select header file");
jButton.addActionListener(buttonListener);
wrapperGeneratorFrame.add(jButton);
wrapperGeneratorFrame.add(new JLabel("Result files prefix"));
newHeaderFileName = new JTextField("dll_wrapper");
wrapperGeneratorFrame.add(newHeaderFileName);
ActionListener doListener = new ActionListener()
public void actionPerformed(ActionEvent e)
targetHeader = new File(origHeader.getParentFile(), newHeaderFileName.getText() + ".h");
targetCpp = new File(origHeader.getParentFile(), newHeaderFileName.getText() + ".cpp");
try
targetHeader.createNewFile();
targetCpp.createNewFile();
generator.reader = new InputStreamReader(new FileInputStream(origHeader),charset);
generator.cppWriter = new OutputStreamWriter(new FileOutputStream(targetCpp), charset);
generator.heaerWriter = new OutputStreamWriter(new FileOutputStream(targetHeader), charset);
generator.parseReader();
catch (IOException e1)
e1.printStackTrace();
JOptionPane.showMessageDialog(wrapperGeneratorFrame, "ERROR:" + e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
return;
;
JButton go = new JButton("go");
go.addActionListener(doListener);
wrapperGeneratorFrame.add(go, "skip 1");
public static void main(String []args)
SwingUtilities.invokeLater(new Runnable()
public void run()
WrapperGenerator wgen = new WrapperGenerator();
JFrame f = wgen.wrapperGeneratorFrame;
wgen.wrapperGeneratorFrame.pack();
Point p = getLocalGraphicsEnvironment().getCenterPoint();
wgen.wrapperGeneratorFrame.setLocation(p.x-f.getWidth()/2, p.y-f.getHeight()/2);
wgen.wrapperGeneratorFrame.setVisible(true);
);
/**
* Does the code parsing and generation
*/
class WrapperGen
/**
* Method is basically syntax like this: <code>(anything apart from some special chars like #;) functionName(anything)</code>;
* Method declarations may span many lines.
*/
private static final Pattern METHOD_PATTERN =
//1 //2 //params
Pattern.compile("([^#;]*\\s+\\w[\\w0-9_]+)\\(([^\\)]*)\\);", Pattern.MULTILINE);
//1 - specifiers - including stuff like __dllspec(export)...
//2 - function name
//3 param list
/**
* Generated functions will have name prefixet with #RESULT_PREFIX
*/
private static final String RESULT_PREFIX = "DLL_WRAPPER_";
/**
* Specifiers of result will be prefixed with #RESULT_SPECIFIER
*/
private static final String RESULT_SPECIFIER = "__declspec(dllexport) ";
Reader reader;
Writer heaerWriter;
Writer cppWriter;
public void parseReader() throws IOException
StringWriter writer = new StringWriter();
int read;
while((read = reader.read())!=-1)
writer.write(read);
reader.close();
heaerWriter.append("#pragma once\n\n\n");
heaerWriter.append("#include \"stdafx.h\"\n\n\n"); //Standard Visual C++ import file.
cppWriter.append("#include \"stdafx.h\"\n\n\n");
Matcher m = METHOD_PATTERN.matcher(writer.getBuffer());
while(m.find())
System.out.println(m.group());
handleMatch(m);
cppWriter.close();
heaerWriter.close();
public void handleMatch(Matcher m) throws IOException
Method meth = new Method(m);
outputHeader(meth);
outputCPP(meth);
private void outputDeclaration(Method m, Writer writer) throws IOException
//writer.append(RESULT_SPECIFIER);
writer.append(m.specifiers);
writer.append(" ");
writer.append(RESULT_PREFIX);
writer.append(m.name);
writer.append("(");
for (int ii = 0; ii < m.params.size(); ii++)
Parameter p = m.params.get(ii);
writer.append(p.specifiers);
writer.append(" ");
writer.append(p.name);
if(ii!=m.params.size()-1)
writer.append(", ");
writer.append(")");
public void outputHeader(Method m) throws IOException
outputDeclaration(m, heaerWriter);
heaerWriter.append(";\n\n");
public void outputCPP(Method m) throws IOException
cppWriter.append(RESULT_SPECIFIER);
outputDeclaration(m, cppWriter);
cppWriter.append("\n\t");
if (!m.specifiers.contains("void") || m.specifiers.matches(".*void\\s*\\*.*"))
cppWriter.append("return ");
cppWriter.append(m.name);
cppWriter.append("(");
for (int ii = 0; ii < m.params.size(); ii++)
Parameter p = m.params.get(ii);
cppWriter.append(p.name);
if(ii!=m.params.size()-1)
cppWriter.append(", ");
cppWriter.append(");\n");
cppWriter.append("\n\n");
class Method
private static final Pattern NAME_REGEXP =
//1 //2
Pattern.compile("\\s*(.*)\\s+(\\w[\\w0-9]+)\\s*", Pattern.MULTILINE);
//1 - all specifiers - including __declspec(dllexport) and such ;)
//2 - function name
public final List<Parameter> params;
public final String name;
public final String specifiers;
public Method(Matcher m)
params = Collections.unmodifiableList(Parameter.parseParamList(m.group(2)));
Matcher nameMather = NAME_REGEXP.matcher(m.group(1));
System.out.println("ALL: " + m.group());
System.out.println("G1: " + m.group(1));
if(!nameMather.matches())
throw new IllegalArgumentException("for string " + m.group(1));
// nameMather.find();
specifiers = nameMather.group(1);
name = nameMather.group(2);
class Parameter
static final Pattern PARAMETER_PATTERN =
//1 //2
Pattern.compile("\\s*(?:(.*)\\s+)?([\\w\\*&]+[\\w0-9]*[\\*&]?)\\s*");
//1 - Most probably parameter type and specifiers, but may also be empty - in which case name is empty, and specifiers are in 2
//2 - Most probably parameter type, sometimes prefixed with ** or &* ;), also
// 'char *' will be parsed as grup(1) == char, group(2) = *.
/**
* Used to check if group that represenrs parameter name is in fact param specifier like '*'.
*/
static final Pattern STAR_PATTERN =
Pattern.compile("\\s*([\\*&]?)+\\s*");
/**
* If
*/
static final Pattern NAME_PATTERN =
Pattern.compile("\\s*([\\*&]+)?(\\w[\\w0-9]*)\\s*");
public final String name;
public final String specifiers;
public Parameter(String param, int idx)
System.out.println(param);
Matcher m = PARAMETER_PATTERN.matcher(param);
String name = null;
String specifiers = null;
if(!m.matches())
throw new IllegalStateException(param);
name = m.group(2);
specifiers = m.group(1);
if(specifiers==null || specifiers.isEmpty()) //Case that parameter has no name like 'int', or 'int**'
specifiers = name;
name = null;
else if(STAR_PATTERN.matcher(name).matches()) //Case that parameter has no name like 'int *'
specifiers += name;
name = null;
else if(NAME_PATTERN.matcher(name).matches()) //Checks if name contains part of type like '**ptrData', and extracts '**'
Matcher m2 = NAME_PATTERN.matcher(name);
m2.matches();
if(m2.group(1)!=null)
specifiers += m2.group(1);
name = m2.group(2);
if(name==null)
name = "param" + idx;
this.specifiers = specifiers;
this.name = name;
public static List<Parameter> parseParamList(String paramList)
List<Parameter> result = new ArrayList<Parameter>();
String[] params = paramList.split(",");
int idx = 0;
for(String param : params)
Parameter p = new Parameter(param, idx++);
result.add(p);
if(result.size()==1)
Parameter p = result.get(0);
if(p.specifiers.matches("\\s*void\\s*"))
return Collections.emptyList();
return result;
【讨论】:
以上是关于将静态 windows 库转换为 dll的主要内容,如果未能解决你的问题,请参考以下文章